Reversi
A Ruby Gem to play reversi game. You can enjoy a game on the command line or easily make your original reversi game programs.
Installation
Add this line to your application's Gemfile:
gem 'reversi'
And then execute:
$ bundle
Or install it yourself as:
$ gem install reversi
Usage
Run a demo program in this introduction.
require 'reversi'
Reversi.configure do |config|
config.disk_color_b = 'cyan'
config.disk_b = "O"
config.disk_w = "O"
config.progress = true
end
game = Reversi::Game.new
game.start
puts "black #{game.board.status[:black].size}"
puts "white #{game.board.status[:white].size}"
Configuration
Use Reversi.configure
to configure setting for a reversi game.
name | description | default |
---|---|---|
player_b | A player having the first move uses this class object. | Reversi::Player::RandomAI |
player_w | A player having the passive move uses this class object. | Reversi::Player::RandomAI |
disk_b | A string of the black disks. | 'b' |
disk_w | A string of the white disks. | 'w' |
disk_color_b | A color of the black disks. | 'white' |
disk_color_w | A color of the white disks. | 'white' |
progress | Whether or not the progress of the game is displayed. | false |
stack_limit | The upper limit number of times of use repeatedly Reversi::Board#undo! |
3 |
A string and a color of the disks are reflected on game.board.to_s
.
You can choose from 9 colors, black, red, green, yellow, blue, magenda, cyan, white and gray.
The default of initial_position
is {:black => [[4, 5], [5, 4]], :white => [[4, 4], [5, 5]]}
.
Using Reversi.reset
method, you can reset all options to the default values.
Human vs Computer
Set Reversi::Player::Human
to player_b or player_w, and run. Please input your move (for example: d3). This program is terminated when this game is over or when you input q
or exit
.
Reversi.configure do |config|
config.player_b = Reversi::Player::Human
end
game = Reversi::Game.new
game.start
Your Original Player
You can make your original player class by inheriting Reversi::Player::BasePlayer
and defining move
method.
next_moves
method returns an array of the next moves. A player places a supplied color's disk on specified position, and flips the opponent's disks by using put_disk
method. You can get the current game board state from a board
variable or status
method.
- Example of Random Player
class MyAI < Reversi::Player::BasePlayer
def move(board)
moves = next_moves
put_disk(*moves.sample) unless moves.empty?
end
end
Reversi.configure do |config|
config.player_b = MyAI
config.progress = true
end
game = Reversi::Game.new
game.start
- Example of MinMax algorithm
class MyAI < Reversi::Player::BasePlayer
def initialize(_color, _board)
super
# The evaluation value at each position.
points = [
100, -10, 0, -1, -1, 0, -10, 100,
-10, -30, -5, -5, -5, -5, -30, -10,
0, -5, 0, -1, -1, 0, -5, 0,
-1, -5, -1, -1, -1, -1, -5, -1,
-1, -5, -1, -1, -1, -1, -5, -1,
0, -5, 0, -1, -1, 0, -5, 0,
-10, -30, -5, -5, -5, -5, -30, -10,
100, -10, 0, -1, -1, 0, -10, 100
]
@evaluation_value =
Hash[(1..8).map{ |x| (1..8).map{ |y| [[x, y], points.shift] } }.flatten(1) ]
end
def move(board)
moves = next_moves
return if moves.empty?
next_move = moves.map do |move|
{ :move => move, :point => evaluate(move, board, 3, true) }
end.max_by{ |v| v[:point] }[:move]
put_disk(*next_move)
end
def evaluate(move, board, depth, color)
# Move to the child node.
put_disk(*move, color)
# Acquire the branches of this node.
moves = next_moves(!color)
# Evaluate a current game-state when a search reaches the leaf node.
if depth == 1
status[:mine].inject(0){ |sum, xy| sum + @evaluation_value[xy] }
elsif moves.empty?
-100
# Select one of the child nodes
# when the current node is not the leaf node.
# Return a minimum value if it is a my move, or
# return a maximum value if it is an opponent's move.
else
values = moves.map{ |move| evaluate(move, board, depth - 1, !color) }
case depth
when ->(n){ n.odd? } then values.min
when ->(n){ n.even? } then values.max end
end
# Return to a parent node.
ensure
board.undo!
end
end
Reversi.configure do |config|
config.player_b = MyAI
config.progress = true
end
game = Reversi::Game.new
game.start
- Other examples of algorithm
Please see Reversi::Player::NegaMaxAI or Reversi::Player::AlphaBetaAI . These are examples of the player that can read the next three moves and evaluate a game state based on the positions of the disks. If you want to read the next more than three moves, setstack_limit
to the number.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request