reversi 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ff1bf1812bca5e760682bda5b45a12ccdba645f
4
- data.tar.gz: b8d577cc947632a87cc90baf852825f5c65d2a07
3
+ metadata.gz: 3c602bf3c1c6a4dc238b2a168a769f4b46a5727f
4
+ data.tar.gz: 88313f627c8fef5882dbfa5829c225ff0a1e3e0b
5
5
  SHA512:
6
- metadata.gz: 06780bd5ce1eaa0581e80f60356de0f0ddf66d41c49e5a48789e84141a2f6d231e55b4f5f415ff737ea9673eef87bf9c449eabec663ac0b5e466025c1dd265a6
7
- data.tar.gz: e7fa1a96392164b0359ad673334cddc5b9e4a8b19c0b98e44988da387c423e0a1adc18cf43410dc340e107e5dbfa6330aaa9a667a850825e7ea4702474a93844
6
+ metadata.gz: 409dcbf84198f1f7e0bff93e3314a5cf6b6126381eca11fff4d65260fcf4c4bb31931ef0082268737cfa63720aa497179074d6856fbf08f2afea13bdfd124d9e
7
+ data.tar.gz: fa549524250d3431623f06ac0bcdd7746032a388f8c546fb759913ec1ec63927147e19b119574a25603c41c1900ccec560cf5ba353ebeb903d1dd8b539a6ce46
data/.gitignore CHANGED
@@ -13,4 +13,3 @@
13
13
  *.o
14
14
  *.a
15
15
  mkmf.log
