Skip to content

Instantly share code, notes, and snippets.

@slpsys
Last active July 25, 2019 01:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slpsys/59cd287834e7dbe7656ba90a4c918c73 to your computer and use it in GitHub Desktop.
Save slpsys/59cd287834e7dbe7656ba90a4c918c73 to your computer and use it in GitHub Desktop.
class Player
private_class_method :new
class << self
def one ; 1 ; end
def two ; 2 ; end
end
end
class TTTEngine
attr_accessor :board
BOTTOM_LEFT = 2 ** 0
BOTTOM_CENTER = 2 ** 1
BOTTOM_RIGHT = 2 ** 2
CENTER_LEFT = 2 ** 3
CENTER_CENTER = 2 ** 4
CENTER_RIGHT = 2 ** 5
TOP_LEFT = 2 ** 6
TOP_CENTER = 2 ** 7
TOP_RIGHT = 2 ** 8
WIN_CONDITIONS = [
[BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_RIGHT],
[CENTER_LEFT, CENTER_RIGHT, CENTER_RIGHT],
[TOP_LEFT, TOP_RIGHT, TOP_RIGHT],
[BOTTOM_LEFT, CENTER_LEFT, TOP_LEFT],
[BOTTOM_CENTER, CENTER_CENTER, TOP_CENTER],
[BOTTOM_RIGHT, CENTER_RIGHT, TOP_RIGHT],
[BOTTOM_LEFT, CENTER_CENTER, TOP_Rclass Player
private_class_method :new
class << self
def one ; 1 ; end
def two ; 2 ; end
end
end
class TTTEngine
attr_accessor :board
BOTTOM_LEFT = 2 ** 0
BOTTOM_CENTER = 2 ** 1
BOTTOM_RIGHT = 2 ** 2
CENTER_LEFT = 2 ** 3
CENTER_CENTER = 2 ** 4
CENTER_RIGHT = 2 ** 5
TOP_LEFT = 2 ** 6
TOP_CENTER = 2 ** 7
TOP_RIGHT = 2 ** 8
WIN_CONDITIONS = [
[BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_RIGHT],
[CENTER_LEFT, CENTER_RIGHT, CENTER_RIGHT],
[TOP_LEFT, TOP_RIGHT, TOP_RIGHT],
[BOTTOM_LEFT, CENTER_LEFT, TOP_LEFT],
[BOTTOM_CENTER, CENTER_CENTER, TOP_CENTER],
[BOTTOM_RIGHT, CENTER_RIGHT, TOP_RIGHT],
[BOTTOM_LEFT, CENTER_CENTER, TOP_RIGHT],
[TOP_LEFT, CENTER_CENTER, BOTTOM_RIGHT]
]
def initialize
@board = 0
end
def move(player, x, y)
b = transpose_for_read(player, @board)
coord = translate_coords(x, y)
msg = "Great move!"
status = "Success"
if game_won?
msg = "Game has already been won!"
status = "Failure"
elsif !coord
msg = "Invalid position!"
status = "Failure"
elsif !valid_move?(player, @board, coord)
msg = "Invalid move!"
status = "Failure"
else
b += coord
@board |= transpose_for_write(player, b)
if game_won?
msg = "Player #{player} has won!"
status = "Completion"
end
end
{ board_state: @board, message: msg, status: status}
end
private
def count_moves(board)
count = 0
while board > 0
count += 1 if board & 1 == 1
board >>= 1
end
count
end
def valid_move?(player, board, coord)
## Check if it's their turn
if count_moves(board).even? && player == Player.two
return false
end
## Check if anyone's taken this space
(transpose_for_read(Player.one, board) & coord == 0) &&
(transpose_for_read(Player.two, board) & coord == 0)
end
def game_won?
WIN_CONDITIONS.each do |cond|
mask = cond[0] | cond[1] | cond[2]
if (transpose_for_read(Player.one, @board) & mask) == mask
puts "Player One has won!"
return Player.one
elsif (transpose_for_read(Player.two, @board) & mask) == mask
puts "Player Two has won!"
return Player.two
end
end
false
end
def translate_coords(x, y)
bx = translate_x(x)
by = translate_y(y)
if bx && by
Object.const_get("TTTEngine::#{by}_#{bx}")
else
nil
end
end
def translate_x(coord)
case coord
when 0
:LEFT
when 1
:CENTER
when 2
:RIGHT
end
end
def translate_y(coord)
case coord
when 0
:BOTTOM
when 1
:CENTER
when 2
:TOP
end
end
def transpose_for_read(player, board)
if player == Player.one
board & (2 ** 9 - 1)
else
(board >> 9) & (2 ** 9 - 1)
end
end
def transpose_for_write(player, board)
if player == Player.two
board << 9
else
board
end
end
end
t = TTTEngine.new
puts t.move(Player.one, 0, 0)
puts t.move(Player.two, 0, 3)
puts t.move(Player.two, 0, 2)
puts t.move(Player.two, 0, 1)
puts t.move(Player.one, 1, 0)
puts t.move(Player.two, 0, 1)
puts t.move(Player.one, 2, 0)IGHT],
[TOP_LEFT, CENTER_CENTER, BOTTOM_RIGHT]
]
def initialize
@board = 0
end
def move(player, x, y)
b = transpose_in(player, @board)
coord = translate_coords(x, y)
msg = "Great move!"
status = "Success"
if game_won?
msg = "Game has already been won!"
status = "Failure"
elsif !coord
msg = "Invalid position!"
status = "Failure"
elsif !valid_move?(player, @board, coord)
msg = "Invalid move!"
status = "Failure"
else
b += coord
@board |= transpose_out(player, b)
if game_won?
msg = "Player #{player} has won!"
status = "Completion"
end
end
{ board_state: @board, message: msg, status: status}
end
private
def count_moves(board)
count = 0
while board > 0
count += 1 if board & 1 == 1
board >>= 1
end
count
end
def valid_move?(player, board, coord)
## Check if it's their turn
if count_moves(board).even? && player == Player.two
return false
end
## Check if anyone's taken this space
(transpose_in(Player.one, board) & coord == 0) &&
(transpose_in(Player.two, board) & coord == 0)
end
def game_won?
WIN_CONDITIONS.each do |cond|
mask = cond[0] | cond[1] | cond[2]
if (transpose_in(Player.one, @board) & mask) == mask
puts "Player One has won!"
return Player.one
elsif (transpose_in(Player.two, @board) & mask) == mask
puts "Player Two has won!"
return Player.two
end
end
false
end
def translate_coords(x, y)
bx = translate_x(x)
by = translate_y(y)
if bx && by
Object.const_get("TTTEngine::#{by}_#{bx}")
else
nil
end
end
def translate_x(coord)
case coord
when 0
:LEFT
when 1
:CENTER
when 2
:RIGHT
end
end
def translate_y(coord)
case coord
when 0
:BOTTOM
when 1
:CENTER
when 2
:TOP
end
end
def transpose_in(player, board)
if player == Player.one
board & (2 ** 9 - 1)
else
(board >> 9) & (2 ** 9 - 1)
end
end
def transpose_out(player, board)
if player == Player.two
board << 9
else
board
end
end
end
t = TTTEngine.new
puts t.move(Player.one, 0, 0)
puts t.move(Player.two, 0, 3)
puts t.move(Player.two, 0, 2)
puts t.move(Player.two, 0, 1)
puts t.move(Player.one, 1, 0)
puts t.move(Player.two, 0, 1)
puts t.move(Player.one, 2, 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment