ruby-go 0.4.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +30 -16
- data/bin/rubygo +56 -0
- data/lib/ruby-go/board.rb +8 -31
- data/lib/ruby-go/game.rb +16 -13
- data/lib/ruby-go/liberty.rb +2 -2
- data/lib/ruby-go/printers/html.rb +76 -0
- data/lib/ruby-go/printers/text.rb +40 -0
- data/lib/ruby-go/stone.rb +3 -7
- data/lib/ruby-go/version.rb +1 -1
- data/test/go_test.rb +72 -81
- data/test/sgf_test.rb +18 -18
- data/test/test_helper.rb +2 -1
- metadata +7 -6
- data/bin/ruby-go.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '024418870e37d715d73c1ce299b3db4c59b231d8fea65b64870e280b9f439387'
|
4
|
+
data.tar.gz: 460d7dbde08c15c6aec3e067dcd50c11d1b2dfac31cd708a97826a3b7b585ad1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2871316ce937e2df59f6ec8b912b51bb20cc1b37c3d257e3ddb6be0067f559d7a18feb6d8e292955257d910cfacb36aab945794912f61438d036c0d561269b3
|
7
|
+
data.tar.gz: bba3a81eac11819591ff71683b413a9679d06e15fc3334b3e874e415ec25886a600272e783f98495a578722ad8fc4c4514089e954cd2bdf73d6046c8e3836555
|
data/README.md
CHANGED
@@ -1,16 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
# Ruby Go
|
2
|
+
|
3
|
+
A gem that implements the rules of go (igo, weiqi, baduk).
|
4
|
+
|
5
|
+
## Use
|
6
|
+
|
7
|
+
```
|
8
|
+
game = RubyGo::Game(board: 19)
|
9
|
+
game.place_black(3,3)
|
10
|
+
game.place_white(15,15)
|
11
|
+
|
12
|
+
# ...
|
13
|
+
|
14
|
+
game.pass_black
|
15
|
+
game.pass_white
|
16
|
+
```
|
17
|
+
|
18
|
+
### Printers
|
19
|
+
|
20
|
+
There are a few printers included in the gem, including `TextPrinter` and `HTMLPrinter`.
|
21
|
+
|
22
|
+
The printer takes an `IO` like object, and can print the game.
|
23
|
+
```
|
24
|
+
printer = RubyGo::TextPrinter.new($stdout)
|
25
|
+
printer.print_game(game)
|
26
|
+
```
|
27
|
+
|
28
|
+
### rubygo Command Line Interface
|
29
|
+
|
30
|
+
The rubygo executable included in the gem is CLI that plays the game of go.
|
data/bin/rubygo
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ruby-go'
|
4
|
+
require 'ruby-go/printers/text'
|
5
|
+
|
6
|
+
game = RubyGo::Game.new
|
7
|
+
printer = RubyGo::TextPrinter.new($stdout)
|
8
|
+
|
9
|
+
Signal.trap("INTERUPT") do
|
10
|
+
puts "\nGoodbye"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def prompt_for_turn(game)
|
15
|
+
loop do
|
16
|
+
print 'Enter "Pass" or enter coordinates x, y for move (e.g. "4, 4"): '
|
17
|
+
ans = gets.chomp.downcase.gsub(/\s/, '')
|
18
|
+
|
19
|
+
return if ans =~ /pass/
|
20
|
+
|
21
|
+
return ans.split(',').collect {|c| Integer(c)} if ans =~/\d+,\d+/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_terminal(printer, game)
|
26
|
+
system "clear"
|
27
|
+
printer.print_game(game)
|
28
|
+
end
|
29
|
+
|
30
|
+
update_terminal(printer, game)
|
31
|
+
|
32
|
+
turn = 0
|
33
|
+
until game.passes >= 2
|
34
|
+
begin
|
35
|
+
if turn % 2 == 0
|
36
|
+
#black's turn
|
37
|
+
puts "Black's turn"
|
38
|
+
move = prompt_for_turn(game)
|
39
|
+
move ? game.place_black(*move) : game.black_pass
|
40
|
+
else
|
41
|
+
#white's turn
|
42
|
+
puts "White's turn"
|
43
|
+
move = prompt_for_turn(game)
|
44
|
+
move ? game.place_white(*move) : game.white_pass
|
45
|
+
end
|
46
|
+
|
47
|
+
update_terminal(printer, game)
|
48
|
+
|
49
|
+
turn += 1
|
50
|
+
rescue RubyGo::Game::IllegalMove => e
|
51
|
+
puts e.message
|
52
|
+
next
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
puts "Game over"
|
data/lib/ruby-go/board.rb
CHANGED
@@ -1,31 +1,27 @@
|
|
1
1
|
module RubyGo
|
2
2
|
class Board
|
3
|
-
|
4
|
-
|
5
|
-
attr_accessor :internal_board, :size
|
3
|
+
attr_reader :rows, :size
|
6
4
|
|
7
5
|
def initialize(size)
|
8
|
-
@
|
6
|
+
@rows = Array.new(size) { Array.new(size) { Liberty.new } }
|
9
7
|
@size = size
|
10
8
|
end
|
11
9
|
|
12
|
-
private :internal_board
|
13
|
-
|
14
10
|
def empty?
|
15
|
-
|
11
|
+
rows.flatten.all?(&:empty?)
|
16
12
|
end
|
17
13
|
|
18
14
|
def at(x, y)
|
19
|
-
|
15
|
+
rows[y][x]
|
20
16
|
end
|
21
17
|
|
22
18
|
def around(x, y)
|
23
19
|
intersections = []
|
24
20
|
|
25
21
|
intersections << at(x-1, y) unless x == 0
|
26
|
-
intersections << at(x+1, y) unless x == (
|
22
|
+
intersections << at(x+1, y) unless x == (size - 1)
|
27
23
|
intersections << at(x, y-1) unless y == 0
|
28
|
-
intersections << at(x, y+1) unless y == (
|
24
|
+
intersections << at(x, y+1) unless y == (size - 1)
|
29
25
|
intersections
|
30
26
|
end
|
31
27
|
|
@@ -34,14 +30,13 @@ module RubyGo
|
|
34
30
|
|
35
31
|
x, y = stone.to_coord
|
36
32
|
|
37
|
-
|
33
|
+
rows[y][x] = Liberty.new
|
38
34
|
end
|
39
35
|
|
40
|
-
# Board shouldn't care about game rules
|
41
36
|
def place(stone)
|
42
37
|
x, y = stone.to_coord
|
43
38
|
|
44
|
-
|
39
|
+
rows[y][x] = stone
|
45
40
|
end
|
46
41
|
|
47
42
|
def liberties(stone)
|
@@ -67,23 +62,5 @@ module RubyGo
|
|
67
62
|
|
68
63
|
stones
|
69
64
|
end
|
70
|
-
|
71
|
-
def to_s
|
72
|
-
out = ""
|
73
|
-
|
74
|
-
if size < 11
|
75
|
-
out << "\s\s\s#{(0..size - 1).to_a.join(' ')}\n"
|
76
|
-
else
|
77
|
-
out << "\s\s\s#{(0..10).to_a.join(' ')}"
|
78
|
-
out << "#{(11..size - 1).to_a.join('')}\n"
|
79
|
-
end
|
80
|
-
|
81
|
-
internal_board.each_with_index do |row, i|
|
82
|
-
i = "\s#{i}" if i < 10
|
83
|
-
out << "#{i}\s#{(row.collect {|stn| stn.to_s}).join(' ')}\n"
|
84
|
-
end
|
85
|
-
|
86
|
-
out
|
87
|
-
end
|
88
65
|
end
|
89
66
|
end
|
data/lib/ruby-go/game.rb
CHANGED
@@ -24,19 +24,11 @@ module RubyGo
|
|
24
24
|
sgf << ')'
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
puts board
|
29
|
-
puts " " + "_"*(board.size * 2)
|
30
|
-
print " Prisoners || White: #{captures[:black]} |"
|
31
|
-
puts " Black: #{captures[:white]}"
|
32
|
-
puts " " + "-"*(board.size * 2)
|
33
|
-
end
|
34
|
-
|
35
|
-
def black(x, y)
|
27
|
+
def place_black(x, y)
|
36
28
|
play(Stone.new(x, y, :black))
|
37
29
|
end
|
38
30
|
|
39
|
-
def
|
31
|
+
def place_white(x, y)
|
40
32
|
play(Stone.new(x, y, :white))
|
41
33
|
end
|
42
34
|
|
@@ -83,10 +75,21 @@ module RubyGo
|
|
83
75
|
end
|
84
76
|
|
85
77
|
def check_illegal_placement!(stone)
|
86
|
-
|
78
|
+
coord = stone.to_coord
|
79
|
+
|
80
|
+
if coord.any? { |i| i < 0 || i >= board.size }
|
81
|
+
raise(
|
82
|
+
Game::IllegalMove,
|
83
|
+
"You cannot place a stone off the board."
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
intersection = board.at(*coord)
|
88
|
+
|
89
|
+
unless intersection.empty?
|
87
90
|
raise(
|
88
|
-
Game::IllegalMove,
|
89
|
-
"You cannot place a stone on top of another stone."
|
91
|
+
Game::IllegalMove,
|
92
|
+
"You cannot place a stone on top of another stone."
|
90
93
|
)
|
91
94
|
end
|
92
95
|
end
|
data/lib/ruby-go/liberty.rb
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module RubyGo
|
4
|
+
class HTMLPrinter
|
5
|
+
LETTERS = ('A'..'Z').to_a.freeze
|
6
|
+
COLORS = { black: 'black stone', white: 'white stone', empty: 'liberty' }.freeze
|
7
|
+
TEMPLATE = ERB.new(<<~ERB).freeze
|
8
|
+
<style>
|
9
|
+
.board { max-width: 100%; padding: 16px; }
|
10
|
+
.row { display: flex; margin: 0; }
|
11
|
+
.intersection { display: inline-block; height: 32px; width: 32px; border-top: 2px solid black; border-left: 2px solid black; }
|
12
|
+
.intersection:last-child { border-top-width: 0px; height: 34px; }
|
13
|
+
.row:last-child .intersection { border-left-width: 0px; width: 34px; }
|
14
|
+
.row:last-child .intersection:last-child { width: 2px; height: 2px; background: black; }
|
15
|
+
.stone, .liberty { display: inline-block; width: 30px; height: 30px; border-radius: 100%; margin: 0; position: relative; top: -18px; left: -18px; }
|
16
|
+
.stone { border: 2px solid black; }
|
17
|
+
.black.stone { background: black; }
|
18
|
+
.white.stone { background: white; }
|
19
|
+
.liberty:hover { border: 2px solid red; }
|
20
|
+
.row-num, .column-num { display: inline-block; width: 34px; height: 34px; margin: 0; position: relative; }
|
21
|
+
.row-num { top: -0.5em; }
|
22
|
+
.column-num { left: -0.3em; }
|
23
|
+
</style>
|
24
|
+
<div class="game">
|
25
|
+
<div class="board">
|
26
|
+
<div class="row">
|
27
|
+
<div class="column-num row-num"></div>
|
28
|
+
<% size.times do |i| %>
|
29
|
+
<div class="column-num"><%= letters[i] %></div>
|
30
|
+
<% end %>
|
31
|
+
</div>
|
32
|
+
<% rows.each_with_index do |row, i| %>
|
33
|
+
<div class="row">
|
34
|
+
<div class="row-num"><%= letters[i] %></div>
|
35
|
+
<% row.each do |stn| %>
|
36
|
+
<div class="intersection">
|
37
|
+
<div class="<%= colors[stn.color] %>"></div>
|
38
|
+
</div>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<div class="info">
|
45
|
+
<table>
|
46
|
+
<tbody>
|
47
|
+
<tr>
|
48
|
+
<th>Prisoners</th>
|
49
|
+
<th>White</th>
|
50
|
+
<td><%= captures[:black] %></td>
|
51
|
+
<th>Black</th>
|
52
|
+
<td><%= captures[:white] %></td>
|
53
|
+
</tr>
|
54
|
+
</tbody>
|
55
|
+
</table>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
ERB
|
59
|
+
|
60
|
+
attr_reader :io
|
61
|
+
|
62
|
+
def initialize(io)
|
63
|
+
@io = io
|
64
|
+
end
|
65
|
+
|
66
|
+
def print_game(game)
|
67
|
+
html = TEMPLATE.result_with_hash(
|
68
|
+
size: game.board.size,
|
69
|
+
captures: game.captures,
|
70
|
+
rows: game.board.rows,
|
71
|
+
colors: COLORS, letters: LETTERS
|
72
|
+
)
|
73
|
+
io.write(html)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RubyGo
|
2
|
+
class TextPrinter
|
3
|
+
COLORS = { black: 'x', white: 'o', empty: '_' }.freeze
|
4
|
+
|
5
|
+
attr_reader :io
|
6
|
+
|
7
|
+
def initialize(io)
|
8
|
+
@io = io
|
9
|
+
end
|
10
|
+
|
11
|
+
def print_game(game)
|
12
|
+
print_board(game.board)
|
13
|
+
io.puts " " + "_"*(game.board.size * 2)
|
14
|
+
io.print " Prisoners || White: #{game.captures[:black]} |"
|
15
|
+
io.puts " Black: #{game.captures[:white]}"
|
16
|
+
io.puts " " + "-"*(game.board.size * 2)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def print_board(board)
|
22
|
+
if board.size < 11
|
23
|
+
io.puts " #{(0..board.size - 1).to_a.join(' ')}"
|
24
|
+
else
|
25
|
+
io.puts " #{(0..10).to_a.join(' ')}#{(11..board.size - 1).to_a.join('')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
board.rows.each_with_index do |row, i|
|
29
|
+
i = " #{i}" if i < 10
|
30
|
+
io.print "#{i} "
|
31
|
+
row.each { |stn| print_stone(stn) }
|
32
|
+
io.puts
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def print_stone(stone)
|
37
|
+
io.print "#{COLORS[stone.color]} "
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/ruby-go/stone.rb
CHANGED
@@ -6,7 +6,7 @@ module RubyGo
|
|
6
6
|
|
7
7
|
def initialize(x_coord, y_coord, color)
|
8
8
|
@x_coord = x_coord
|
9
|
-
@y_coord = y_coord
|
9
|
+
@y_coord = y_coord
|
10
10
|
@color = color
|
11
11
|
end
|
12
12
|
|
@@ -24,10 +24,6 @@ module RubyGo
|
|
24
24
|
[x_coord, y_coord]
|
25
25
|
end
|
26
26
|
|
27
|
-
def to_s
|
28
|
-
Board::COLORS[color]
|
29
|
-
end
|
30
|
-
|
31
27
|
def ==(other)
|
32
28
|
other.is_a?(Stone) &&
|
33
29
|
(color == other.color) &&
|
@@ -36,7 +32,7 @@ module RubyGo
|
|
36
32
|
end
|
37
33
|
|
38
34
|
# This can be changed to a Pass object
|
39
|
-
class NullStone < Stone
|
35
|
+
class NullStone < Stone
|
40
36
|
def initialize(color = :empty)
|
41
37
|
@x_coord = nil
|
42
38
|
@y_coord = nil
|
@@ -46,7 +42,7 @@ module RubyGo
|
|
46
42
|
def to_sgf
|
47
43
|
";#{color.to_s[0].upcase}[]"
|
48
44
|
end
|
49
|
-
|
45
|
+
|
50
46
|
def empty?
|
51
47
|
true
|
52
48
|
end
|
data/lib/ruby-go/version.rb
CHANGED
data/test/go_test.rb
CHANGED
@@ -4,10 +4,7 @@ require 'stringio'
|
|
4
4
|
module RubyGo
|
5
5
|
class GoTest < Minitest::Test
|
6
6
|
def setup
|
7
|
-
|
8
|
-
e = Board::COLORS[:empty]
|
9
|
-
|
10
|
-
@row_9_str = "_ _ _ _ _ _ _ _ _\n"
|
7
|
+
@row_9_str = " 8 _ _ _ _ _ _ _ _ _ \n"
|
11
8
|
|
12
9
|
@game = Game.new(board: 9)
|
13
10
|
end
|
@@ -16,102 +13,96 @@ module RubyGo
|
|
16
13
|
assert @game.board.empty?
|
17
14
|
end
|
18
15
|
|
19
|
-
def
|
20
|
-
assert_includes @game.board.to_s, @row_9_str
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_game_can_print_the_board
|
16
|
+
def test_printer_can_print_the_game
|
24
17
|
out = StringIO.new
|
25
|
-
|
26
|
-
|
27
|
-
@game.view
|
28
|
-
$stdout = temp
|
18
|
+
printer = RubyGo::TextPrinter.new(out)
|
19
|
+
printer.print_game(@game)
|
29
20
|
out.rewind
|
30
21
|
assert_includes out.read, @row_9_str
|
31
22
|
end
|
32
23
|
|
33
24
|
def test_game_can_place_a_stone
|
34
25
|
game = Game.new(board: 9)
|
35
|
-
game.
|
26
|
+
game.place_black(2,2)
|
36
27
|
assert_equal :black, game.board.at(2,2).color
|
37
28
|
end
|
38
29
|
|
39
30
|
def test_cannot_place_a_stone_on_top_of_another_stone
|
40
31
|
game = Game.new(board: 9)
|
41
|
-
game.
|
32
|
+
game.place_black(2,2)
|
42
33
|
assert_raises(Game::IllegalMove) do
|
43
|
-
game.
|
34
|
+
game.place_white(2,2)
|
44
35
|
end
|
45
36
|
end
|
46
37
|
|
47
38
|
def test_can_capture_one_stone
|
48
39
|
game = Game.new(board: 9)
|
49
|
-
game.
|
50
|
-
game.
|
51
|
-
game.
|
52
|
-
game.
|
53
|
-
game.
|
40
|
+
game.place_black(2,2)
|
41
|
+
game.place_white(2,1)
|
42
|
+
game.place_white(2,3)
|
43
|
+
game.place_white(1,2)
|
44
|
+
game.place_white(3,2)
|
54
45
|
assert_equal 1, game.captures[:black]
|
55
46
|
end
|
56
47
|
|
57
48
|
def test_capture_removes_stone
|
58
49
|
game = Game.new(board: 9)
|
59
|
-
game.
|
60
|
-
game.
|
61
|
-
game.
|
62
|
-
game.
|
63
|
-
game.
|
50
|
+
game.place_black(2,2)
|
51
|
+
game.place_white(2,1)
|
52
|
+
game.place_white(2,3)
|
53
|
+
game.place_white(1,2)
|
54
|
+
game.place_white(3,2)
|
64
55
|
assert game.board.at(2,2).empty?
|
65
56
|
end
|
66
57
|
|
67
58
|
def test_capture_three_stones
|
68
59
|
game = Game.new(board: 9)
|
69
|
-
game.
|
70
|
-
game.
|
71
|
-
game.
|
72
|
-
game.
|
73
|
-
game.
|
74
|
-
game.
|
75
|
-
game.
|
76
|
-
game.
|
77
|
-
game.
|
78
|
-
game.
|
79
|
-
game.
|
60
|
+
game.place_black(2,1)
|
61
|
+
game.place_black(2,2)
|
62
|
+
game.place_black(2,3)
|
63
|
+
game.place_white(2,0)
|
64
|
+
game.place_white(2,4)
|
65
|
+
game.place_white(1,1)
|
66
|
+
game.place_white(1,2)
|
67
|
+
game.place_white(1,3)
|
68
|
+
game.place_white(3,1)
|
69
|
+
game.place_white(3,2)
|
70
|
+
game.place_white(3,3)
|
80
71
|
assert_equal 3, game.captures[:black]
|
81
72
|
end
|
82
73
|
|
83
74
|
def test_snap_back
|
84
75
|
game = Game.new(board: 9)
|
85
|
-
game.
|
86
|
-
game.
|
87
|
-
game.
|
88
|
-
game.
|
89
|
-
game.
|
90
|
-
game.
|
91
|
-
game.
|
92
|
-
game.
|
93
|
-
game.
|
94
|
-
game.
|
95
|
-
game.
|
96
|
-
game.
|
76
|
+
game.place_black(3,2)
|
77
|
+
game.place_black(2,3)
|
78
|
+
game.place_black(4,3)
|
79
|
+
game.place_black(2,4)
|
80
|
+
game.place_black(5,4)
|
81
|
+
game.place_black(3,5)
|
82
|
+
game.place_black(4,5)
|
83
|
+
game.place_white(4,2)
|
84
|
+
game.place_white(5,3)
|
85
|
+
game.place_white(3,4)
|
86
|
+
game.place_white(4,4)
|
87
|
+
game.place_white(3,3)
|
97
88
|
assert_equal 1, game.captures[:black]
|
98
89
|
assert_equal 0, game.captures[:white]
|
99
|
-
game.
|
90
|
+
game.place_black(4,3)
|
100
91
|
assert_equal 1, game.captures[:black]
|
101
92
|
assert_equal 3, game.captures[:white]
|
102
93
|
end
|
103
94
|
|
104
95
|
def test_can_undo
|
105
96
|
game = Game.new()
|
106
|
-
game.
|
107
|
-
game.
|
97
|
+
game.place_black(2,2)
|
98
|
+
game.place_white(2,3)
|
108
99
|
game.undo
|
109
100
|
assert game.board.at(2,3).empty?
|
110
101
|
end
|
111
102
|
|
112
103
|
def test_can_undo_pass
|
113
104
|
game = Game.new
|
114
|
-
game.
|
105
|
+
game.place_black(2,2)
|
115
106
|
game.white_pass
|
116
107
|
game.undo
|
117
108
|
assert_equal 0, game.passes
|
@@ -119,9 +110,9 @@ module RubyGo
|
|
119
110
|
|
120
111
|
def test_can_undo_until_beginning
|
121
112
|
game = Game.new()
|
122
|
-
game.
|
123
|
-
game.
|
124
|
-
game.
|
113
|
+
game.place_black(2,2)
|
114
|
+
game.place_white(3,2)
|
115
|
+
game.place_black(3,3)
|
125
116
|
3.times {game.undo}
|
126
117
|
assert game.board.at(2,2).empty?
|
127
118
|
end
|
@@ -135,57 +126,57 @@ module RubyGo
|
|
135
126
|
|
136
127
|
def test_cannot_play_a_suicide
|
137
128
|
game = Game.new
|
138
|
-
game.
|
139
|
-
game.
|
140
|
-
game.
|
141
|
-
game.
|
142
|
-
game.
|
129
|
+
game.place_black(3,3)
|
130
|
+
game.place_white(2,3)
|
131
|
+
game.place_white(4,3)
|
132
|
+
game.place_white(3,4)
|
133
|
+
game.place_white(3,2)
|
143
134
|
assert_raises(Game::IllegalMove) do
|
144
|
-
game.
|
135
|
+
game.place_black(3,3)
|
145
136
|
end
|
146
137
|
end
|
147
138
|
|
148
139
|
def test_cannot_play_a_ko
|
149
140
|
game = Game.new
|
150
|
-
game.
|
151
|
-
game.
|
152
|
-
game.
|
153
|
-
game.
|
154
|
-
game.
|
155
|
-
game.
|
156
|
-
game.
|
157
|
-
game.
|
158
|
-
game.
|
141
|
+
game.place_black(3,3)
|
142
|
+
game.place_white(2,3)
|
143
|
+
game.place_white(4,3)
|
144
|
+
game.place_white(3,4)
|
145
|
+
game.place_white(3,2)
|
146
|
+
game.place_black(4,2)
|
147
|
+
game.place_black(4,4)
|
148
|
+
game.place_black(5,3)
|
149
|
+
game.place_black(3,3)
|
159
150
|
assert_raises(Game::IllegalMove) do
|
160
|
-
game.
|
151
|
+
game.place_white(4,3)
|
161
152
|
end
|
162
153
|
end
|
163
154
|
|
164
155
|
def big_capture_area_game
|
165
156
|
game = Game.new
|
166
|
-
game.
|
167
|
-
game.
|
168
|
-
game.
|
169
|
-
game.
|
170
|
-
game.
|
171
|
-
game.
|
157
|
+
game.place_black(0,0)
|
158
|
+
game.place_white(1,1)
|
159
|
+
game.place_black(0,1)
|
160
|
+
game.place_white(0,2)
|
161
|
+
game.place_black(1,0)
|
162
|
+
game.place_white(2,0)
|
172
163
|
game
|
173
164
|
end
|
174
165
|
|
175
166
|
def test_can_play_in_previous_capture_area_that_is_not_a_ko
|
176
167
|
game = big_capture_area_game
|
177
168
|
assert game.board.at(0,0).empty?
|
178
|
-
game.
|
169
|
+
game.place_black(0,0)
|
179
170
|
assert_equal :black, game.board.at(0,0).color
|
180
171
|
|
181
172
|
game = big_capture_area_game
|
182
173
|
assert game.board.at(0,1).empty?
|
183
|
-
game.
|
174
|
+
game.place_black(0,1)
|
184
175
|
assert_equal :black, game.board.at(0,1).color
|
185
176
|
|
186
177
|
game = big_capture_area_game
|
187
178
|
assert game.board.at(1,0).empty?
|
188
|
-
game.
|
179
|
+
game.place_black(1,0)
|
189
180
|
assert_equal :black, game.board.at(1,0).color
|
190
181
|
end
|
191
182
|
end
|
data/test/sgf_test.rb
CHANGED
@@ -11,26 +11,26 @@ module RubyGo
|
|
11
11
|
|
12
12
|
def test_game_converts_to_sgf_with_moves
|
13
13
|
game = Game.new
|
14
|
-
game.
|
15
|
-
game.
|
16
|
-
game.
|
17
|
-
game.
|
14
|
+
game.place_black(15,3)
|
15
|
+
game.place_white(3,3)
|
16
|
+
game.place_black(3,15)
|
17
|
+
game.place_white(15,15)
|
18
18
|
assert_equal "(;GM[1]FF[4]CA[UTF-8]AP[jphager2]SZ[19]PW[White]PB[Black];B[pd];W[dd];B[dp];W[pp])",
|
19
19
|
game.to_sgf
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_game_converts_correctly_with_capture
|
23
23
|
game = Game.new
|
24
|
-
game.
|
25
|
-
game.
|
26
|
-
game.
|
27
|
-
game.
|
28
|
-
game.
|
29
|
-
game.
|
30
|
-
game.
|
31
|
-
game.
|
32
|
-
game.
|
33
|
-
game.
|
24
|
+
game.place_black(15,3)
|
25
|
+
game.place_white(16,3)
|
26
|
+
game.place_black(16,2)
|
27
|
+
game.place_white(15,2)
|
28
|
+
game.place_black(14,2)
|
29
|
+
game.place_white(14,3)
|
30
|
+
game.place_black(17,3)
|
31
|
+
game.place_white(15,4)
|
32
|
+
game.place_black(16,4)
|
33
|
+
game.place_white(15,3)
|
34
34
|
|
35
35
|
assert_equal "(;GM[1]FF[4]CA[UTF-8]AP[jphager2]SZ[19]PW[White]PB[Black];B[pd];W[qd];B[qc];W[pc];B[oc];W[od];B[rd];W[pe];B[qe];W[pd])",
|
36
36
|
game.to_sgf
|
@@ -41,10 +41,10 @@ module RubyGo
|
|
41
41
|
path = File.expand_path('../../*.sgf', __FILE__)
|
42
42
|
File.delete(file) if File.exist?(file)
|
43
43
|
game = Game.new
|
44
|
-
game.
|
45
|
-
game.
|
46
|
-
game.
|
47
|
-
game.
|
44
|
+
game.place_black(15,3)
|
45
|
+
game.place_white(16,3)
|
46
|
+
game.place_black(16,2)
|
47
|
+
game.place_white(15,2)
|
48
48
|
game.save
|
49
49
|
assert_includes Dir.glob(path), file
|
50
50
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-go
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jphager2
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: SgfParser
|
@@ -27,19 +27,21 @@ dependencies:
|
|
27
27
|
description: A gem to play go and save games as sgf
|
28
28
|
email: jphager2@gmail.com
|
29
29
|
executables:
|
30
|
-
-
|
30
|
+
- rubygo
|
31
31
|
extensions: []
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
34
|
- LICENSE
|
35
35
|
- README.md
|
36
36
|
- Rakefile
|
37
|
-
- bin/
|
37
|
+
- bin/rubygo
|
38
38
|
- lib/ruby-go.rb
|
39
39
|
- lib/ruby-go/board.rb
|
40
40
|
- lib/ruby-go/game.rb
|
41
41
|
- lib/ruby-go/liberty.rb
|
42
42
|
- lib/ruby-go/moves.rb
|
43
|
+
- lib/ruby-go/printers/html.rb
|
44
|
+
- lib/ruby-go/printers/text.rb
|
43
45
|
- lib/ruby-go/stone.rb
|
44
46
|
- lib/ruby-go/version.rb
|
45
47
|
- test/go_test.rb
|
@@ -64,8 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
66
|
- !ruby/object:Gem::Version
|
65
67
|
version: '0'
|
66
68
|
requirements: []
|
67
|
-
|
68
|
-
rubygems_version: 2.6.12
|
69
|
+
rubygems_version: 3.1.2
|
69
70
|
signing_key:
|
70
71
|
specification_version: 4
|
71
72
|
summary: The game of Go, writen in Ruby
|
data/bin/ruby-go.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require_relative '../lib/ruby-go'
|
4
|
-
|
5
|
-
game = RubyGo::Game.new
|
6
|
-
|
7
|
-
def game.prompt_for_turn
|
8
|
-
print "Pass or enter coordinates x, y for move (e.g. 4, 4): "
|
9
|
-
ans = gets.chomp.downcase.gsub(/\s/, '')
|
10
|
-
|
11
|
-
if ans =~ /pass/
|
12
|
-
self.pass
|
13
|
-
nil
|
14
|
-
else
|
15
|
-
ans.split(',').collect {|c| Integer(c)}
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
system "clear"
|
20
|
-
game.view
|
21
|
-
turn = 0
|
22
|
-
until game.passes >= 2
|
23
|
-
begin
|
24
|
-
if turn % 2 == 0
|
25
|
-
#black's turn
|
26
|
-
puts "Black's turn"
|
27
|
-
ans = game.prompt_for_turn
|
28
|
-
game.black(*ans) if ans
|
29
|
-
else
|
30
|
-
#white's turn
|
31
|
-
puts "white's turn"
|
32
|
-
ans = game.prompt_for_turn
|
33
|
-
game.white(*ans) if ans
|
34
|
-
end
|
35
|
-
|
36
|
-
system "clear"
|
37
|
-
game.view
|
38
|
-
|
39
|
-
turn += 1
|
40
|
-
rescue RubyGo::Game::IllegalMove
|
41
|
-
next
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
system "clear"
|