upwords 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d976dd35f79fb8bce46ee07868dff9b3e006307
4
- data.tar.gz: a041750ee16726eb7120413b5e31556fa576dc76
3
+ metadata.gz: 6c9bd9e51484e62844a28edd893d75677898ca58
4
+ data.tar.gz: a6d853e3009e62f02d20b0bca25ea295d7e15e62
5
5
  SHA512:
6
- metadata.gz: f77519cd05dbc45e243f3e36ca24a4f219b800b105dc1538313d71c342e60ca30434f217cb6ce7747ce1e8fa6b442c421c9ee89cc8931e58930c87634e2de169
7
- data.tar.gz: 63e37dd7bd4f961bcd189121c51402e00d4bbd7b5d51c62315f09c755aca522e69a2191c8da60aa671d26343cc08246e991f7965ecd17b8f9add784224823fc4
6
+ metadata.gz: 8d9708d7e8b1910c0662defce90876449ec30f459ad1caf210e4e95dc0f89fa391c2a9e9c4fa54caf6f527d0f7b85c75ad85b2abce0bfb7e585f90033f43c48f
7
+ data.tar.gz: 696b89a6feaf45026c0a7b94046d93c6eb03063c1f01a3d7b9d2ae8b3e7e6431a374c9f49f8656d6ddd34ebf3f986c442a251b70ad2eba943100ba929e4ab4ce
data/README.md CHANGED
@@ -1,4 +1,38 @@
1
- # UPWORDS - THE QUICK STACKING WORD GAME
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
- ## OBJECT
51
+ ## Objective
18
52
 
19
53
  Build words to score the most points.
20
54
 
21
- ## CONTENTS
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
- ## SETUP
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
- ## GAMEPLAY
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. BASIC TURN
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. HOW TO FORM WORDS
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
- Figure 2 Score: 8 Points
96
-
97
- [FIGURE 2]
98
-
99
- Figure 3 Score: 10 Points
100
-
101
- [FIGURE 3]
102
-
103
- **N0TE:** Any letter in your word that is adjacent to another letter or letters on
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. HOW TO SCORE WORDS
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. ILLEGAL WORDS
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. CHALLENGING A WORD
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. PASSING
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. EXCHANGING YOUR LETTERS
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. HOW TO END THE GAME
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
- ### HOW TO WIN
283
+ ### How To Win
231
284
 
232
285
  The player who scores the most points wins.
233
286
 
234
- ### SOLO PLAY RULES
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,
@@ -2,4 +2,4 @@
2
2
 
3
3
  require 'upwords'
4
4
 
5
- Upwords::Game.new.run
5
+ Upwords::UI::new(Upwords::Game.new, row_height=1, col_width=4)
@@ -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
- require 'upwords/graphics'
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
 
@@ -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
- get_letter(row, col, 1)
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
@@ -6,9 +6,9 @@ module Upwords
6
6
  @max_y = max_y
7
7
  @max_x = max_x
8
8
 
9
- # TODO: Handle case where init_y, x are outside bounds
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 posn
35
+ def pos
36
36
  [y, x]
37
37
  end
38
38
  end
@@ -2,19 +2,15 @@ module Upwords
2
2
  class Game
3
3
  attr_reader :board, :cursor, :players
4
4
 
5
- def initialize(display_on = true, max_players = 4)
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 = false
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
- raise StandardError, "No more players can join"
39
- else
40
- if name.nil? || name.size == 0
41
- name = "Player #{player_count + 1}"
42
- end
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 add_players(player_names = nil)
49
- print "\n"
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
- # Graphics Methods
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 display_on?
90
- @display_on
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 update_message msg
100
- if display_on?
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 clear_message
107
- update_message standard_message
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 run
133
- @running = true
134
-
135
- # Add players
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
- when Curses::KEY_UP
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 undo_moves
247
- @moves.undo_last(current_player)
248
- clear_message
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 submit_moves(need_confirm=true)
252
- if !need_confirm || (confirm_action? "Are you sure you want to submit?")
253
- @moves.submit(current_player)
254
- current_player.refill_rack(@letter_bank)
255
- @submitted = true
256
- clear_message
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
- # TODO: Test this method...
264
- def swap_letter(need_confirm=true)
265
- update_message "Pick a letter to swap... "
266
- letter = @win.getch
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 skip_turn(need_confirm=true)
282
- if !need_confirm || (confirm_action? "Are you sure you want to skip your turn?")
283
- @moves.undo_all(current_player)
284
- @submitted = true
122
+ def exit_game
123
+ @running = false
124
+ end
285
125
 
286
- # TODO: remove magic string from last move message
287
- current_player.last_turn = "skipped turn"
288
- end
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 exit_game(need_confirm=true)
292
- if !need_confirm || (confirm_action? "Are you sure you want to exit the game?")
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 toggle_rack_visibility
299
- @win.toggle_rack_visibility
138
+ def get_winners
139
+ @players.select{|p| p.score == get_top_score}.map{|p| p.name}
300
140
  end
301
141
 
302
- def game_over
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
- # Subtract 5 points for each tile remaining
307
- @players.each do |p|
308
- p.score -= p.letters.size * 5
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
- top_score = @players.map {|p| p.score}.max
312
- winners = @players.select{|p| p.score == top_score}.map{|p| p.name}
313
-
314
- if winners.size == 1
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
- update_message "We have a tie! #{winners.join(', ')} all win with #{top_score} points!"
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