16
- .travis.yml
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+
7
+ bundler_args: --without development --jobs=2
8
+
9
+ script:
10
+ - bundle exec rake compile
11
+ - bundle exec rspec
12
+
13
+ branches:
14
+ only:
15
+ - master
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Reversi
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/reversi.svg)](http://badge.fury.io/rb/reversi)
3
+ [![Gem Version](https://badge.fury.io/rb/reversi.svg)](http://badge.fury.io/rb/reversi) [![Build Status](https://travis-ci.org/seinosuke/reversi.svg?branch=master)](https://travis-ci.org/seinosuke/reversi)
4
4
  A Ruby Gem to play reversi game. You can enjoy a game on the command line or easily make your original reversi game programs.
5
5
 
6
- ![reversi](https://github.com/seinosuke/reversi/blob/master/images/reversi.gif)
6
+ ![reversi.gif](https://github.com/seinosuke/reversi/blob/master/images/reversi.gif)
7
7
 
8
8
  ## Installation
9
9
 
@@ -55,7 +55,7 @@ Use `Reversi.configure` to configure setting for a reversi game.
55
55
  * `disk_color_w` A color of the black disks. ( 0 )
56
56
  * `initial_position` The initial positions of each disk on the board. ( {:black => [[:d, 5], [:e, 4]], :white => [[:d, 4], [:e, 5]]} )
57
57
  * `progress` Whether or not the progress of the game is displayed. ( false )
58
- * `stack_limit` The upper limit number of times of use `Reversi::Board#undo!` . ( 3 )
58
+ * `stack_limit` The upper limit number of times of use repeatedly `Reversi::Board#undo!` . ( 3 )
59
59
 
60
60
  A string and a color of the disks are reflected on `game.board.to_s` .
61
61
  You can choose from 9 colors, black, red, green, yellow, blue, magenda, cyan, white and gray.
@@ -99,8 +99,8 @@ game = Reversi::Game.new
99
99
  game.start
100
100
  ```
101
101
 
102
- * Example of Negamax Algorithm
103
- Please see `Reversi::Player::NegamaxAI` .
102
+ * Other examples of algorithm
103
+ Please see [Reversi::Player::MinMaxAI](https://github.com/seinosuke/reversi/blob/master/lib/reversi/player/min_max_ai.rb) or [Reversi::Player::NegaMaxAI](https://github.com/seinosuke/reversi/blob/master/lib/reversi/player/nega_max_ai.rb) . 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, set `stack_limit` to the number.
104
104
 
105
105
  ## Contributing
106
106
 
@@ -0,0 +1,51 @@
1
+ module Reversi::Player
2
+ class MinMaxAI < BasePlayer
3
+
4
+ def initialize(_color, _board)
5
+ super
6
+
7
+ point = [
8
+ 100, -10, 0, -1, -1, 0, -10, 100,
9
+ -10, -30, -5, -5, -5, -5, -30, -10,
10
+ 0, -5, 0, -1, -1, 0, -5, 0,
11
+ -1, -5, -1, -1, -1, -1, -5, -1,
12
+ -1, -5, -1, -1, -1, -1, -5, -1,
13
+ 0, -5, 0, -1, -1, 0, -5, 0,
14
+ -10, -30, -5, -5, -5, -5, -30, -10,
15
+ 100, -10, 0, -1, -1, 0, -10, 100
16
+ ]
17
+ @evaluation_value =
18
+ Hash[(1..8).map{ |x| (1..8).map{ |y| [[x, y], point.shift] } }.flatten(1) ]
19
+ end
20
+
21
+ def move(board)
22
+ moves = next_moves.map{ |v| v[:move] }
23
+ return if moves.empty?
24
+
25
+ next_move = moves.map do |move|
26
+ { :move => move, :point => evaluate(move, board, 1, true) }
27
+ end
28
+ .max_by{ |v| v[:point] }[:move]
29
+ put_disk(*next_move)
30
+ end
31
+
32
+ def evaluate(move, board, depth, color)
33
+ put_disk(*move, color)
34
+ moves = next_moves(!color).map{ |v| v[:move] }
35
+
36
+ if depth == 3
37
+ status[:mine].inject(0){ |sum, xy| sum + @evaluation_value[xy] }
38
+ elsif moves.empty?
39
+ -100
40
+ else
41
+ values = moves.map{ |move| evaluate(move, board, depth + 1, !color) }
42
+ case depth
43
+ when ->(n){ n.odd? } then values.min
44
+ when ->(n){ n.even? } then values.max end
45
+ end
46
+
47
+ ensure
48
+ board.undo!
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ module Reversi::Player
2
+ class NegaMaxAI < BasePlayer
3
+
4
+ def initialize(_color, _board)
5
+ super
6
+
7
+ point = [
8
+ 100, -10, 0, -1, -1, 0, -10, 100,
9
+ -10, -30, -5, -5, -5, -5, -30, -10,
10
+ 0, -5, 0, -1, -1, 0, -5, 0,
11
+ -1, -5, -1, -1, -1, -1, -5, -1,
12
+ -1, -5, -1, -1, -1, -1, -5, -1,
13
+ 0, -5, 0, -1, -1, 0, -5, 0,
14
+ -10, -30, -5, -5, -5, -5, -30, -10,
15
+ 100, -10, 0, -1, -1, 0, -10, 100
16
+ ]
17
+ @evaluation_value =
18
+ Hash[(1..8).map{ |x| (1..8).map{ |y| [[x, y], point.shift] } }.flatten(1) ]
19
+ end
20
+
21
+ def move(board)
22
+ moves = next_moves.map{ |v| v[:move] }
23
+ return if moves.empty?
24
+
25
+ next_move = moves.map do |move|
26
+ { :move => move, :point => evaluate(move, board, 1, true) }
27
+ end
28
+ .max_by{ |v| v[:point] }[:move]
29
+ put_disk(*next_move)
30
+ end
31
+
32
+ def evaluate(move, board, depth, color)
33
+ put_disk(*move, color)
34
+ moves = next_moves(!color).map{ |v| v[:move] }
35
+
36
+ if depth == 3
37
+ status[:mine].inject(0){ |sum, xy| sum + @evaluation_value[xy] }
38
+ elsif moves.empty?
39
+ -100
40
+ else
41
+ -( moves.map{ |move| evaluate(move, board, depth + 1, !color) }.max )
42
+ end
43
+
44
+ ensure
45
+ board.undo!
46
+ end
47
+ end
48
+ end
@@ -1,7 +1,8 @@
1
1
  module Reversi
2
2
  module Player
3
3
  autoload :RandomAI, "reversi/player/random_ai"
4
- autoload :NegamaxAI, "reversi/player/negamax_ai"
4
+ autoload :NegaMaxAI, "reversi/player/nega_max_ai"
5
+ autoload :MinMaxAI, "reversi/player/min_max_ai"
5
6
  autoload :Human, "reversi/player/human"
6
7
  end
7
8
  end
@@ -1,3 +1,3 @@
1
1
  module Reversi
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reversi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - seinosuke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-10 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -35,6 +35,7 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - ".gitignore"
37
37
  - ".rspec"
38
+ - ".travis.yml"
38
39
  - Gemfile
39
40
  - Guardfile
40
41
  - LICENSE.txt
@@ -51,7 +52,8 @@ files:
51
52
  - lib/reversi/player.rb
52
53
  - lib/reversi/player/base_player.rb
53
54
  - lib/reversi/player/human.rb
54
- - lib/reversi/player/negamax_ai.rb
55
+ - lib/reversi/player/min_max_ai.rb
56
+ - lib/reversi/player/nega_max_ai.rb
55
57
  - lib/reversi/player/random_ai.rb
56
58
  - lib/reversi/version.rb
57
59
  - reversi.gemspec
@@ -1,42 +0,0 @@
1
- module Reversi::Player
2
- class NegamaxAI < BasePlayer
3
-
4
- POINT = {
5
- [1, 1] => 100, [2, 1] => -10, [3, 1] => 0, [4, 1] => -1, [5, 1] => -1, [6, 1] => 0, [7, 1] => -10, [8, 1] => 100,
6
- [1, 2] => -10, [2, 2] => -30, [3, 2] => -5, [4, 2] => -5, [5, 2] => -5, [6, 2] => -5, [7, 2] => -30, [8, 2] => -10,
7
- [1, 3] => 0, [2, 3] => -5, [3, 3] => 0, [4, 3] => -1, [5, 3] => -1, [6, 3] => 0, [7, 3] => -5, [8, 3] => 0,
8
- [1, 4] => -1, [2, 4] => -5, [3, 4] => -1, [4, 4] => -1, [5, 4] => -1, [6, 4] => -1, [7, 4] => -5, [8, 4] => -1,
9
- [1, 5] => -1, [2, 5] => -5, [3, 5] => -1, [4, 5] => -1, [5, 5] => -1, [6, 5] => -1, [7, 5] => -5, [8, 5] => -1,
10
- [1, 6] => 0, [2, 6] => -5, [3, 6] => 0, [4, 6] => -1, [5, 6] => -1, [6, 6] => 0, [7, 6] => -5, [8, 6] => 0,
11
- [1, 7] => -10, [2, 7] => -30, [3, 7] => -5, [4, 7] => -5, [5, 7] => -5, [6, 7] => -5, [7, 7] => -30, [8, 7] => -10,
12
- [1, 8] => 100, [2, 8] => -10, [3, 8] => 0, [4, 8] => -1, [5, 8] => -1, [6, 8] => 0, [7, 8] => -12, [8, 8] => 100
13
- }.freeze
14
-
15
- def move(board)
16
- moves = next_moves.map{ |v| v[:move] }
17
- return if moves.empty?
18
-
19
- next_move = moves.map do |move|
20
- { :move => move, :point => evaluate(move, board, 1, true) }
21
- end
22
- .max_by{ |v| v[:point] }[:move]
23
- put_disk(*next_move)
24
- end
25
-
26
- def evaluate(move, board, depth, color)
27
- put_disk(*move, color)
28
- moves = next_moves(!color).map{ |v| v[:move] }
29
-
30
- if depth == 3
31
- status[:mine].inject(0){ |sum, xy| sum + POINT[xy] }
32
- elsif moves.empty?
33
- -100
34
- else
35
- -( moves.map{ |move| evaluate(move, board, depth + 1, !color) }.max )
36
- end
37
-
38
- ensure
39
- board.undo!
40
- end
41
- end
42
- end