Ruby, 115 chars
Oops: Somehow I miscounted by a lot. This is actually 115 characters, not 79.
def t(b)[1,2].find{|p|[448,56,7,292,146,73,273,84].any?{|k|(k^b.inject(0){|m,i|m*2+((i==p)?1:0)})&k==0}}||false end
# Usage:
b = [ 1, 2, 1,
0, 1, 2,
1, 0, 2 ]
t(b) # => 1
b = [ 1, 1, 0,
2, 2, 2,
0, 2, 1 ]
t(b) # => 2
b = [ 0, 0, 1,
2, 2, 0,
0, 1, 1 ]
t(b) # => false
And the expanded code, for educational purposes:
def tic(board)
# all the winning board positions for a player as bitmasks
wins = [ 0b111_000_000, # 448
0b000_111_000, # 56
0b000_000_111, # 7
0b100_100_100, # 292
0b010_010_010, # 146
0b001_001_001, # 73
0b100_010_001, # 273
0b001_010_100 ] # 84
[1, 2].find do |player| # find the player who's won
# for the winning player, one of the win positions will be true for :
wins.any? do |win|
# make a bitmask from the current player's moves
moves = board.inject(0) { |acc, square|
# shift it to the left and add one if this square matches the player number
(acc * 2) + ((square == player) ? 1 : 0)
}
# some logic evaluates to 0 if the moves match the win mask
(win ^ moves) & win == 0
end
end || false # return false if the find returns nil (no winner)
end
I'm sure this could be shortened, especially the big array and possibly the code for getting a bitmask of the players's moves--that ternary bugs me--but I think this is pretty good for now.