Class: Upwords::UI
- Inherits:
-
Object
- Object
- Upwords::UI
- Defined in:
- lib/upwords/ui.rb
Instance Method Summary collapse
-
#add_players ⇒ Object
Select the maximum number of players, then add players and select if they humans or computers TODO: refactor this method.
- #clear_message ⇒ Object
-
#draw_confirm(text) ⇒ Object
TODO: make confirmation options more clear.
- #draw_controls ⇒ Object
- #draw_grid ⇒ Object
- #draw_letters ⇒ Object
-
#draw_message(text) ⇒ Object
Draw individual game elements =============================.
- #draw_player_info ⇒ Object
- #draw_stack_heights ⇒ Object
-
#draw_update_loop ⇒ Object
Main methods: draw and input loops ==================================.
- #get_game_result ⇒ Object
-
#initialize(game, row_height = 1, col_width = 4) ⇒ UI
constructor
A new instance of UI.
-
#read_key ⇒ Object
If read_key returns ‘false’, then current iteration of the input loop ends.
Constructor Details
#initialize(game, row_height = 1, col_width = 4) ⇒ UI
Returns a new instance of UI.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/upwords/ui.rb', line 4 def initialize(game, row_height = 1, col_width = 4) # Game and drawing variables @game = game @rows = game.board.num_rows @cols = game.board.num_columns @row_height = row_height @col_width = col_width @rack_visible = false # Configure Curses and initialize screen Curses.noecho Curses.curs_set(2) # Blinking cursor Curses.init_screen Curses.start_color # Initialize colors Curses.init_pair(RED, Curses::COLOR_RED, Curses::COLOR_BLACK) # Red on black background Curses.init_pair(YELLOW, Curses::COLOR_YELLOW, Curses::COLOR_BLACK) # Yellow on black background # Initialize main window and game loop begin @win = Curses.stdscr @win.keypad=(true) add_players @game.all_refill_racks @win.setpos(*letter_pos(*@game.cursor.pos)) draw_update_loop ensure Curses.close_screen end end |
Instance Method Details
#add_players ⇒ Object
Select the maximum number of players, then add players and select if they humans or computers TODO: refactor this method
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/upwords/ui.rb', line 135 def add_players @win.setpos(0, 0) Curses.echo @win.keypad=(false) num_players = 0 # Select how many players will be in the game # TODO: Add a command-line flag to allow players to skip this step until (1..@game.max_players).include?(num_players.to_i) do @win.addstr("How many players will play? (1-#{@game.max_players})\n") num_players = @win.getstr @win.addstr("Invalid selection\n") if !(1..@game.max_players).include?(num_players.to_i) @win.addstr("\n") # Refresh screen if lines go beyond terminal window clear_terminal if @win.cury >= @win.maxy - 1 end # Name each player and choose if they are humans or computers # TODO: Add a command-line flag to set this (1..num_players.to_i).each do |idx| @win.addstr("What is Player #{idx}'s name? (Press enter to submit...)\n") name = @win.getstr name = (name =~ /[[:alpha:]]/ ? name : sprintf('Player %d', idx)) @win.addstr("\nIs #{name} a computer? (y/n)\n") cpu = @win.getstr @game.add_player(name, rack_capacity=7, cpu.upcase == "Y") @win.addstr("\n") # Refresh screen if lines go beyond terminal window clear_terminal if @win.cury >= @win.maxy - 1 end ensure Curses.noecho @win.keypad=(true) end |
#clear_message ⇒ Object
199 200 201 |
# File 'lib/upwords/ui.rb', line 199 def ("") end |
#draw_confirm(text) ⇒ Object
TODO: make confirmation options more clear
218 219 220 221 222 223 |
# File 'lib/upwords/ui.rb', line 218 def draw_confirm(text) ("#{text}") reply = (@win.getch.to_s).upcase == "Y" return reply end |
#draw_controls ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/upwords/ui.rb', line 238 def draw_controls draw_wrapper do y, x = controls_info_pos ["----------------------", "| Controls |", "----------------------", "Show Letters [SPACE]", "Undo Last Move [DEL]", "Submit Move [ENTER]", "Swap Letter [+]", "Skip Turn [-]", "Quit Game [SHIFT+Q]", "Force Quit [CTRL+Z]" # TODO: technically this only works for unix shells... ].each_with_index do |line, i| @win.setpos(y+i, x) @win.addstr(line) end end end |
#draw_grid ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/upwords/ui.rb', line 225 def draw_grid draw_wrapper do # create a list containing each line of the board string divider = [nil, ["-" * @col_width] * @cols, nil].flatten.join("+") spaces = [nil, [" " * @col_width] * @cols, nil].flatten.join("|") lines = ([divider] * (@rows + 1)).zip([spaces] * @rows).flatten # concatenate board lines and draw in a sub-window on the terminal @win.setpos(0, 0) @win.addstr(lines.join("\n")) end end |
#draw_letters ⇒ Object
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/upwords/ui.rb', line 258 def draw_letters board = @game.board draw_for_each_cell do |row, col| @win.setpos(*letter_pos(row, col)) # HACK: removes yellow highlighting from 'Qu' letter = "#{board.top_letter(row, col)} "[0..1] if @game.pending_position?(row, col) Curses.attron(Curses.color_pair(YELLOW)) { @win.addstr(letter) } else @win.addstr(letter) end end end |
#draw_message(text) ⇒ Object
Draw individual game elements
195 196 197 |
# File 'lib/upwords/ui.rb', line 195 def (text) write_str(*, text, clear_below=true) end |
#draw_player_info ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/upwords/ui.rb', line 203 def draw_player_info draw_wrapper do py, px = player_info_pos # Draw rack for current player only write_str(py, px, "#{@game.current_player.name}'s letters:", clear_right=true) write_str(py+1, px, "[#{@game.current_player.show_rack(masked=!@rack_visible)}]", clear_right=true) @game.players.each_with_index do |p, i| write_str(py+i+3, px, sprintf("%s %-13s %4d", p == @game.current_player ? "->" : " ", "#{p.name}:", p.score), clear_right=true) end end end |
#draw_stack_heights ⇒ Object
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/upwords/ui.rb', line 275 def draw_stack_heights board = @game.board draw_for_each_cell do |row, col| @win.setpos(*stack_height_pos(row, col)) case (height = board.stack_height(row, col)) when 0 @win.addstr("-") when board.max_height Curses.attron(Curses.color_pair(RED)) { @win.addstr(height.to_s) } else @win.addstr(height.to_s) end end end |
#draw_update_loop ⇒ Object
Main methods: draw and input loops
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/upwords/ui.rb', line 42 def draw_update_loop draw_grid draw_controls while @game.running? do @rack_visible = false draw_player_info "#{@game.current_player.name}'s turn" # CPU move subroutine if @game.current_player.cpu? "#{@game.current_player.name} is thinking..." @game.cpu_move draw_letters draw_stack_heights draw_player_info # Read key inputs then update cursor and window else while read_key do @win.setpos(*letter_pos(*@game.cursor.pos)) draw_letters draw_stack_heights draw_player_info end end # Game over subroutine if @game.game_over? draw_player_info get_game_result end end end |
#get_game_result ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/upwords/ui.rb', line 176 def get_game_result draw_confirm("The game is over. Press any key to continue to see who won...") top_score = @game.get_top_score winners = @game.get_winners if winners.size == 1 draw_confirm "And the winner is... #{winners.first} with #{top_score} points!" else draw_confirm "We have a tie! #{winners.join(', ')} all win with #{top_score} points!" end @game.exit_game end |
#read_key ⇒ Object
If read_key returns ‘false’, then current iteration of the input loop ends
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/upwords/ui.rb', line 78 def read_key case (key = @win.getch) when 'Q' if draw_confirm("Are you sure you want to exit the game? (y/n)") @game.exit_game return false end when DELETE @game.undo_last (@game.) # TODO: factor this method when Curses::Key::UP @game.cursor.up when Curses::Key::DOWN @game.cursor.down when Curses::Key::LEFT @game.cursor.left when Curses::Key::RIGHT @game.cursor.right when SPACE @rack_visible = !@rack_visible when ENTER if draw_confirm("Are you sure you wanted to submit? (y/n)") @game.submit_moves return false end when '+' ("Pick a letter to swap") letter = @win.getch if letter =~ /[[:alpha:]]/ && draw_confirm("Swap '#{letter}' for a new letter? (y/n)") @game.swap_letter(letter) return false else ("'#{letter}' is not a valid letter") end when '-' if draw_confirm("Are you sure you wanted to skip your turn? (y/n)") @game.skip_turn return false end when /[[:alpha:]]/ @game.play_letter(key) (@game.) end return true rescue IllegalMove => exception draw_confirm("#{exception.} (press any key to continue...)") return true end |