reversi 2.0.0 → 2.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 +4 -4
- data/README.md +10 -11
- data/ext/reversi/bit_board_functions.c +18 -0
- data/ext/reversi/board.c +7 -1
- data/lib/reversi/board.rb +5 -0
- data/lib/reversi/game.rb +2 -0
- data/lib/reversi/player/base_player.rb +3 -3
- data/lib/reversi/version.rb +1 -1
- data/lib/reversi.rb +1 -0
- data/spec/board_spec.rb +61 -32
- data/spec/player_spec.rb +1 -1
- metadata +2 -4
- data/black +0 -0
- data/white +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cb57c511c13a037077ba6d8f0ab1caa8cd8cc577
|
|
4
|
+
data.tar.gz: ba9e86d039af5cf0b84131abc34b840391a870cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8750708addcd46a68728174747d20dd86190b121bcb49860e9a157aaf7c70e9403c1723f1901ff45e90fa020c0b9f42b0cf2db8f23bdccf043a41daf01cb061
|
|
7
|
+
data.tar.gz: c5173b9bead22a20bf952fc0f79c7e15b54b9572821d4bd3a331bebc5d52d33c3b01248ae06a6e77f348249daccfcf81bcfc2118ac36a7600f3e204e993f4d14
|
data/README.md
CHANGED
|
@@ -45,17 +45,16 @@ puts "white #{game.board.status[:white].size}"
|
|
|
45
45
|
|
|
46
46
|
Use `Reversi.configure` to configure setting for a reversi game.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* `stack_limit` The upper limit number of times of use repeatedly `Reversi::Board#undo!` . ( 3 )
|
|
48
|
+
| name | description | default |
|
|
49
|
+
|:----:|:----:|:----:|
|
|
50
|
+
| player_b | A player having the first move uses this class object. | `Reversi::Player::RandomAI` |
|
|
51
|
+
| player_w | A player having the passive move uses this class object. | `Reversi::Player::RandomAI` |
|
|
52
|
+
| disk_b | A string of the black disks. | 'b' |
|
|
53
|
+
| disk_w | A string of the white disks. | 'w' |
|
|
54
|
+
| disk_color_b | A color of the black disks. | 'white' |
|
|
55
|
+
| disk_color_w | A color of the white disks. | 'white' |
|
|
56
|
+
| progress | Whether or not the progress of the game is displayed. | `false` |
|
|
57
|
+
| stack_limit | The upper limit number of times of use repeatedly `Reversi::Board#undo!` | 3 |
|
|
59
58
|
|
|
60
59
|
A string and a color of the disks are reflected on `game.board.to_s` .
|
|
61
60
|
You can choose from 9 colors, black, red, green, yellow, blue, magenda, cyan, white and gray.
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#include "bit_board_functions.h"
|
|
2
2
|
|
|
3
|
+
/*
|
|
4
|
+
* Convert coordinate data to a bitboard.
|
|
5
|
+
*/
|
|
3
6
|
unsigned long XY2BB(int x, int y) {
|
|
4
7
|
return (unsigned long)1 << ((8-x) + (8-y) * 8);
|
|
5
8
|
}
|
|
6
9
|
|
|
10
|
+
/*
|
|
11
|
+
* Convert a bitboard to coordinate data.
|
|
12
|
+
*/
|
|
7
13
|
VALUE BB2XY(unsigned long bb) {
|
|
8
14
|
VALUE xy = rb_ary_new();
|
|
9
15
|
|
|
@@ -83,6 +89,9 @@ VALUE BB2XY(unsigned long bb) {
|
|
|
83
89
|
return xy;
|
|
84
90
|
}
|
|
85
91
|
|
|
92
|
+
/*
|
|
93
|
+
* Rotate a bitboard by 90 degrees to the right.
|
|
94
|
+
*/
|
|
86
95
|
unsigned long rotate_r90(unsigned long bb) {
|
|
87
96
|
bb = ((bb << 8) & 0xAA00AA00AA00AA00) |
|
|
88
97
|
((bb >> 8) & 0x0055005500550055) |
|
|
@@ -99,6 +108,9 @@ unsigned long rotate_r90(unsigned long bb) {
|
|
|
99
108
|
return bb;
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
/*
|
|
112
|
+
* Rotate a bitboard by 90 degrees to the left.
|
|
113
|
+
*/
|
|
102
114
|
unsigned long rotate_l90(unsigned long bb) {
|
|
103
115
|
bb = ((bb << 1) & 0xAA00AA00AA00AA00) |
|
|
104
116
|
((bb >> 1) & 0x0055005500550055) |
|
|
@@ -115,6 +127,9 @@ unsigned long rotate_l90(unsigned long bb) {
|
|
|
115
127
|
return bb;
|
|
116
128
|
}
|
|
117
129
|
|
|
130
|
+
/*
|
|
131
|
+
* Rotate a bitboard by 45 degrees to the right.
|
|
132
|
+
*/
|
|
118
133
|
unsigned long rotate_r45(unsigned long bb) {
|
|
119
134
|
bb = (bb & 0x0101010101010101) |
|
|
120
135
|
(((bb << 8) | (bb >> 56)) & 0x0202020202020202) |
|
|
@@ -127,6 +142,9 @@ unsigned long rotate_r45(unsigned long bb) {
|
|
|
127
142
|
return bb;
|
|
128
143
|
}
|
|
129
144
|
|
|
145
|
+
/*
|
|
146
|
+
* Rotate a bitboard by 45 degrees to the left.
|
|
147
|
+
*/
|
|
130
148
|
unsigned long rotate_l45(unsigned long bb) {
|
|
131
149
|
bb = (bb & 0x0101010101010101) |
|
|
132
150
|
(((bb >> 8) | (bb << 56)) & 0x0202020202020202) |
|
data/ext/reversi/board.c
CHANGED
|
@@ -176,6 +176,7 @@ VALUE count_disks(VALUE self, VALUE color) {
|
|
|
176
176
|
|
|
177
177
|
/*
|
|
178
178
|
* Returns an array of the next moves.
|
|
179
|
+
* This method is used in Reversi::Player::BasePlayer class.
|
|
179
180
|
*
|
|
180
181
|
* @param color [Integer]
|
|
181
182
|
* @return [Array<Array<Integer, Integer>>]
|
|
@@ -202,6 +203,9 @@ VALUE next_moves(VALUE self, VALUE color) {
|
|
|
202
203
|
|
|
203
204
|
/*
|
|
204
205
|
* Places a supplied color's disk on specified position.
|
|
206
|
+
* This method is used in Reversi::Board.initialize method
|
|
207
|
+
* for putting the disks at the initial position,
|
|
208
|
+
* but not used in Reversi::Player::BasePlayer class.
|
|
205
209
|
*
|
|
206
210
|
* @param rb_x [Integer] the column number
|
|
207
211
|
* @param rb_y [Integer] the row number
|
|
@@ -221,7 +225,9 @@ VALUE put_disk(VALUE self, VALUE rb_x, VALUE rb_y, VALUE color) {
|
|
|
221
225
|
|
|
222
226
|
/*
|
|
223
227
|
* Flips the opponent's disks between a new disk and another disk of my color.
|
|
224
|
-
*
|
|
228
|
+
* This method is used in Reversi::Player::BasePlayer class.
|
|
229
|
+
* When the invalid move is supplied, a disk is put only the position
|
|
230
|
+
* and Reversi::MoveError is raised at Reversi::Game.check_move method.
|
|
225
231
|
*
|
|
226
232
|
* @param rb_x [Integer] the column number
|
|
227
233
|
* @param rb_y [Integer] the row number
|
data/lib/reversi/board.rb
CHANGED
|
@@ -25,6 +25,7 @@ module Reversi
|
|
|
25
25
|
# @see Reversi::Game
|
|
26
26
|
# @see Reversi::Configration
|
|
27
27
|
# @return [Reversi::Board]
|
|
28
|
+
# @raise [OptionError] Error is raised when the supplied option is invalid.
|
|
28
29
|
def initialize(options = {})
|
|
29
30
|
@options = options
|
|
30
31
|
@stack = []
|
|
@@ -39,6 +40,10 @@ module Reversi
|
|
|
39
40
|
@options[:initial_position].each do |color, positions|
|
|
40
41
|
positions.each{ |position| put_disk(*position, DISK[color]) }
|
|
41
42
|
end
|
|
43
|
+
|
|
44
|
+
if @options[:disk_b].size != 1 || @options[:disk_w].size != 1
|
|
45
|
+
raise OptionError, "The length of the disk string must be one."
|
|
46
|
+
end
|
|
42
47
|
end
|
|
43
48
|
|
|
44
49
|
# Returns a string of the game board in human-readable form.
|
data/lib/reversi/game.rb
CHANGED
|
@@ -74,6 +74,8 @@ module Reversi
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
# Checks a move to make sure it is valid.
|
|
77
|
+
#
|
|
78
|
+
# @raise [MoveError] Error is raised when a player make an invalid move.
|
|
77
79
|
def check_move(color)
|
|
78
80
|
blank_diff = @status[:none].size - @board.count_disks(Reversi::Board::DISK[:none])
|
|
79
81
|
|
|
@@ -18,7 +18,7 @@ module Reversi::Player
|
|
|
18
18
|
# Places a supplied color's disk on specified position,
|
|
19
19
|
# and flips the opponent's disks.
|
|
20
20
|
#
|
|
21
|
-
# @param x [
|
|
21
|
+
# @param x [Integer] the column number
|
|
22
22
|
# @param y [Integer] the row number
|
|
23
23
|
# @param my_color [Boolean] my color or opponent's color
|
|
24
24
|
def put_disk(x, y, my_color = true)
|
|
@@ -30,7 +30,7 @@ module Reversi::Player
|
|
|
30
30
|
# Returns an array of the next moves.
|
|
31
31
|
#
|
|
32
32
|
# @param my_color [Boolean] my color or opponent's color
|
|
33
|
-
# @return [
|
|
33
|
+
# @return [Array<Array<Integer, Integer>>] the next moves
|
|
34
34
|
def next_moves(my_color = true)
|
|
35
35
|
color = my_color ? @my_color : @opponent_color
|
|
36
36
|
@board.next_moves(color)
|
|
@@ -47,7 +47,7 @@ module Reversi::Player
|
|
|
47
47
|
|
|
48
48
|
# Returns a hash containing the coordinates of each color.
|
|
49
49
|
#
|
|
50
|
-
# @return [Hash{Symbol => Array<
|
|
50
|
+
# @return [Hash{Symbol => Array<Integer, Integer>}]
|
|
51
51
|
def status
|
|
52
52
|
convert = {
|
|
53
53
|
:black => @my_color == Reversi::Board::DISK[:black] ? :mine : :opponent,
|
data/lib/reversi/version.rb
CHANGED
data/lib/reversi.rb
CHANGED
data/spec/board_spec.rb
CHANGED
|
@@ -6,8 +6,8 @@ describe Reversi::Board do
|
|
|
6
6
|
:player_w => Reversi::Player::RandomAI,
|
|
7
7
|
:disk_b => "b",
|
|
8
8
|
:disk_w => "w",
|
|
9
|
-
:disk_color_b =>
|
|
10
|
-
:disk_color_w =>
|
|
9
|
+
:disk_color_b => 0,
|
|
10
|
+
:disk_color_w => 0,
|
|
11
11
|
:initial_position => {:black => [[4, 5], [5, 4]],
|
|
12
12
|
:white => [[4, 4], [5, 5]]},
|
|
13
13
|
:progress => false,
|
|
@@ -15,31 +15,78 @@ describe Reversi::Board do
|
|
|
15
15
|
end
|
|
16
16
|
let(:board) { Reversi::Board.new(options) }
|
|
17
17
|
|
|
18
|
+
describe "the options, disk_b, disk_w" do
|
|
19
|
+
after { Reversi.reset }
|
|
20
|
+
|
|
21
|
+
context "when disk_b is invalid" do
|
|
22
|
+
it "should raise Reversi::MoveError" do
|
|
23
|
+
Reversi.configure do |config|
|
|
24
|
+
config.disk_b = "hoge"
|
|
25
|
+
config.disk_w = "w"
|
|
26
|
+
end
|
|
27
|
+
message = "The length of the disk string must be one."
|
|
28
|
+
expect{ Reversi::Game.new.start }.to raise_error(Reversi::OptionError, message)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "when both of the disks are invalid" do
|
|
33
|
+
it "should raise Reversi::MoveError" do
|
|
34
|
+
Reversi.configure do |config|
|
|
35
|
+
config.disk_b = "poyo"
|
|
36
|
+
config.disk_w = ""
|
|
37
|
+
end
|
|
38
|
+
message = "The length of the disk string must be one."
|
|
39
|
+
expect{ Reversi::Game.new.start }.to raise_error(Reversi::OptionError, message)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when both of the disks are valid" do
|
|
44
|
+
it "should not raise Reversi::MoveError" do
|
|
45
|
+
Reversi.configure do |config|
|
|
46
|
+
config.disk_b = "a"
|
|
47
|
+
config.disk_w = "b"
|
|
48
|
+
end
|
|
49
|
+
expect{ Reversi::Game.new.start }.not_to raise_error
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
18
54
|
describe "sets each disk color" do
|
|
55
|
+
after { Reversi.reset }
|
|
56
|
+
|
|
19
57
|
context "when a color name is valid" do
|
|
20
|
-
let(:disk_color_b) { "cyan" }
|
|
21
|
-
let(:disk_color_w) { :red }
|
|
22
58
|
it "sets the valid color value" do
|
|
23
|
-
|
|
24
|
-
|
|
59
|
+
Reversi.configure do |config|
|
|
60
|
+
config.disk_color_b = "cyan"
|
|
61
|
+
config.disk_color_w = :red
|
|
62
|
+
end
|
|
63
|
+
game = Reversi::Game.new
|
|
64
|
+
expect(game.board.options[:disk_color_b]).to eq 36
|
|
65
|
+
expect(game.board.options[:disk_color_w]).to eq 31
|
|
25
66
|
end
|
|
26
67
|
end
|
|
27
68
|
|
|
28
69
|
context "when a color name is invalid" do
|
|
29
|
-
let(:disk_color_b) { "hoge" }
|
|
30
|
-
let(:disk_color_w) { :hoge }
|
|
31
70
|
it "sets 0" do
|
|
32
|
-
|
|
33
|
-
|
|
71
|
+
Reversi.configure do |config|
|
|
72
|
+
config.disk_color_b = "hoge"
|
|
73
|
+
config.disk_color_w = :hoge
|
|
74
|
+
end
|
|
75
|
+
game = Reversi::Game.new
|
|
76
|
+
expect(game.board.options[:disk_color_b]).to eq 0
|
|
77
|
+
expect(game.board.options[:disk_color_w]).to eq 0
|
|
34
78
|
end
|
|
35
79
|
end
|
|
36
80
|
end
|
|
37
81
|
|
|
38
82
|
describe "#to_s" do
|
|
39
|
-
|
|
40
|
-
let(:disk_color_w) { 'white' }
|
|
83
|
+
after { Reversi.reset }
|
|
41
84
|
|
|
42
85
|
it do
|
|
86
|
+
Reversi.configure do |config|
|
|
87
|
+
config.disk_color_b = :black
|
|
88
|
+
config.disk_color_w = 'white'
|
|
89
|
+
end
|
|
43
90
|
str = <<-END.gsub(/ {6}/,"")
|
|
44
91
|
a b c d e f g h
|
|
45
92
|
+---+---+---+---+---+---+---+---+
|
|
@@ -60,14 +107,12 @@ describe Reversi::Board do
|
|
|
60
107
|
8 | | | | | | | | |
|
|
61
108
|
+---+---+---+---+---+---+---+---+
|
|
62
109
|
END
|
|
63
|
-
|
|
110
|
+
game = Reversi::Game.new
|
|
111
|
+
expect(game.board.to_s).to eq str
|
|
64
112
|
end
|
|
65
113
|
end
|
|
66
114
|
|
|
67
115
|
describe "#push_stack" do
|
|
68
|
-
let(:disk_color_b) { 0 }
|
|
69
|
-
let(:disk_color_w) { 0 }
|
|
70
|
-
|
|
71
116
|
it "the stack size limit is 3(default)" do
|
|
72
117
|
4.times { board.push_stack }
|
|
73
118
|
expect(board.stack.size).to eq 3
|
|
@@ -82,9 +127,6 @@ describe Reversi::Board do
|
|
|
82
127
|
end
|
|
83
128
|
|
|
84
129
|
describe "#undo!" do
|
|
85
|
-
let(:disk_color_b) { 0 }
|
|
86
|
-
let(:disk_color_w) { 0 }
|
|
87
|
-
|
|
88
130
|
context "when the first argument is omitted" do
|
|
89
131
|
it "the default value is 1" do
|
|
90
132
|
3.times { board.push_stack }
|
|
@@ -94,8 +136,6 @@ describe Reversi::Board do
|
|
|
94
136
|
end
|
|
95
137
|
|
|
96
138
|
describe "#status" do
|
|
97
|
-
let(:disk_color_b) { 0 }
|
|
98
|
-
let(:disk_color_w) { 0 }
|
|
99
139
|
it "returns a hash containing the coordinates of each color" do
|
|
100
140
|
expect{ board.put_disk(1, 1, Reversi::Board::DISK[:black]) }
|
|
101
141
|
.to change{ board.status[:black].size }.by(1)
|
|
@@ -105,8 +145,6 @@ describe Reversi::Board do
|
|
|
105
145
|
end
|
|
106
146
|
|
|
107
147
|
describe "#openness" do
|
|
108
|
-
let(:disk_color_b) { 0 }
|
|
109
|
-
let(:disk_color_w) { 0 }
|
|
110
148
|
it "returns the openness of the coordinates" do
|
|
111
149
|
expect(board.openness(1, 1)).to eq 3
|
|
112
150
|
expect(board.openness(2, 2)).to eq 8
|
|
@@ -115,9 +153,6 @@ describe Reversi::Board do
|
|
|
115
153
|
end
|
|
116
154
|
|
|
117
155
|
describe "#at" do
|
|
118
|
-
let(:disk_color_b) { 0 }
|
|
119
|
-
let(:disk_color_w) { 0 }
|
|
120
|
-
|
|
121
156
|
it do
|
|
122
157
|
board.put_disk(3, 3, Reversi::Board::DISK[:white])
|
|
123
158
|
expect(board.at(3, 3)).to eq :white
|
|
@@ -127,16 +162,12 @@ describe Reversi::Board do
|
|
|
127
162
|
end
|
|
128
163
|
|
|
129
164
|
describe "#count_disks" do
|
|
130
|
-
let(:disk_color_b) { 0 }
|
|
131
|
-
let(:disk_color_w) { 0 }
|
|
132
165
|
it { expect(board.count_disks(Reversi::Board::DISK[:black])).to eq 2 }
|
|
133
166
|
it { expect(board.count_disks(Reversi::Board::DISK[:white])).to eq 2 }
|
|
134
167
|
it { expect(board.count_disks(Reversi::Board::DISK[:none])).to eq 60 }
|
|
135
168
|
end
|
|
136
169
|
|
|
137
170
|
describe "#next_moves" do
|
|
138
|
-
let(:disk_color_b) { 0 }
|
|
139
|
-
let(:disk_color_w) { 0 }
|
|
140
171
|
it { expect(board.next_moves(Reversi::Board::DISK[:black]))
|
|
141
172
|
.to eq [[5, 6], [6, 5], [3, 4], [4, 3]] }
|
|
142
173
|
it { expect(board.next_moves(Reversi::Board::DISK[:white]))
|
|
@@ -144,8 +175,6 @@ describe Reversi::Board do
|
|
|
144
175
|
end
|
|
145
176
|
|
|
146
177
|
describe "#put_disk, #flip_disks" do
|
|
147
|
-
let(:disk_color_b) { 0 }
|
|
148
|
-
let(:disk_color_w) { 0 }
|
|
149
178
|
it "flips the opponent's disks between a new disk and another disk of my color" do
|
|
150
179
|
board.put_disk(4, 6, Reversi::Board::DISK[:white])
|
|
151
180
|
board.put_disk(5, 3, Reversi::Board::DISK[:white])
|
data/spec/player_spec.rb
CHANGED
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: 2.0.
|
|
4
|
+
version: 2.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-05-
|
|
11
|
+
date: 2015-05-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -41,7 +41,6 @@ files:
|
|
|
41
41
|
- LICENSE.txt
|
|
42
42
|
- README.md
|
|
43
43
|
- Rakefile
|
|
44
|
-
- black
|
|
45
44
|
- ext/reversi/bit_board_functions.c
|
|
46
45
|
- ext/reversi/bit_board_functions.h
|
|
47
46
|
- ext/reversi/board.c
|
|
@@ -68,7 +67,6 @@ files:
|
|
|
68
67
|
- spec/game_spec.rb
|
|
69
68
|
- spec/player_spec.rb
|
|
70
69
|
- spec/spec_helper.rb
|
|
71
|
-
- white
|
|
72
70
|
homepage: https://github.com/seinosuke/reversi
|
|
73
71
|
licenses:
|
|
74
72
|
- MIT
|
data/black
DELETED
|
File without changes
|
data/white
DELETED
|
File without changes
|