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.
@@ -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)_
@@ -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
@@ -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