Skip to content

Instantly share code, notes, and snippets.

@hakobe
Created October 12, 2008 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hakobe/16396 to your computer and use it in GitHub Desktop.
Save hakobe/16396 to your computer and use it in GitHub Desktop.
class Stone
@@STONE_COLORS = [:white, :black]
def initialize(heads_color)
raise "Invalid type" unless @@STONE_COLORS.include?(heads_color)
@heads = heads_color
end
attr_reader :heads # 表の色
def tails # 裏の色
@heads == :white ? :black : :white
end
def flip
@heads = self.tails
end
end
class Board
@@DEFAULT_BOARD_SIZE = 8
def initialize(board_size = @@DEFAULT_BOARD_SIZE)
@BOARD_SIZE = board_size
@box = Array.new(@BOARD_SIZE) { Array.new(@BOARD_SIZE, nil) }
end
def set(point, stone)
raise "Out of board" unless self.in_board?(point)
raise "Invalid stone" unless Stone === stone
raise "Already set" if self.get(point)
row, column = *point
@box[row][column]= stone
end
def get(point)
raise "Out of board" unless self.in_board?(point)
row, column = *point
@box[row][column]
end
alias_method :[], :get
alias_method :[]=, :set
def to_s
out = []
rule = { :white => 'w', :black => 'b' }
header = " " + (0...@BOARD_SIZE).to_a.join(' ')
out.push(header)
@box.each_with_index do |row, i|
line = i.to_s + "|"
row.each do |cell|
line += cell ? rule[cell.heads] : ' '
line += "|"
end
out.push(line)
end
return out.join("\n")
end
def in_board?(point)
point.all? { |n| (0...@BOARD_SIZE).include?(n) }
end
end
class Game
@@DEFAULT_BOARD_SIZE = 8
def initialize(board_size = @@DEFAULT_BOARD_SIZE)
@BOARD_SIZE = board_size
@board = Board.new(@BOARD_SIZE)
c = @BOARD_SIZE / 2 # center
@board[[c-1,c-1]] = Stone.new(:black)
@board[[c, c ]] = Stone.new(:black)
@board[[c-1,c ]] = Stone.new(:white)
@board[[c, c-1]] = Stone.new(:white)
@current_turn = :black
end
attr_reader :current_turn
def put(point)
raise "Invalid point" if point.any? {|e| !(Integer === e)} || point.size != 2
self.flip(point)
@board[point] = Stone.new(@current_turn)
self.change
end
def change
@current_turn = @current_turn == :white ? :black : :white
end
def flip_with_dir_from(point, row_dir, colmn_dir)
# flip可能か調べる
found = nil
row, column = *point
loop do
row += row_dir
column += colmn_dir
break unless @board.in_board?([row, column]) # ボード外
break unless @board[[row, column]] # 石が連続していない
next if @board[[row, column]].heads != @current_turn # まだ続く
found = [row, column]; break
end
return nil if !found ||
((point[0] - found[0]).abs == 1 || (point[1] - point[1]).abs == 1)
# flipする
row, column = *point
found_row, found_column = *found
loop do
row += row_dir
column += colmn_dir
break if row == found_row && column == found_column
@board[[row,column]].flip
end
return found
end
def flip(point)
# 8方向のflipを行う
results = [
[ 0,+1], # 右
[ 0,-1], # 左
[+1, 0], # 下
[-1, 0], # 上
[+1,+1], # 右下
[-1,+1], # 右上
[+1,-1], # 左下
[-1,-1], # 左上
].map { |dir| self.flip_with_dir_from(point, *dir) }
raise "Invalid flip" if results.all? {|r| r.nil?}
end
def to_s
@board.to_s
end
end
# main
game = Game.new
error = nil
loop do
begin
puts game
puts game.current_turn.to_s + "'s turn"
if error
puts "!!! " + error + " !!!"
error = nil
end
print '> '
point = gets.chomp.split.map {|e| e.to_i} rescue raise("Invalid input")
game.put(point)
rescue => e
error = e
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment