stack_wars 0.1.0
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.
- data/LICENSE +661 -0
- data/README.md +70 -0
- data/RULES.txt +113 -0
- data/bin/stack_wars +63 -0
- data/example/sample-moves.txt +190 -0
- data/example/sample_game.rb +31 -0
- data/lib/stack_wars.rb +10 -0
- data/lib/stack_wars/battlefield.rb +65 -0
- data/lib/stack_wars/errors.rb +7 -0
- data/lib/stack_wars/game.rb +85 -0
- data/lib/stack_wars/player.rb +20 -0
- data/lib/stack_wars/territory.rb +75 -0
- data/lib/stack_wars/text_client.rb +25 -0
- data/lib/stack_wars/text_display.rb +34 -0
- data/lib/stack_wars/version.rb +3 -0
- data/test/fixtures/active_battlefield.json +9 -0
- data/test/fixtures/empty_battlefield.json +9 -0
- data/test/fixtures/moves.json +13 -0
- data/test/integration/full_game_test.rb +32 -0
- data/test/suite.rb +2 -0
- data/test/test_helper.rb +11 -0
- data/test/units/territory_test.rb +107 -0
- data/test/units/text_client_test.rb +27 -0
- metadata +80 -0
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
Stack Wars is an abstract board game currently being developed by Gregory Brown
|
2
|
+
(@seacreature) and Jia Wu (@sindhri)
|
3
|
+
|
4
|
+
The game itself can be played on Chess or Go board as long as you have some
|
5
|
+
stackable objects available to you (coins or bingo markers work fine). However,
|
6
|
+
the goal of this project is to build a computerized version so that anyone can
|
7
|
+
play without any special equipment.
|
8
|
+
|
9
|
+
See the RULES.txt file for an explanation of how the game works, and
|
10
|
+
follow the instructions below.
|
11
|
+
|
12
|
+
## To try out the game
|
13
|
+
|
14
|
+
First install the `stack_wars` Ruby gem
|
15
|
+
|
16
|
+
$ gem install stack_wars
|
17
|
+
|
18
|
+
Next, step through a sample game to get a sense of how things work
|
19
|
+
|
20
|
+
$ stack_wars demo
|
21
|
+
|
22
|
+
If the demo made sense, start up your own game. Make sure to have a friend
|
23
|
+
to share the keyboard with, as there are no bots yet. Rudimentary online
|
24
|
+
games can be done via tmux or screen, but only if you already know
|
25
|
+
how to use those tools and have a shared server handy ;)
|
26
|
+
|
27
|
+
$ stack_wars
|
28
|
+
|
29
|
+
If the demo didn't make sense, you can review the rules once more:
|
30
|
+
(uses the `less` command line tool)
|
31
|
+
|
32
|
+
$ stack_wars rules
|
33
|
+
|
34
|
+
If things still don't make sense, you may want to wait until this project is
|
35
|
+
farther along before playing with it further. But I'm happy to answer whatever
|
36
|
+
questions you might have: gregory.t.brown@gmail.com
|
37
|
+
|
38
|
+
_Please note that right now this game has a very rudimentary command line
|
39
|
+
interface and has not been tested on any platforms other than Ruby 1.9.2 /
|
40
|
+
Mac OS X 10.6. If you are trying this game out now, please make sure you
|
41
|
+
feel comfortable diving into the source code if things don't work as
|
42
|
+
expected._
|
43
|
+
|
44
|
+
## To contribute to this project
|
45
|
+
|
46
|
+
There is a lot to be done on this project, and I'd be happy to accept contributions.
|
47
|
+
If you'd like to help out, here's where to start:
|
48
|
+
|
49
|
+
0) Make sure you've got a working install of Ruby 1.9.2 handy
|
50
|
+
1) Fork the project on github: https://github.com/sandal/stack_wars
|
51
|
+
2) Install Bundler if necessary (gem install bundler) [*]
|
52
|
+
3) Run bundle install [*]
|
53
|
+
4) Run ruby tests/suite.rb and verify tests are passing
|
54
|
+
5) Run ruby examples/sample_game.rb and make sure it works as expected
|
55
|
+
|
56
|
+
[*] Feel free to skip bundler instructions if you know what you're doing and
|
57
|
+
would rather not use Bundler, there are no runtime dependencies on it.
|
58
|
+
|
59
|
+
Once you have gone through those steps, please email me at
|
60
|
+
gregory.t.brown@gmail.com letting me know that you'd like to contribute to the
|
61
|
+
project. If you had any trouble with the setup process, you can let me know at
|
62
|
+
that time.
|
63
|
+
|
64
|
+
I will eventually post a roadmap publicly, but it's a bit early for that now. If
|
65
|
+
you get in touch with me, I'll work with you to figure out what you can work on
|
66
|
+
based on your interests and the needs of the project.
|
67
|
+
|
68
|
+
_NOTE: Contributors retain copyright to their work but must agree to release their
|
69
|
+
contributions under the [GNU Affero GPL version
|
70
|
+
3](http://www.gnu.org/licenses/agpl.html)_
|
data/RULES.txt
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
Stack Wars is an abstract board game played on a two dimensional grid, similar
|
2
|
+
to a Chess or Go board. The game is currently still being play tested /
|
3
|
+
balanced, but the rules below should give you enough to try it out on your own.
|
4
|
+
|
5
|
+
== Board layout + setup
|
6
|
+
|
7
|
+
The board represents a battlefield that two players must
|
8
|
+
fight for control over, with the goal of invading each other's bases. The ASCII
|
9
|
+
representation below shows a standard 9x9 grid representing the battlefield.
|
10
|
+
|
11
|
+
0 1 2 3 4 5 6 7 8
|
12
|
+
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
|
13
|
+
0 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
14
|
+
| | | | | | | | |
|
15
|
+
1 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
16
|
+
| | | | | | | | |
|
17
|
+
2 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
18
|
+
| | | | | | | | |
|
19
|
+
3 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
20
|
+
| | | | | | | | |
|
21
|
+
4 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
22
|
+
| | | | | | | | |
|
23
|
+
5 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
24
|
+
| | | | | | | | |
|
25
|
+
6 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
26
|
+
| | | | | | | | |
|
27
|
+
7 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
28
|
+
| | | | | | | | |
|
29
|
+
8 (___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)--(___)
|
30
|
+
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
31
|
+
|
32
|
+
The battlefield starts off empty (as shown above), with each player holding a
|
33
|
+
number of armies in reserve equal to three times the width of the battlefield.
|
34
|
+
For example, on a 9x9 grid, each player starts off with 27 armies, on a 13x13
|
35
|
+
each player starts off with 39 armies, and so on.
|
36
|
+
|
37
|
+
== Possible turn actions
|
38
|
+
|
39
|
+
Black starts the game, and then play alternates as each player takes one of the
|
40
|
+
following actions per turn.
|
41
|
+
|
42
|
+
- FORTIFY a CONTROLLED territory by adding a single army from reserves
|
43
|
+
- MOVE a single army from a CONTROLLED territory to an adjacent
|
44
|
+
UNCLAIMED territory
|
45
|
+
- ATTACK a single enemy territory adjacent to one of the player's
|
46
|
+
CONTROLLED territories
|
47
|
+
- INVADE the enemy base (may be a MOVE or ATTACK, details explained later)
|
48
|
+
|
49
|
+
Throughout the game, the following territories are considered to be CONTROLLED
|
50
|
+
by the active player:
|
51
|
+
|
52
|
+
1) Anything that lies on the BASELINE (i.e. boundary line between the
|
53
|
+
battlefield and the player's base). This works out to any territory
|
54
|
+
in row 0 for white, and any territory in row N for black, where N is
|
55
|
+
the last row of the board.
|
56
|
+
|
57
|
+
2) Any territory which has at least one of the active player's army fortified
|
58
|
+
within it.
|
59
|
+
|
60
|
+
Some restrictions apply to how turns play out, depending on game conditions:
|
61
|
+
|
62
|
+
* In order to FORTIFY a position, the active player must have at least one
|
63
|
+
army in reserves.
|
64
|
+
|
65
|
+
* Adjacent territories are a single edge away horizontally or vertically,
|
66
|
+
but not diagonally. E.g. adjacent territories to (2,2) are:
|
67
|
+
(2,1), (2,3), (1,2), (3,2). You cannot MOVE, ATTACK, or INVADE diagonally
|
68
|
+
at any point in time.
|
69
|
+
|
70
|
+
* Two or more armies within a single territory form a STACK. If moving from
|
71
|
+
a STACK to another position, only a single army is moved, not the
|
72
|
+
entire STACK.
|
73
|
+
|
74
|
+
* You can only carry out an ATTACK from a territory which does not contain
|
75
|
+
a STACK (i.e. a position with a single army)
|
76
|
+
|
77
|
+
* If an ATTACK on an enemy territory causes that territory to becomes
|
78
|
+
unoccupied, you must immediately move the army you attacked with
|
79
|
+
into that territory.
|
80
|
+
|
81
|
+
* Whenever an army is removed from the battlefield via an ATTACK,
|
82
|
+
it is immediately removed from play, and does not count for or against
|
83
|
+
either player's score, nor does it get returned to the either player's
|
84
|
+
reserves.
|
85
|
+
|
86
|
+
== Gaining Points
|
87
|
+
|
88
|
+
An INVASION is carried out by moving one of the active player's armies into an
|
89
|
+
adjacent territory which is part of the enemy's BASELINE. This can be done via a
|
90
|
+
MOVE or an ATTACK. As soon as the active player's army is moved onto the
|
91
|
+
baseline, it is removed from play, and the active player gets one point added to
|
92
|
+
their score.
|
93
|
+
|
94
|
+
== Ending the game
|
95
|
+
|
96
|
+
At the exact moment that one player has no armies in play as well as no armies
|
97
|
+
in reserve, the game immediately ends. If one player has more points than the
|
98
|
+
other, the player with the greater amount of points. If instead each player
|
99
|
+
has an equal number of points, the game ends in a draw.
|
100
|
+
|
101
|
+
Alteratively, both players have the option of resigning at any time. Because
|
102
|
+
this is a game in which it may be obvious who the winner is well ahead of the
|
103
|
+
standard end game conditions, it should not be considered impolite to resign
|
104
|
+
when the battle is no longer interesting.
|
105
|
+
|
106
|
+
== Questions / Suggestions?
|
107
|
+
|
108
|
+
Email gregory.t.brown@gmail.com
|
109
|
+
|
110
|
+
== Implementation
|
111
|
+
|
112
|
+
You can find the source code for this game at:
|
113
|
+
http://github.com/sandal/stack_wars
|
data/bin/stack_wars
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# NOTE: This script is just a proof of concept.
|
4
|
+
# This game will eventually have a GUI of some sort
|
5
|
+
|
6
|
+
require_relative "../lib/stack_wars"
|
7
|
+
|
8
|
+
def play_game
|
9
|
+
field = StackWars::Battlefield.new
|
10
|
+
game = StackWars::Game.new(field)
|
11
|
+
|
12
|
+
client = StackWars::TextClient.new(game)
|
13
|
+
|
14
|
+
message = catch(:game_over) do
|
15
|
+
loop do
|
16
|
+
system "clear"
|
17
|
+
puts field
|
18
|
+
|
19
|
+
puts
|
20
|
+
puts "Current Score: #{game.active_player.color}: "+
|
21
|
+
"#{game.active_player.successful_invasions}, "+
|
22
|
+
"#{game.opponent.color}: "+
|
23
|
+
"#{game.opponent.successful_invasions}"
|
24
|
+
|
25
|
+
print "#{game.active_player.color}:#{game.active_player.reserves} > "
|
26
|
+
|
27
|
+
begin
|
28
|
+
move = yield
|
29
|
+
|
30
|
+
if move[/resign/i]
|
31
|
+
throw :game_over, "#{game.active_player.color} resigned"
|
32
|
+
else
|
33
|
+
client.play(move)
|
34
|
+
end
|
35
|
+
rescue StackWars::Errors::ParseError
|
36
|
+
puts "invalid command, press enter to continue"
|
37
|
+
gets
|
38
|
+
rescue StackWars::Errors::IllegalMove
|
39
|
+
puts "that move is illegal, press enter to continue"
|
40
|
+
gets
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
puts field
|
46
|
+
puts message
|
47
|
+
end
|
48
|
+
|
49
|
+
case ARGV[0]
|
50
|
+
when "rules"
|
51
|
+
system("less #{File.dirname(__FILE__)}/../RULES.txt")
|
52
|
+
when "demo"
|
53
|
+
file = "#{File.dirname(__FILE__)}/../example/sample-moves.txt"
|
54
|
+
moves = File.foreach(file)
|
55
|
+
play_game do
|
56
|
+
move = moves.next
|
57
|
+
puts "#{move}\nhit enter to continue"
|
58
|
+
$stdin.gets
|
59
|
+
move
|
60
|
+
end
|
61
|
+
else
|
62
|
+
play_game { $stdin.gets }
|
63
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
3 8
|
2
|
+
6 0
|
3
|
+
6 8
|
4
|
+
6 0 6 1
|
5
|
+
6 8 6 7
|
6
|
+
6 1 6 2
|
7
|
+
6 7 6 6
|
8
|
+
6 2 6 3
|
9
|
+
6 6 6 5
|
10
|
+
6 3
|
11
|
+
6 5
|
12
|
+
6 3 6 4
|
13
|
+
6 5 5 5
|
14
|
+
6 4 7 4
|
15
|
+
6 5 6 6
|
16
|
+
7 4 7 5
|
17
|
+
5 5
|
18
|
+
7 5
|
19
|
+
5 5 5 6
|
20
|
+
7 5 7 6
|
21
|
+
7 8
|
22
|
+
6 3 7 3
|
23
|
+
8 8
|
24
|
+
7 3 7 4
|
25
|
+
8 8
|
26
|
+
7 4 8 4
|
27
|
+
8 8 8 7
|
28
|
+
8 4 8 5
|
29
|
+
5 5 5 4
|
30
|
+
8 5
|
31
|
+
7 8 7 7
|
32
|
+
8 5 8 6
|
33
|
+
7 7 7 6
|
34
|
+
8 6 7 6
|
35
|
+
5 4 5 3
|
36
|
+
8 5
|
37
|
+
5 3 5 2
|
38
|
+
8 5 8 6
|
39
|
+
5 2
|
40
|
+
7 6 6 6
|
41
|
+
5 2 5 1
|
42
|
+
6 6 5 6
|
43
|
+
4 8
|
44
|
+
7 5
|
45
|
+
5 8
|
46
|
+
7 5 7 6
|
47
|
+
5 2
|
48
|
+
7 6
|
49
|
+
8 7 7 7
|
50
|
+
7 6 6 6
|
51
|
+
7 8
|
52
|
+
6 6
|
53
|
+
6 8
|
54
|
+
5 6
|
55
|
+
5 8 5 7
|
56
|
+
5 6 4 6
|
57
|
+
5 8
|
58
|
+
4 6
|
59
|
+
5 1 5 0
|
60
|
+
4 6 3 6
|
61
|
+
5 2 5 1
|
62
|
+
3 6
|
63
|
+
5 2
|
64
|
+
3 6 3 7
|
65
|
+
5 1 5 0
|
66
|
+
3 7 3 8
|
67
|
+
3 8
|
68
|
+
3 6
|
69
|
+
5 8 5 7
|
70
|
+
3 6 3 7
|
71
|
+
5 7 5 8
|
72
|
+
3 7 3 8
|
73
|
+
3 8
|
74
|
+
5 0
|
75
|
+
6 8 6 7
|
76
|
+
7 6 7 7
|
77
|
+
7 8 7 7
|
78
|
+
5 6 5 7
|
79
|
+
5 8 5 7
|
80
|
+
6 6 5 6
|
81
|
+
5 7 5 6
|
82
|
+
6 6 5 6
|
83
|
+
5 2 4 2
|
84
|
+
4 6
|
85
|
+
4 8 4 7
|
86
|
+
4 6 3 6
|
87
|
+
4 7 4 6
|
88
|
+
5 6 4 6
|
89
|
+
3 8 3 7
|
90
|
+
3 6 2 6
|
91
|
+
4 2 4 1
|
92
|
+
3 6 3 7
|
93
|
+
3 8
|
94
|
+
2 6 2 7
|
95
|
+
3 8 3 7
|
96
|
+
2 7 3 7
|
97
|
+
4 8
|
98
|
+
4 6
|
99
|
+
6 7 5 7
|
100
|
+
4 6 5 6
|
101
|
+
5 8
|
102
|
+
3 7
|
103
|
+
3 8
|
104
|
+
3 7 3 6
|
105
|
+
5 2
|
106
|
+
8 6
|
107
|
+
5 2 4 2
|
108
|
+
8 6 7 6
|
109
|
+
7 8
|
110
|
+
3 6
|
111
|
+
3 8 3 7
|
112
|
+
3 6 2 6
|
113
|
+
3 7 3 6
|
114
|
+
2 6 3 6
|
115
|
+
3 8
|
116
|
+
7 5
|
117
|
+
4 2
|
118
|
+
7 5 6 5
|
119
|
+
4 1 4 0
|
120
|
+
4 0
|
121
|
+
4 2 4 1
|
122
|
+
4 0 4 1
|
123
|
+
4 2 4 1
|
124
|
+
6 5 6 6
|
125
|
+
6 8
|
126
|
+
6 6
|
127
|
+
6 8 6 7
|
128
|
+
6 6 6 5
|
129
|
+
5 2 5 1
|
130
|
+
5 0 5 1
|
131
|
+
4 1 5 1
|
132
|
+
3 6
|
133
|
+
4 8 4 7
|
134
|
+
4 6 4 7
|
135
|
+
5 7 4 7
|
136
|
+
3 6 2 6
|
137
|
+
2 8
|
138
|
+
2 6
|
139
|
+
2 8 2 7
|
140
|
+
2 6 1 6
|
141
|
+
2 7 2 6
|
142
|
+
1 6 2 6
|
143
|
+
3 8 3 7
|
144
|
+
3 6 2 6
|
145
|
+
3 7 2 7
|
146
|
+
2 6 1 6
|
147
|
+
2 7 2 6
|
148
|
+
1 6 2 6
|
149
|
+
4 7 3 7
|
150
|
+
2 6
|
151
|
+
3 7 2 7
|
152
|
+
2 6 1 6
|
153
|
+
2 7 2 6
|
154
|
+
1 6 2 6
|
155
|
+
5 8 5 7
|
156
|
+
2 6 2 7
|
157
|
+
5 7 4 7
|
158
|
+
2 7
|
159
|
+
4 7 3 7
|
160
|
+
2 7 1 7
|
161
|
+
3 7 2 7
|
162
|
+
1 7 2 7
|
163
|
+
7 8 6 8
|
164
|
+
2 7
|
165
|
+
6 8 5 8
|
166
|
+
2 7
|
167
|
+
5 8 4 8
|
168
|
+
2 7 2 8
|
169
|
+
4 8 3 8
|
170
|
+
2 7 2 8
|
171
|
+
5 1 5 0
|
172
|
+
7 6 7 7
|
173
|
+
6 7 7 7
|
174
|
+
2 7 2 8
|
175
|
+
3 8 3 7
|
176
|
+
5 6 5 7
|
177
|
+
3 7 3 6
|
178
|
+
5 7 5 8
|
179
|
+
3 6 4 6
|
180
|
+
7 5 7 6
|
181
|
+
7 7 7 8
|
182
|
+
6 6 6 7
|
183
|
+
4 6 5 6
|
184
|
+
6 5 6 6
|
185
|
+
5 6 6 6
|
186
|
+
7 6 6 6
|
187
|
+
7 8 7 7
|
188
|
+
6 7 7 7
|
189
|
+
8 8 8 7
|
190
|
+
8 6 8 7
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative "../lib/stack_wars"
|
2
|
+
|
3
|
+
field = StackWars::Battlefield.new
|
4
|
+
game = StackWars::Game.new(field)
|
5
|
+
moves = File.foreach("#{File.dirname(__FILE__)}/sample-moves.txt")
|
6
|
+
|
7
|
+
client = StackWars::TextClient.new(game)
|
8
|
+
|
9
|
+
message = catch(:game_over) do
|
10
|
+
loop do
|
11
|
+
system "clear"
|
12
|
+
puts field
|
13
|
+
|
14
|
+
puts
|
15
|
+
puts "Current Score: #{game.active_player.color}: "+
|
16
|
+
"#{game.active_player.successful_invasions}, "+
|
17
|
+
"#{game.opponent.color}: "+
|
18
|
+
"#{game.opponent.successful_invasions}"
|
19
|
+
|
20
|
+
command = moves.next
|
21
|
+
print "#{game.active_player.color}:#{game.active_player.reserves} > #{command}"
|
22
|
+
client.play(command)
|
23
|
+
|
24
|
+
|
25
|
+
puts "hit enter to continue"
|
26
|
+
gets
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
puts field
|
31
|
+
puts message
|