Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module YWF
- class Board
- ROW_MIN = 1
- ROW_MAX = 9
- COL_MIN = 1
- COL_MAX = 9
- WALL = -1
- EMPTY = 0
- BLACK = 1
- GRAY = 2
- WHITE = 3
- Direction = [
- [-1, -1], [-1, 0], [-1, 1],
- [ 0, -1], [ 0, 1],
- [ 1, -1], [ 1, 0], [ 1, 1],
- ]
- def initialize(other=nil)
- @board = [
- [WALL, WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, GRAY , BLACK, WHITE, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, WHITE, GRAY , BLACK, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, BLACK, WHITE, GRAY , EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WALL],
- [WALL, WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL , WALL],
- ]
- @move = 1
- @turn = BLACK
- @token = GRAY
- if other
- copy(other)
- end
- end
- attr_reader :move, :turn, :token
- def opponent
- (@turn + 2) % 4
- end
- def color(row, col)
- if (row < ROW_MIN) || (ROW_MAX < row)
- raise "invalid row. [row: #{row}]"
- end
- if (col < COL_MIN) || (COL_MAX < col)
- raise "invalid col. [col: #{col}]"
- end
- @board[row][col]
- end
- def count(color)
- if (color != EMPTY) && (color != BLACK) && (color != GRAY) && (color != WHITE)
- raise "invalid color. [color: #{color}]"
- end
- count = 0
- (ROW_MIN..ROW_MAX).each do |row|
- (COL_MIN..COL_MAX).each do |col|
- if self.color(row, col) == color
- count += 1
- end
- end
- end
- count
- end
- def playable?(row, col)
- if self.color(row, col) != EMPTY
- return false
- end
- has_color_from?(row, col)
- end
- def changeable?(row, col)
- if self.color(row, col) != GRAY
- return false
- end
- if (@token != GRAY) && (@token != @turn)
- return false
- end
- has_color_from?(row, col)
- end
- def must_pass?
- (self.playable_places.size == 0) && (self.changeable_places.size == 0)
- end
- def playable_places
- places = []
- (ROW_MIN..ROW_MAX).each do |row|
- (COL_MIN..COL_MAX).each do |col|
- if self.playable?(row, col)
- places.push [row, col]
- end
- end
- end
- places
- end
- def changeable_places
- places = []
- if @token != opponent
- (ROW_MIN..ROW_MAX).each do |row|
- (COL_MIN..COL_MAX).each do |col|
- if self.changeable?(row, col)
- places.push [row, col]
- end
- end
- end
- end
- places
- end
- def legal_actions
- actions = Array.new
- if self.must_pass?
- actions.push [:pass, nil]
- else
- self.playable_places.each do |place|
- actions.push [:play, place]
- end
- self.changeable_places.each do |place|
- actions.push [:change, place]
- end
- end
- actions
- end
- def play(row, col)
- unless self.playable?(row, col)
- raise "not playable. [row: #{row}, col: #{col}]"
- end
- new_board = self.class.new(self)
- new_board.put_piece(row, col)
- new_board.change_turn
- new_board.add_move
- new_board
- end
- def change(row, col)
- unless self.changeable?(row, col)
- raise "not changeable. [row: #{row}, col: #{col}]"
- end
- new_board = self.class.new(self)
- new_board.put_piece(row, col)
- new_board.change_token
- new_board.change_turn
- new_board.add_move
- new_board
- end
- def pass
- unless self.must_pass?
- raise "cannot pass."
- end
- new_board = self.class.new(self)
- new_board.change_turn
- new_board.add_move
- new_board
- end
- def game_end?
- if self.count(EMPTY) == 0
- return true
- end
- if self.must_pass?
- passed = self.pass
- if passed.must_pass?
- return true
- end
- end
- false
- end
- def win?(color)
- if (color != BLACK) && (color != WHITE)
- raise "invalid color. [color: #{color}]"
- end
- unless self.game_end?
- return false
- end
- if color == BLACK
- (self.count(BLACK) > self.count(WHITE)) ||
- ((self.count(BLACK) == self.count(WHITE)) && (@token == BLACK))
- else
- (self.count(BLACK) < self.count(WHITE)) ||
- ((self.count(BLACK) == self.count(WHITE)) && (@token == WHITE))
- end
- end
- protected
- def put_piece(row, col)
- @board[row][col] = @turn
- color_diff = (@turn == BLACK) ? -1 : +1
- Direction.each do |direction|
- if has_color_from_to?(row, col, direction)
- traverse_to(row, col, direction) do |step_count, traverse_row, traverse_col, traverse_color|
- if traverse_color == @turn
- break
- else
- @board[traverse_row][traverse_col] += color_diff
- end
- end
- end
- end
- end
- def change_turn
- @turn = self.opponent
- end
- def change_token
- @token += (@turn == BLACK) ? +1 : -1
- end
- def add_move
- @move += 1
- end
- private
- def copy(other)
- (ROW_MIN..ROW_MAX).each do |row|
- (COL_MIN..COL_MAX).each do |col|
- @board[row][col] = other.color(row, col)
- end
- end
- @move = other.move
- @turn = other.turn
- @token = other.token
- end
- def has_color_from?(row, col)
- Direction.each do |direction|
- if has_color_from_to?(row, col, direction)
- return true
- end
- end
- return false
- end
- def has_color_from_to?(row, col, direction)
- traverse_to(row, col, direction) do |step_count, traverse_row, traverse_col, traverse_color|
- if traverse_color == @turn
- if step_count == 1
- return false
- else
- return true
- end
- end
- end
- return false
- end
- def traverse_to(row, col, direction, &block)
- # NOTE:
- # 'traverse_to' accesses to 'WALL',
- # so 'color' cannot be used.
- traverse_row = row + direction[0]
- traverse_col = col + direction[1]
- traverse_color = @board[traverse_row][traverse_col]
- step_count = 1
- while (traverse_color != WALL) && (traverse_color != EMPTY)
- block.call(step_count, traverse_row, traverse_col, traverse_color)
- traverse_row += direction[0]
- traverse_col += direction[1]
- traverse_color = @board[traverse_row][traverse_col]
- step_count += 1
- end
- end
- end
- module BoardViewer
- COL_INDEX = " 1 2 3 4 5 6 7 8 9"
- LINE = " +---+---+---+---+---+---+---+---+---+"
- def view(board)
- puts "[#{sprintf '%03d', board.move}] turn: #{mark(board.turn)}, token: #{mark(board.token)}"
- puts COL_INDEX
- puts LINE
- (Board::ROW_MIN..Board::ROW_MAX).each do |row|
- print " #{row} "
- (Board::COL_MIN..Board::COL_MAX).each do |col|
- color = board.color(row, col)
- print "| #{mark(color)} "
- end
- puts "|"
- puts LINE
- end
- end
- def mark(color)
- case color
- when Board::EMPTY
- " "
- when Board::BLACK
- "O"
- when Board::GRAY
- "-"
- when Board::WHITE
- "X"
- else
- raise "invalid color. [color: #{color}]"
- end
- end
- module_function :view, :mark
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement