upwords 0.1.1 → 0.2.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 +83 -30
- data/exe/upwords +1 -1
- data/lib/upwords.rb +8 -4
- data/lib/upwords/board.rb +4 -12
- data/lib/upwords/cursor.rb +4 -4
- data/lib/upwords/game.rb +70 -232
- data/lib/upwords/move.rb +45 -30
- data/lib/upwords/move_manager.rb +11 -3
- data/lib/upwords/player.rb +55 -48
- data/lib/upwords/shape.rb +11 -2
- data/lib/upwords/ui.rb +360 -0
- data/lib/upwords/version.rb +1 -1
- data/lib/upwords/word.rb +10 -9
- metadata +3 -3
- data/lib/upwords/graphics.rb +0 -149
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c9bd9e51484e62844a28edd893d75677898ca58
|
4
|
+
data.tar.gz: a6d853e3009e62f02d20b0bca25ea295d7e15e62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d9708d7e8b1910c0662defce90876449ec30f459ad1caf210e4e95dc0f89fa391c2a9e9c4fa54caf6f527d0f7b85c75ad85b2abce0bfb7e585f90033f43c48f
|
7
|
+
data.tar.gz: 696b89a6feaf45026c0a7b94046d93c6eb03063c1f01a3d7b9d2ae8b3e7e6431a374c9f49f8656d6ddd34ebf3f986c442a251b70ad2eba943100ba929e4ab4ce
|
data/README.md
CHANGED
@@ -1,4 +1,38 @@
|
|
1
|
-
#
|
1
|
+
# Upwords - The Quick Stacking Word Game
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
1. Install Upwords at the command prompt if you haven't yet:
|
6
|
+
|
7
|
+
$ gem install upwords
|
8
|
+
|
9
|
+
2. At the command prompt, start a new Upwords game:
|
10
|
+
|
11
|
+
$ upwords
|
12
|
+
|
13
|
+
3. Select the number of players:
|
14
|
+
|
15
|
+
How many players will play? (1-4)
|
16
|
+
3
|
17
|
+
|
18
|
+
4. Name each player and select if they are humans or computers:
|
19
|
+
|
20
|
+
What is Player 1's name? (Press enter to submit...)
|
21
|
+
Bob
|
22
|
+
Is Bob a computer? (y/n)
|
23
|
+
n
|
24
|
+
|
25
|
+
What is Player 2's name? (Press enter to submit...)
|
26
|
+
Nina
|
27
|
+
Is Nina a computer? (y/n)
|
28
|
+
n
|
29
|
+
|
30
|
+
What is Player 3's name? (Press enter to submit...)
|
31
|
+
Jack
|
32
|
+
Is Jack a computer? (y/n)
|
33
|
+
y
|
34
|
+
|
35
|
+
## Rules
|
2
36
|
|
3
37
|
Rules taken from: http://www.hasbro.com/common/instruct/04312.pdf
|
4
38
|
|
@@ -14,17 +48,11 @@ You score points for each letter in your word and every letter tile under
|
|
14
48
|
each letter of your word.Letters can be stacked five tiles high so your score
|
15
49
|
can really add up fast. Build words, stack letters, score high and have fun!
|
16
50
|
|
17
|
-
##
|
51
|
+
## Objective
|
18
52
|
|
19
53
|
Build words to score the most points.
|
20
54
|
|
21
|
-
##
|
22
|
-
|
23
|
-
Plastic gameboard 100 plastic letter tiles 4 plastic tile racks
|
24
|
-
|
25
|
-
4 rubber feet label sheet
|
26
|
-
|
27
|
-
## LETTER DISTRIBUTION
|
55
|
+
## Letter Distribution
|
28
56
|
|
29
57
|
| Letters | Amount |
|
30
58
|
| ------------- | --------- |
|
@@ -37,7 +65,7 @@ Plastic gameboard 100 plastic letter tiles 4 plastic tile racks
|
|
37
65
|
| A I O | 7 of each |
|
38
66
|
| E | 8 of each |
|
39
67
|
|
40
|
-
##
|
68
|
+
## Setup
|
41
69
|
|
42
70
|
- Turn all of the tiles letter-side down and mix them up to create a draw pile.
|
43
71
|
- Each player takes a rack.
|
@@ -46,7 +74,7 @@ Plastic gameboard 100 plastic letter tiles 4 plastic tile racks
|
|
46
74
|
word. See Rule 8 on page 5 for more information. Use the dictionary
|
47
75
|
to settle challenges only.
|
48
76
|
|
49
|
-
##
|
77
|
+
## Gameplay
|
50
78
|
|
51
79
|
### 1. Deciding Who Goes First
|
52
80
|
|
@@ -68,7 +96,7 @@ let your opponents see 1 your letters.
|
|
68
96
|
Whoever plays first must form a word of two letters or more that covers at least
|
69
97
|
one of the four game squares in the center of the gameboard.
|
70
98
|
|
71
|
-
### 4.
|
99
|
+
### 4. Basic Turn
|
72
100
|
|
73
101
|
On your turn, play one or more letter tiles, either to form a new word that connects to
|
74
102
|
a word already on the board, or to change a word already on the board to a different word.
|
@@ -79,7 +107,7 @@ the ones you played.
|
|
79
107
|
**IMPORTANT:** A word is legal and can be used in the game if it is in the dictionary and
|
80
108
|
it does not fall into any of the categories of illegal words listed in Rule 7 on page 5.
|
81
109
|
|
82
|
-
### 5.
|
110
|
+
### 5. How To Form Words
|
83
111
|
|
84
112
|
Figures 2 through 7 show a sequence of plays. Arrows point out the word or words
|
85
113
|
formed on each play. Point scores are given for each example. See Rule 6 on page
|
@@ -92,15 +120,40 @@ Build across using the letter "E" in DEAR to form the word NET as shown in Figur
|
|
92
120
|
The word ON is also formed reading down.You score points for all of the words
|
93
121
|
formed during your turn.
|
94
122
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
123
|
+
+----+----+----+----+----+----+
|
124
|
+
| | | | | | |
|
125
|
+
+----+----+----+----+----+----+
|
126
|
+
| | M | O | O |{D} | |
|
127
|
+
+----+---1+---1+---1+---1+----+
|
128
|
+
| | | | |{E} | |
|
129
|
+
+----+----+----+----+---1+----+
|
130
|
+
| | | | |{A} | |
|
131
|
+
+----+----+----+----+---1+----+
|
132
|
+
| | | | |{R} | |
|
133
|
+
+----+----+----+----+---1+----+
|
134
|
+
| | | | | | |
|
135
|
+
+----+----+----+----+----+----+
|
136
|
+
|
137
|
+
*Figure 2 - Score: 8 Points*
|
138
|
+
|
139
|
+
+----+----+----+----+----+----+
|
140
|
+
| | | | | | |
|
141
|
+
+----+----+----+----+----+----+
|
142
|
+
| | M | O |{O} | D | |
|
143
|
+
+----+---1+---1+---1+---1+----+
|
144
|
+
| | | |{N} |{E} |{T} |
|
145
|
+
+----+----+----+---1+---1+---1+
|
146
|
+
| | | | | A | |
|
147
|
+
+----+----+----+----+---1+----+
|
148
|
+
| | | | | R | |
|
149
|
+
+----+----+----+----+---1+----+
|
150
|
+
| | | | | | |
|
151
|
+
+----+----+----+----+----+----+
|
152
|
+
|
153
|
+
*Figure 3 - Score: 10 Points*
|
154
|
+
|
155
|
+
|
156
|
+
**NOTE:** Any letter in your word that is adjacent to another letter or letters on
|
104
157
|
the board must form a word. For example, in Figure 3, the letter "N" in NET is adjacent to
|
105
158
|
the letter "O" in MOOD, which forms the word ON.
|
106
159
|
|
@@ -147,7 +200,7 @@ makes it plural as shown in Figure 7. You score points for both words.
|
|
147
200
|
|
148
201
|
[FIGURE 7 | Score: 16 Points]
|
149
202
|
|
150
|
-
### 6.
|
203
|
+
### 6. How To Score Words
|
151
204
|
|
152
205
|
- You score 2 points per letter tile for any word formed with all letters
|
153
206
|
only one tile high (no letter in the word is stacked on top of another
|
@@ -178,7 +231,7 @@ makes it plural as shown in Figure 7. You score points for both words.
|
|
178
231
|
- At the end of the game, 5 points are subtracted from your score for
|
179
232
|
each letter tile you cannot play.
|
180
233
|
|
181
|
-
### 7.
|
234
|
+
### 7. Illegal Words
|
182
235
|
|
183
236
|
Any word that falls into any category listed below, is an illegal
|
184
237
|
word and cannot be used in the game:
|
@@ -190,7 +243,7 @@ word and cannot be used in the game:
|
|
190
243
|
- Foreign words are illegal unless they appear in the dictionary.
|
191
244
|
- Words that are only one letter long are illegal. *(Note: Not Standard)*
|
192
245
|
|
193
|
-
### 8.
|
246
|
+
### 8. Challenging A Word
|
194
247
|
|
195
248
|
You can challenge an opponent's word if you think it's misspelled or
|
196
249
|
an illegal word. The word must be challenged before another word is
|
@@ -198,13 +251,13 @@ played. Use a dictionary to decide if the challenged word is legal or
|
|
198
251
|
illegal. lf the challenged word is illegal, the player who played it removes
|
199
252
|
the letter tiles from the board and either plays another word or passes.
|
200
253
|
|
201
|
-
### 9.
|
254
|
+
### 9. Passing
|
202
255
|
|
203
256
|
You may pass your turn at any time during the game. Sometimes it is to
|
204
257
|
your advantage to pass, especially toward the end of the game, to allow
|
205
258
|
a better scoring opportunity to open up for you.
|
206
259
|
|
207
|
-
### 10.
|
260
|
+
### 10. Exchanging Your Letters
|
208
261
|
|
209
262
|
On your turn, you may exchange one of your letter tiles for a new one.
|
210
263
|
Just turn the tile you want to exchange letter-side down and draw a
|
@@ -214,7 +267,7 @@ it is a good strategy to give up a turn in order to exchange a letter. For
|
|
214
267
|
example, you may want to exchange a "J" or a "Z" if you draw them late
|
215
268
|
in the game.
|
216
269
|
|
217
|
-
### 11.
|
270
|
+
### 11. How To End The Game
|
218
271
|
|
219
272
|
The game is over as soon as any of the following situations occur:
|
220
273
|
- When one player uses all of his or her letter tiles, and no tiles remain in
|
@@ -227,11 +280,11 @@ The game is over as soon as any of the following situations occur:
|
|
227
280
|
When the game is over, total each player's final score. Subtract 5 points
|
228
281
|
from a player's score for each letter tile he/she has not played.
|
229
282
|
|
230
|
-
###
|
283
|
+
### How To Win
|
231
284
|
|
232
285
|
The player who scores the most points wins.
|
233
286
|
|
234
|
-
###
|
287
|
+
### Solo Play Rules
|
235
288
|
|
236
289
|
Follow setup and gameplay rules as explained above. Make words, one at
|
237
290
|
a time, and score points for every word you make. **NOTE:** During the game,
|
data/exe/upwords
CHANGED
data/lib/upwords.rb
CHANGED
@@ -7,17 +7,17 @@ require 'upwords/board'
|
|
7
7
|
require 'upwords/letter_bank'
|
8
8
|
require 'upwords/letter_rack'
|
9
9
|
require 'upwords/dictionary'
|
10
|
+
require 'upwords/word'
|
10
11
|
|
11
12
|
require 'upwords/shape'
|
12
13
|
require 'upwords/move'
|
13
|
-
require 'upwords/move_manager'
|
14
14
|
|
15
15
|
require 'upwords/cursor'
|
16
|
-
|
17
|
-
require 'upwords/word'
|
18
16
|
require 'upwords/player'
|
19
|
-
|
17
|
+
|
18
|
+
require 'upwords/move_manager'
|
20
19
|
require 'upwords/game'
|
20
|
+
require 'upwords/ui'
|
21
21
|
|
22
22
|
module Upwords
|
23
23
|
# Raised when player makes an illegal move
|
@@ -42,6 +42,10 @@ module Upwords
|
|
42
42
|
DELETE = 127
|
43
43
|
ENTER = 10
|
44
44
|
|
45
|
+
# Curses Color Constants
|
46
|
+
RED = 1
|
47
|
+
YELLOW = 2
|
48
|
+
|
45
49
|
# Official Scrabble Player Dictionary file
|
46
50
|
OSPD_FILE = File.join(File.dirname(__FILE__), "../data/ospd.txt")
|
47
51
|
|
data/lib/upwords/board.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Upwords
|
2
2
|
class Board
|
3
3
|
|
4
|
-
attr_accessor :max_height, :size
|
4
|
+
attr_accessor :max_height, :min_word_length, :size
|
5
5
|
|
6
6
|
# creates a 10 x 10 board
|
7
7
|
def initialize(size=10, max_height=5)
|
@@ -10,6 +10,7 @@ module Upwords
|
|
10
10
|
else
|
11
11
|
@size = size
|
12
12
|
@max_height = max_height
|
13
|
+
@min_word_length = 2
|
13
14
|
@grid = Hash.new do |h, (row, col)|
|
14
15
|
if row < 0 || col < 0 || num_rows <= row || num_columns <= col
|
15
16
|
raise IllegalMove, "#{row}, #{col} is out of bounds!"
|
@@ -28,11 +29,6 @@ module Upwords
|
|
28
29
|
@grid.key?([row, col]) && stack_height(row, col) > 0
|
29
30
|
end
|
30
31
|
|
31
|
-
# maximum letters than can be stacked in one space
|
32
|
-
def min_word_length
|
33
|
-
2
|
34
|
-
end
|
35
|
-
|
36
32
|
def num_rows
|
37
33
|
@size
|
38
34
|
end
|
@@ -70,6 +66,7 @@ module Upwords
|
|
70
66
|
else
|
71
67
|
return true
|
72
68
|
end
|
69
|
+
|
73
70
|
return false
|
74
71
|
end
|
75
72
|
|
@@ -84,13 +81,8 @@ module Upwords
|
|
84
81
|
@grid[[row, col]].pop
|
85
82
|
end
|
86
83
|
|
87
|
-
# show top letter in board space
|
88
84
|
def top_letter(row, col)
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
def get_letter(row, col, depth=1)
|
93
|
-
@grid[[row, col]][-depth]
|
85
|
+
@grid[[row, col]].last
|
94
86
|
end
|
95
87
|
|
96
88
|
def word_positions
|
data/lib/upwords/cursor.rb
CHANGED
@@ -6,9 +6,9 @@ module Upwords
|
|
6
6
|
@max_y = max_y
|
7
7
|
@max_x = max_x
|
8
8
|
|
9
|
-
#
|
10
|
-
@y = init_y
|
11
|
-
@x = init_x
|
9
|
+
# HACK: Force init_y, init_x to be in bounds
|
10
|
+
@y = init_y % @max_y
|
11
|
+
@x = init_x % @max_x
|
12
12
|
end
|
13
13
|
|
14
14
|
def up
|
@@ -32,7 +32,7 @@ module Upwords
|
|
32
32
|
@x = (x + dx) % @max_x
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def pos
|
36
36
|
[y, x]
|
37
37
|
end
|
38
38
|
end
|
data/lib/upwords/game.rb
CHANGED
@@ -2,19 +2,15 @@ module Upwords
|
|
2
2
|
class Game
|
3
3
|
attr_reader :board, :cursor, :players
|
4
4
|
|
5
|
-
def initialize(
|
5
|
+
def initialize(max_players = 4)
|
6
6
|
@max_players = max_players
|
7
|
-
@display_on = display_on
|
8
7
|
@board = Board.new(10, 5)
|
9
8
|
@letter_bank = LetterBank.new(ALL_LETTERS.dup)
|
10
|
-
@cursor = Cursor.new(@board.num_rows,
|
11
|
-
@board.num_columns,
|
12
|
-
*@board.middle_square[0])
|
9
|
+
@cursor = Cursor.new(@board.num_rows, @board.num_columns, *@board.middle_square[0])
|
13
10
|
@dict = Dictionary.import(OSPD_FILE)
|
14
11
|
@moves = MoveManager.new(@board, @dict)
|
15
12
|
@players = []
|
16
|
-
@running =
|
17
|
-
@submitted = false
|
13
|
+
@running = true
|
18
14
|
end
|
19
15
|
|
20
16
|
# =========================================
|
@@ -33,80 +29,39 @@ module Upwords
|
|
33
29
|
player_count = @players.size
|
34
30
|
end
|
35
31
|
|
36
|
-
def add_player(name = nil, cpu = false)
|
37
|
-
if player_count >= max_players
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@players << Player.new(name, rack_capacity=7, cpu)
|
44
|
-
end
|
45
|
-
@players.each {|p| p.refill_rack(@letter_bank) }
|
32
|
+
def add_player(name = nil, letter_capacity = 7, cpu = false)
|
33
|
+
raise ArgumentError, "No more players can join" if player_count >= max_players
|
34
|
+
|
35
|
+
# Automatically name player if no name is provided
|
36
|
+
name = "Player #{player_count + 1}" if name.nil? || name.length == 0
|
37
|
+
|
38
|
+
@players << Player.new(name, letter_capacity, cpu)
|
46
39
|
end
|
47
40
|
|
48
|
-
def
|
49
|
-
|
50
|
-
num_players = 0
|
51
|
-
|
52
|
-
# Select how many players will be in the game
|
53
|
-
# TODO: Add a command-line flag to allow players to skip this step
|
54
|
-
until (1..@max_players).include?(num_players) do
|
55
|
-
print "How many players will play? (1-#{@max_players})\n"
|
56
|
-
num_players = gets.chomp.to_i
|
57
|
-
print "\n"
|
58
|
-
if !(1..@max_players).include?(num_players)
|
59
|
-
print "Invalid selection: #{num_players}\n\n"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Name each player and choose if they are humans or computers
|
64
|
-
# TODO: Add a command-line flag to set this
|
65
|
-
(1..num_players).each do |idx|
|
66
|
-
print "What is Player #{idx}'s name?\n"
|
67
|
-
name = gets.chomp
|
68
|
-
print "Is Player #{idx} or a computer? (y/n)\n"
|
69
|
-
cpu = gets.chomp
|
70
|
-
add_player(name, cpu.upcase == "Y")
|
71
|
-
print "\n"
|
72
|
-
end
|
41
|
+
def all_refill_racks
|
42
|
+
@players.each {|p| p.refill_rack(@letter_bank) }
|
73
43
|
end
|
74
44
|
|
75
45
|
# =========================================
|
76
|
-
#
|
46
|
+
# Move Manager Methods
|
77
47
|
# =========================================
|
78
|
-
|
79
|
-
def init_window
|
80
|
-
Curses.noecho
|
81
|
-
Curses.curs_set(0)
|
82
|
-
Curses.init_screen
|
83
|
-
# Curses.start_color
|
84
|
-
|
85
|
-
@win = Graphics.new(self)
|
86
|
-
@win.keypad(true)
|
87
|
-
end
|
88
48
|
|
89
|
-
def
|
90
|
-
@
|
91
|
-
end
|
92
|
-
|
93
|
-
def refresh_graphics
|
94
|
-
if display_on? && running?
|
95
|
-
@win.refresh
|
96
|
-
end
|
49
|
+
def play_letter(letter, y = @cursor.y, x = @cursor.x)
|
50
|
+
@moves.add(current_player, modify_letter_input(letter), y, x)
|
97
51
|
end
|
98
52
|
|
99
|
-
def
|
100
|
-
|
101
|
-
@win.message = msg
|
102
|
-
refresh_graphics
|
103
|
-
end
|
53
|
+
def undo_last
|
54
|
+
@moves.undo_last(current_player)
|
104
55
|
end
|
105
56
|
|
106
|
-
def
|
107
|
-
|
57
|
+
def pending_position?(row, col)
|
58
|
+
@moves.include?(row, col)
|
108
59
|
end
|
109
60
|
|
61
|
+
# =========================================
|
62
|
+
# Output messages that rely on MoveManager
|
63
|
+
# =========================================
|
64
|
+
|
110
65
|
def standard_message
|
111
66
|
"#{current_player.name}'s pending words: #{pending_result}"
|
112
67
|
end
|
@@ -116,7 +71,7 @@ module Upwords
|
|
116
71
|
|
117
72
|
unless new_words.empty?
|
118
73
|
new_words.map do |w|
|
119
|
-
"#{w} (#{w.score})"
|
74
|
+
"#{w} (#{w.score})".upcase
|
120
75
|
end.join(", ") + " (Total = #{@moves.pending_score(current_player)})"
|
121
76
|
end
|
122
77
|
end
|
@@ -129,196 +84,79 @@ module Upwords
|
|
129
84
|
@running
|
130
85
|
end
|
131
86
|
|
132
|
-
def
|
133
|
-
@
|
134
|
-
|
135
|
-
|
136
|
-
add_players
|
137
|
-
|
138
|
-
# Start graphics
|
139
|
-
init_window if @display_on
|
140
|
-
clear_message
|
141
|
-
|
142
|
-
# Start main loop
|
143
|
-
while running? do
|
144
|
-
begin
|
145
|
-
# ------ CPU MOVE --------
|
146
|
-
if current_player.cpu?
|
147
|
-
update_message "#{current_player.name} is thinking..."
|
148
|
-
cpu_move = current_player.cpu_move(@board, @dict, 50, 10)
|
149
|
-
|
150
|
-
if !cpu_move.nil?
|
151
|
-
cpu_move.each do |posn, letter|
|
152
|
-
@moves.add(current_player, letter, *posn)
|
153
|
-
end
|
154
|
-
submit_moves(need_confirm=false)
|
155
|
-
else
|
156
|
-
skip_turn(need_confirm=false)
|
157
|
-
end
|
158
|
-
else
|
159
|
-
read_input(@win.getch)
|
160
|
-
end
|
161
|
-
|
162
|
-
if @submitted
|
163
|
-
# TODO: remove magic string from last move message
|
164
|
-
if @players.all? {|p| p.last_turn == "skipped turn"} || @letter_bank.empty? && current_player.rack_empty?
|
165
|
-
game_over
|
166
|
-
@running = false
|
167
|
-
else
|
168
|
-
next_turn
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
refresh_graphics
|
173
|
-
|
174
|
-
rescue IllegalMove => exception
|
175
|
-
update_message "#{exception.message} (press any key to continue...)"
|
176
|
-
@win.getch if display_on?
|
177
|
-
clear_message
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
def read_input(key)
|
184
|
-
case key
|
185
|
-
when 'Q'
|
186
|
-
exit_game
|
187
|
-
when SPACE
|
188
|
-
toggle_rack_visibility
|
189
|
-
when DELETE
|
190
|
-
undo_moves
|
191
|
-
when ENTER
|
87
|
+
def cpu_move
|
88
|
+
move = current_player.cpu_move(@board, @dict, batch_size=50, min_score=10)
|
89
|
+
if !move.nil?
|
90
|
+
move.each { |pos, letter| play_letter(letter, *pos) }
|
192
91
|
submit_moves
|
193
|
-
|
194
|
-
@cursor.up
|
195
|
-
when Curses::KEY_DOWN
|
196
|
-
@cursor.down
|
197
|
-
when Curses::KEY_LEFT
|
198
|
-
@cursor.left
|
199
|
-
when Curses::KEY_RIGHT
|
200
|
-
@cursor.right
|
201
|
-
when '+'
|
202
|
-
swap_letter
|
203
|
-
when '-'
|
92
|
+
else
|
204
93
|
skip_turn
|
205
|
-
when /[[:alpha:]]/
|
206
|
-
@moves.add(current_player, modify_letter_input(key), @cursor.y, @cursor.x)
|
207
|
-
clear_message
|
208
94
|
end
|
209
95
|
end
|
210
96
|
|
211
|
-
def next_turn
|
212
|
-
@players.rotate!
|
213
|
-
@win.hide_rack if display_on?
|
214
|
-
clear_message
|
215
|
-
@submitted = false
|
216
|
-
end
|
217
|
-
|
218
|
-
# =========================================
|
219
|
-
# Methods Related to Key Inputs
|
220
|
-
# =========================================
|
221
|
-
|
222
|
-
# Capitalize letters, and convert 'Q' and 'q' to 'Qu'
|
223
|
-
def modify_letter_input(letter)
|
224
|
-
if letter =~ /[Qq]/
|
225
|
-
'Qu'
|
226
|
-
else
|
227
|
-
letter.capitalize
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def confirm_action?(question_text)
|
232
|
-
if display_on?
|
233
|
-
update_message "#{question_text} (y/n)"
|
234
|
-
inp = @win.getch
|
235
|
-
clear_message
|
236
|
-
inp == 'y' || inp == 'Y'
|
237
|
-
else
|
238
|
-
true # Never ask for confirm if the display_on is off
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
97
|
# =========================================
|
243
98
|
# Game Procedures Bound to some Key Input
|
244
99
|
# =========================================
|
245
100
|
|
246
|
-
def
|
247
|
-
@moves.
|
248
|
-
|
101
|
+
def submit_moves
|
102
|
+
@moves.submit(current_player)
|
103
|
+
current_player.refill_rack(@letter_bank)
|
104
|
+
current_player.last_turn = "played word" # TODO: remove magic string from last move message
|
105
|
+
next_turn
|
249
106
|
end
|
250
107
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
# TODO: remove magic string from last move message
|
259
|
-
current_player.last_turn = "played word"
|
260
|
-
end
|
108
|
+
def swap_letter(letter)
|
109
|
+
letter = modify_letter_input(letter)
|
110
|
+
@moves.undo_all(current_player)
|
111
|
+
current_player.swap_letter(letter, @letter_bank)
|
112
|
+
current_player.last_turn = "swapped letter" # TODO: remove magic string from last move message
|
113
|
+
next_turn
|
261
114
|
end
|
262
115
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
if letter =~ /[[:alpha:]]/
|
269
|
-
letter = modify_letter_input(letter)
|
270
|
-
if !need_confirm || (confirm_action? "Swap '#{letter}' for another?")
|
271
|
-
@moves.undo_all(current_player)
|
272
|
-
current_player.swap_letter(letter, @letter_bank)
|
273
|
-
@submitted = true
|
274
|
-
|
275
|
-
# TODO: remove magic string from last move message
|
276
|
-
current_player.last_turn = "swapped letter"
|
277
|
-
end
|
278
|
-
end
|
116
|
+
def skip_turn
|
117
|
+
@moves.undo_all(current_player)
|
118
|
+
current_player.last_turn = "skipped turn" # TODO: remove magic string from last move message
|
119
|
+
next_turn
|
279
120
|
end
|
280
121
|
|
281
|
-
def
|
282
|
-
|
283
|
-
|
284
|
-
@submitted = true
|
122
|
+
def exit_game
|
123
|
+
@running = false
|
124
|
+
end
|
285
125
|
|
286
|
-
|
287
|
-
|
288
|
-
|
126
|
+
# =================
|
127
|
+
# Game over methods
|
128
|
+
# =================
|
129
|
+
|
130
|
+
def game_over?
|
131
|
+
@players.all? {|p| p.last_turn == "skipped turn"} || (@letter_bank.empty? && current_player.rack_empty?)
|
289
132
|
end
|
290
133
|
|
291
|
-
def
|
292
|
-
|
293
|
-
@running = false
|
294
|
-
@win.close if display_on?
|
295
|
-
end
|
134
|
+
def get_top_score
|
135
|
+
@players.map {|p| p.score}.max
|
296
136
|
end
|
297
137
|
|
298
|
-
def
|
299
|
-
@
|
138
|
+
def get_winners
|
139
|
+
@players.select{|p| p.score == get_top_score}.map{|p| p.name}
|
300
140
|
end
|
301
141
|
|
302
|
-
|
303
|
-
update_message "The game is over. Press any key to continue to see who won..."
|
304
|
-
@win.getch if display_on?
|
142
|
+
private
|
305
143
|
|
306
|
-
|
307
|
-
|
308
|
-
|
144
|
+
def next_turn
|
145
|
+
if game_over?
|
146
|
+
# Subtract 5 points for each tile remaining
|
147
|
+
@players.each { |p| p.score -= p.letters.size * 5 }
|
148
|
+
else
|
149
|
+
@players.rotate!
|
309
150
|
end
|
151
|
+
end
|
310
152
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
update_message "And the winner is... #{winners[0]} with #{top_score} points!"
|
153
|
+
# Capitalize letters, and convert 'Q' and 'q' to 'Qu'
|
154
|
+
def modify_letter_input(letter)
|
155
|
+
if letter =~ /[Qq]/
|
156
|
+
'Qu'
|
316
157
|
else
|
317
|
-
|
158
|
+
letter.capitalize
|
318
159
|
end
|
319
|
-
|
320
|
-
@win.getch if display_on?
|
321
|
-
exit_game(need_confirm=false)
|
322
160
|
end
|
323
161
|
|
324
162
|
end
|