Skip to content

Instantly share code, notes, and snippets.

@davidrobles
Created April 24, 2012 01:11
Show Gist options
  • Save davidrobles/2475231 to your computer and use it in GitHub Desktop.
Save davidrobles/2475231 to your computer and use it in GitHub Desktop.
Ruby Tic-Tac-Toe
class TicTacToe
WINS = ['000000111', '000111000', '111000000',
'001001001', '010010010', '100100100',
'100010001', '001010100'].map! {|x| x.to_i(2) }
attr_writer :crosses, :noughts
def initialize
reset
end
def check_win(bitboard)
WINS.any? {|win| win & bitboard == win }
end
def reset
@crosses = 0
@noughts = 0
end
def legal_bitboard
~(@crosses | @noughts)
end
def legal_moves
legal = legal_bitboard
9.times.find_all {|move| legal & (1 << move) > 0}
end
def bit_moves
legal_moves.map {|move| (1 << move)}
end
def to_s
str = "Legal moves: {legal_moves.inspect}\n"
str += "Game over: {over?}\n\n"
9.times do |i|
if @crosses & (1 << i) > 0
str += ' X '
elsif @noughts & (1 << i) > 0
str += ' 0 '
else
str += ' - '
end
str += "\n" if i % 3 == 2
end
str + "\n"
end
def set_cur_board(board)
if cur_player == 0
@crosses = board
else
@noughts = board
end
end
def cur_board
cur_player == 0 ? @crosses : @noughts
end
# Game
def copy
tic = TicTacToe.new
tic.crosses = @crosses
tic.noughts = @noughts
tic
end
def cur_player
(bit_moves.length + 1) % 2
end
def make_move(move)
bit_ms = bit_moves
raise 'Illegal move' if move < 0 or move >= bit_ms.length
set_cur_board(cur_board | bit_ms[move])
end
def num_moves
bit_moves.length
end
def over?
check_win(@crosses) or check_win(@noughts) or bit_moves.empty?
end
def outcomes
if check_win(@crosses)
[:WIN, :LOSS]
elsif check_win(@noughts)
[:LOSS, :WIN]
else
[:NF, :NF]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment