git_game_show 0.1.2 → 0.1.4
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/bin/git-game-show +18 -0
- data/lib/git_game_show/cli.rb +100 -40
- data/lib/git_game_show/game_server.rb +1 -1
- data/lib/git_game_show/player_client.rb +201 -189
- data/lib/git_game_show/updater.rb +107 -0
- data/lib/git_game_show/version.rb +2 -2
- data/lib/git_game_show.rb +5 -4
- metadata +3 -2
@@ -4,48 +4,60 @@ require 'timeout'
|
|
4
4
|
|
5
5
|
module GitGameShow
|
6
6
|
class PlayerClient
|
7
|
-
attr_reader :host, :port, :password, :name
|
8
|
-
|
9
|
-
def initialize(host:, port:, password:, name:)
|
7
|
+
attr_reader :host, :port, :password, :name, :secure
|
8
|
+
|
9
|
+
def initialize(host:, port:, password:, name:, secure: false)
|
10
10
|
@host = host
|
11
11
|
@port = port
|
12
12
|
@password = password
|
13
13
|
@name = name
|
14
|
+
@secure = secure
|
14
15
|
@ws = nil
|
15
16
|
@prompt = TTY::Prompt.new
|
16
17
|
@players = []
|
17
18
|
@game_state = :lobby # :lobby, :playing, :ended
|
18
19
|
@current_timer_id = nil
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
def connect
|
22
23
|
begin
|
23
24
|
client = self # Store reference to the client instance
|
24
|
-
|
25
|
-
|
25
|
+
|
26
|
+
# Check if the connection should use a secure protocol
|
27
|
+
# For ngrok TCP tunnels, we should use regular ws:// since ngrok tcp doesn't provide SSL termination
|
28
|
+
# Only use wss:// if the secure flag is explicitly set (for configured HTTPS endpoints)
|
29
|
+
protocol = if @secure
|
30
|
+
puts "Using secure WebSocket connection (wss://)".colorize(:cyan)
|
31
|
+
'wss'
|
32
|
+
else
|
33
|
+
'ws'
|
34
|
+
end
|
35
|
+
|
36
|
+
@ws = WebSocket::Client::Simple.connect("#{protocol}://#{host}:#{port}")
|
37
|
+
|
26
38
|
@ws.on :open do
|
27
39
|
puts "Connected to server".colorize(:green)
|
28
40
|
# Use the stored client reference
|
29
41
|
client.send_join_request
|
30
42
|
end
|
31
|
-
|
43
|
+
|
32
44
|
@ws.on :message do |msg|
|
33
45
|
client.handle_message(msg)
|
34
46
|
end
|
35
|
-
|
47
|
+
|
36
48
|
@ws.on :error do |e|
|
37
49
|
puts "Error: #{e.message}".colorize(:red)
|
38
50
|
end
|
39
|
-
|
51
|
+
|
40
52
|
@ws.on :close do |e|
|
41
53
|
puts "Connection closed (#{e.code}: #{e.reason})".colorize(:yellow)
|
42
54
|
exit(1)
|
43
55
|
end
|
44
|
-
|
56
|
+
|
45
57
|
# Keep the client running
|
46
58
|
loop do
|
47
59
|
sleep(1)
|
48
|
-
|
60
|
+
|
49
61
|
# Check if connection is still alive
|
50
62
|
if @ws.nil? || @ws.closed?
|
51
63
|
puts "Connection lost. Exiting...".colorize(:red)
|
@@ -56,7 +68,7 @@ module GitGameShow
|
|
56
68
|
puts "Failed to connect: #{e.message}".colorize(:red)
|
57
69
|
end
|
58
70
|
end
|
59
|
-
|
71
|
+
|
60
72
|
# Make these methods public so they can be called from the WebSocket callbacks
|
61
73
|
def send_join_request
|
62
74
|
send_message({
|
@@ -65,14 +77,14 @@ module GitGameShow
|
|
65
77
|
password: password
|
66
78
|
})
|
67
79
|
end
|
68
|
-
|
80
|
+
|
69
81
|
# Make public for WebSocket callback
|
70
82
|
def handle_message(msg)
|
71
83
|
begin
|
72
84
|
data = JSON.parse(msg.data)
|
73
|
-
|
85
|
+
|
74
86
|
# Remove debug print to reduce console noise
|
75
|
-
|
87
|
+
|
76
88
|
case data['type']
|
77
89
|
when MessageType::JOIN_RESPONSE
|
78
90
|
handle_join_response(data)
|
@@ -105,7 +117,7 @@ module GitGameShow
|
|
105
117
|
puts "Error processing message: #{e.message}".colorize(:red)
|
106
118
|
end
|
107
119
|
end
|
108
|
-
|
120
|
+
|
109
121
|
def handle_join_response(data)
|
110
122
|
if data['success']
|
111
123
|
@players = data['players'] # Get the full player list from server
|
@@ -115,22 +127,22 @@ module GitGameShow
|
|
115
127
|
exit(1)
|
116
128
|
end
|
117
129
|
end
|
118
|
-
|
130
|
+
|
119
131
|
def display_waiting_room
|
120
132
|
clear_screen
|
121
|
-
|
133
|
+
|
122
134
|
# Draw header with fancy box
|
123
135
|
terminal_width = `tput cols`.to_i rescue 80
|
124
136
|
terminal_height = `tput lines`.to_i rescue 24
|
125
|
-
|
137
|
+
|
126
138
|
# Create title box
|
127
139
|
puts "┏#{"━" * (terminal_width - 2)}┓".colorize(:green)
|
128
140
|
puts "┃#{" GIT GAME SHOW - WAITING ROOM ".center(terminal_width - 2)}┃".colorize(:green)
|
129
141
|
puts "┗#{"━" * (terminal_width - 2)}┛".colorize(:green)
|
130
|
-
|
142
|
+
|
131
143
|
# Left column width (2/3 of terminal) for main content
|
132
144
|
left_width = (terminal_width * 0.65).to_i
|
133
|
-
|
145
|
+
|
134
146
|
# Display instructions and welcome information
|
135
147
|
puts "\n"
|
136
148
|
puts " Welcome to Git Game Show!".colorize(:yellow)
|
@@ -144,41 +156,41 @@ module GitGameShow
|
|
144
156
|
puts "\n"
|
145
157
|
puts " 🔹 STATUS: Waiting for the host to start the game...".colorize(:light_yellow)
|
146
158
|
puts "\n"
|
147
|
-
|
159
|
+
|
148
160
|
# Draw player section in a box
|
149
161
|
player_box_width = terminal_width - 4
|
150
162
|
puts " ┏#{"━" * player_box_width}┓".colorize(:cyan)
|
151
163
|
puts " ┃#{" PLAYERS ".center(player_box_width)}┃".colorize(:cyan)
|
152
164
|
puts " ┗#{"━" * player_box_width}┛".colorize(:cyan)
|
153
|
-
|
165
|
+
|
154
166
|
# Display list of players in a nicer format
|
155
167
|
if @players.empty?
|
156
168
|
puts " (No other players yet)".colorize(:light_black)
|
157
169
|
else
|
158
170
|
# Calculate number of columns based on terminal width and name lengths
|
159
171
|
max_name_length = @players.map(&:length).max + 10 # Extra space for number and "(You)" text
|
160
|
-
|
172
|
+
|
161
173
|
# Add more spacing between players - increase padding from 4 to 10
|
162
174
|
column_width = max_name_length + 12 # More generous spacing
|
163
175
|
num_cols = [terminal_width / column_width, 3].min # Cap at 3 columns max
|
164
176
|
num_cols = 1 if num_cols < 1
|
165
|
-
|
177
|
+
|
166
178
|
# Use fewer columns for better spacing
|
167
179
|
if num_cols > 1 && @players.size > 6
|
168
180
|
# If we have many players, prefer fewer columns with more space
|
169
181
|
num_cols = [num_cols, 2].min
|
170
182
|
end
|
171
|
-
|
183
|
+
|
172
184
|
# Split players into rows for multi-column display
|
173
185
|
player_rows = @players.each_slice(((@players.size + num_cols - 1) / num_cols).ceil).to_a
|
174
|
-
|
186
|
+
|
175
187
|
puts "\n"
|
176
188
|
player_rows.each do |row_players|
|
177
189
|
row_str = " "
|
178
190
|
row_players.each_with_index do |player, idx|
|
179
191
|
col_idx = player_rows.index { |rp| rp.include?(player) }
|
180
192
|
player_num = col_idx * player_rows[0].length + idx + 1
|
181
|
-
|
193
|
+
|
182
194
|
# Apply different color for current player
|
183
195
|
if player == @name
|
184
196
|
row_str += "#{player_num}. #{player} (You)".colorize(:green).ljust(column_width)
|
@@ -191,30 +203,30 @@ module GitGameShow
|
|
191
203
|
puts ""
|
192
204
|
end
|
193
205
|
end
|
194
|
-
|
206
|
+
|
195
207
|
puts "\n"
|
196
208
|
puts " When the game starts, you'll see questions appear automatically.".colorize(:light_black)
|
197
209
|
puts " Get ready to test your Git knowledge!".colorize(:light_yellow)
|
198
210
|
puts "\n"
|
199
211
|
end
|
200
|
-
|
212
|
+
|
201
213
|
def clear_screen
|
202
214
|
# Reset cursor and clear entire screen
|
203
215
|
print "\033[H\033[2J" # Move to home position and clear screen
|
204
216
|
print "\033[3J" # Clear scrollback buffer
|
205
|
-
|
217
|
+
|
206
218
|
# Reserve bottom line for timer status
|
207
219
|
term_height = `tput lines`.to_i rescue 24
|
208
|
-
|
220
|
+
|
209
221
|
# Move to bottom of screen and clear status line
|
210
222
|
print "\e[#{term_height};1H"
|
211
223
|
print "\e[K"
|
212
224
|
print "\e[H" # Move cursor back to home position
|
213
|
-
|
225
|
+
|
214
226
|
STDOUT.flush
|
215
227
|
end
|
216
|
-
|
217
|
-
|
228
|
+
|
229
|
+
|
218
230
|
# Helper method to print a countdown timer status in the window title
|
219
231
|
# This doesn't interfere with the terminal content
|
220
232
|
def update_title_timer(seconds)
|
@@ -223,7 +235,7 @@ module GitGameShow
|
|
223
235
|
print "\033]0;Git Game Show - #{seconds} seconds remaining\007"
|
224
236
|
STDOUT.flush
|
225
237
|
end
|
226
|
-
|
238
|
+
|
227
239
|
# Super simple ordering implementation with minimal screen updates
|
228
240
|
def handle_ordering_question(options, question_text = nil)
|
229
241
|
# Create a copy of the options that we can modify
|
@@ -232,59 +244,59 @@ module GitGameShow
|
|
232
244
|
selected_index = nil
|
233
245
|
num_options = current_order.size
|
234
246
|
question_text ||= "Put these commits in chronological order (oldest to newest)"
|
235
|
-
|
247
|
+
|
236
248
|
# Extract question data if available
|
237
249
|
data = Thread.current[:question_data] || {}
|
238
250
|
question_number = data['question_number']
|
239
251
|
total_questions = data['total_questions']
|
240
|
-
|
252
|
+
|
241
253
|
# Draw the initial screen once
|
242
254
|
# system('clear') || system('cls')
|
243
|
-
|
255
|
+
|
244
256
|
# Draw question header once
|
245
257
|
if question_number && total_questions
|
246
258
|
puts "\n ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".colorize(:cyan)
|
247
259
|
puts " ┃#{"QUESTION #{question_number} of #{total_questions}".center(45)}┃".colorize(:cyan)
|
248
260
|
puts " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".colorize(:cyan)
|
249
261
|
end
|
250
|
-
|
262
|
+
|
251
263
|
# Draw the main question text once
|
252
264
|
puts "\n #{question_text}".colorize(:light_blue)
|
253
265
|
puts " Put in order from oldest (1) to newest (#{num_options})".colorize(:light_blue)
|
254
|
-
|
266
|
+
|
255
267
|
# Draw instructions once
|
256
268
|
puts "\n INSTRUCTIONS:".colorize(:yellow)
|
257
269
|
puts " • Use ↑/↓ arrows to move cursor".colorize(:white)
|
258
270
|
puts " • Press ENTER to select/deselect an item to move".colorize(:white)
|
259
271
|
puts " • Selected items move with cursor when you press ↑/↓".colorize(:white)
|
260
272
|
puts " • Navigate to Submit and press ENTER when finished".colorize(:white)
|
261
|
-
|
273
|
+
|
262
274
|
# Draw the header for the list content once
|
263
275
|
puts "\n CURRENT ORDER:".colorize(:light_blue)
|
264
|
-
|
276
|
+
|
265
277
|
# Calculate where the list content starts on screen
|
266
278
|
content_start_line = question_number ? 15 : 12
|
267
|
-
|
279
|
+
|
268
280
|
# Draw the list content (this will be redrawn repeatedly)
|
269
281
|
draw_ordering_list(current_order, cursor_index, selected_index, content_start_line, num_options)
|
270
|
-
|
282
|
+
|
271
283
|
# Initialize variables
|
272
|
-
|
284
|
+
|
273
285
|
# Main interaction loop
|
274
286
|
loop do
|
275
287
|
# Read a single keypress
|
276
288
|
char = read_char
|
277
|
-
|
289
|
+
|
278
290
|
# Clear any message on this line
|
279
291
|
move_cursor_to(content_start_line + num_options + 2, 0)
|
280
292
|
print "\r\033[K"
|
281
|
-
|
293
|
+
|
282
294
|
# Check if the timer has expired
|
283
295
|
if @timer_expired
|
284
296
|
# If timer expired, just return the current ordering
|
285
297
|
return current_order
|
286
298
|
end
|
287
|
-
|
299
|
+
|
288
300
|
# Now char is an integer (ASCII code)
|
289
301
|
case char
|
290
302
|
when 13, 10 # Enter key (CR or LF)
|
@@ -306,7 +318,7 @@ module GitGameShow
|
|
306
318
|
# Move cursor up
|
307
319
|
if selected_index == cursor_index && cursor_index > 0
|
308
320
|
# Move the selected item up in the order
|
309
|
-
current_order[cursor_index], current_order[cursor_index - 1] =
|
321
|
+
current_order[cursor_index], current_order[cursor_index - 1] =
|
310
322
|
current_order[cursor_index - 1], current_order[cursor_index]
|
311
323
|
cursor_index -= 1
|
312
324
|
selected_index = cursor_index
|
@@ -317,7 +329,7 @@ module GitGameShow
|
|
317
329
|
when 66, 106, 115 # Down arrow (66='B'), j (106), s (115)
|
318
330
|
if selected_index == cursor_index && cursor_index < num_options - 1
|
319
331
|
# Move the selected item down in the order
|
320
|
-
current_order[cursor_index], current_order[cursor_index + 1] =
|
332
|
+
current_order[cursor_index], current_order[cursor_index + 1] =
|
321
333
|
current_order[cursor_index + 1], current_order[cursor_index]
|
322
334
|
cursor_index += 1
|
323
335
|
selected_index = cursor_index
|
@@ -326,34 +338,34 @@ module GitGameShow
|
|
326
338
|
cursor_index += 1
|
327
339
|
end
|
328
340
|
end
|
329
|
-
|
341
|
+
|
330
342
|
# Redraw just the list portion of the screen
|
331
343
|
draw_ordering_list(current_order, cursor_index, selected_index, content_start_line, num_options)
|
332
344
|
end
|
333
345
|
end
|
334
|
-
|
346
|
+
|
335
347
|
# Helper method to draw just the list portion of the ordering UI
|
336
348
|
def draw_ordering_list(items, cursor_index, selected_index, start_line, num_options)
|
337
349
|
# Clear the line above the list (was used for debugging)
|
338
350
|
debug_line = start_line - 1
|
339
351
|
move_cursor_to(debug_line, 0)
|
340
352
|
print "\r\033[K" # Clear debug line
|
341
|
-
|
353
|
+
|
342
354
|
# Move cursor to the start position for the list
|
343
355
|
move_cursor_to(start_line, 0)
|
344
|
-
|
356
|
+
|
345
357
|
# Clear all lines that will contain list items and the submit button
|
346
358
|
(num_options + 2).times do |i|
|
347
359
|
move_cursor_to(start_line + i, 0)
|
348
360
|
print "\r\033[K" # Clear current line without moving cursor
|
349
361
|
end
|
350
|
-
|
362
|
+
|
351
363
|
# Draw each item with appropriate highlighting
|
352
364
|
items.each_with_index do |item, idx|
|
353
365
|
# Calculate the line for this item
|
354
366
|
item_line = start_line + idx
|
355
367
|
move_cursor_to(item_line, 0)
|
356
|
-
|
368
|
+
|
357
369
|
if selected_index == idx
|
358
370
|
# Selected item (being moved)
|
359
371
|
print " → #{idx + 1}. #{item}".colorize(:light_green)
|
@@ -365,7 +377,7 @@ module GitGameShow
|
|
365
377
|
print " #{idx + 1}. #{item}".colorize(:white)
|
366
378
|
end
|
367
379
|
end
|
368
|
-
|
380
|
+
|
369
381
|
# Add the Submit option at the bottom
|
370
382
|
move_cursor_to(start_line + num_options, 0)
|
371
383
|
if cursor_index == num_options
|
@@ -373,27 +385,27 @@ module GitGameShow
|
|
373
385
|
else
|
374
386
|
print " Submit Answer".colorize(:white)
|
375
387
|
end
|
376
|
-
|
388
|
+
|
377
389
|
# Move cursor after the list
|
378
390
|
move_cursor_to(start_line + num_options + 1, 0)
|
379
|
-
|
391
|
+
|
380
392
|
# Ensure output is visible
|
381
393
|
STDOUT.flush
|
382
394
|
end
|
383
|
-
|
395
|
+
|
384
396
|
# Helper to position cursor at a specific row/column
|
385
397
|
def move_cursor_to(row, col)
|
386
398
|
print "\033[#{row};#{col}H"
|
387
399
|
end
|
388
|
-
|
400
|
+
|
389
401
|
# Simplified key input reader that uses numbers for arrow keys
|
390
402
|
def read_char
|
391
403
|
begin
|
392
404
|
system("stty raw -echo")
|
393
|
-
|
405
|
+
|
394
406
|
# Read a character
|
395
407
|
c = STDIN.getc
|
396
|
-
|
408
|
+
|
397
409
|
# Special handling for escape sequences
|
398
410
|
if c == "\e"
|
399
411
|
# Could be an arrow key - read more
|
@@ -423,14 +435,14 @@ module GitGameShow
|
|
423
435
|
return 27 # ESC key
|
424
436
|
end
|
425
437
|
end
|
426
|
-
|
438
|
+
|
427
439
|
# Just return the ASCII value for the key
|
428
440
|
return c.ord
|
429
441
|
ensure
|
430
442
|
system("stty -raw echo")
|
431
443
|
end
|
432
444
|
end
|
433
|
-
|
445
|
+
|
434
446
|
# Non-blocking key input reader that supports timeouts
|
435
447
|
def read_char_with_timeout
|
436
448
|
begin
|
@@ -438,10 +450,10 @@ module GitGameShow
|
|
438
450
|
if IO.select([STDIN], [], [], 0.1)
|
439
451
|
# Read a character
|
440
452
|
c = STDIN.getc
|
441
|
-
|
453
|
+
|
442
454
|
# Handle nil case (EOF)
|
443
455
|
return nil if c.nil?
|
444
|
-
|
456
|
+
|
445
457
|
# Special handling for escape sequences
|
446
458
|
if c == "\e"
|
447
459
|
# Could be an arrow key - read more
|
@@ -471,11 +483,11 @@ module GitGameShow
|
|
471
483
|
return 27 # ESC key
|
472
484
|
end
|
473
485
|
end
|
474
|
-
|
486
|
+
|
475
487
|
# Just return the ASCII value for the key
|
476
488
|
return c.ord
|
477
489
|
end
|
478
|
-
|
490
|
+
|
479
491
|
# No input available - return nil for timeout
|
480
492
|
return nil
|
481
493
|
rescue => e
|
@@ -483,17 +495,17 @@ module GitGameShow
|
|
483
495
|
return nil
|
484
496
|
end
|
485
497
|
end
|
486
|
-
|
498
|
+
|
487
499
|
# Helper method to display countdown using a status bar at the bottom of the screen
|
488
500
|
def update_countdown_display(seconds, original_seconds)
|
489
501
|
# Get terminal dimensions
|
490
502
|
term_height = `tput lines`.to_i rescue 24
|
491
|
-
|
503
|
+
|
492
504
|
# Calculate a simple progress bar
|
493
505
|
total_width = 30
|
494
506
|
progress_width = ((seconds.to_f / original_seconds) * total_width).to_i
|
495
507
|
remaining_width = total_width - progress_width
|
496
|
-
|
508
|
+
|
497
509
|
# Choose color based on time remaining
|
498
510
|
color = if seconds <= 5
|
499
511
|
:red
|
@@ -502,57 +514,57 @@ module GitGameShow
|
|
502
514
|
else
|
503
515
|
:green
|
504
516
|
end
|
505
|
-
|
517
|
+
|
506
518
|
# Create status bar with progress indicator
|
507
519
|
bar = "[#{"█" * progress_width}#{" " * remaining_width}]"
|
508
520
|
status_text = " ⏱️ Time remaining: #{seconds.to_s.rjust(2)} seconds ".colorize(color) + bar
|
509
|
-
|
521
|
+
|
510
522
|
# Save cursor position
|
511
523
|
print "\e7"
|
512
|
-
|
524
|
+
|
513
525
|
# Move to bottom of screen (status line)
|
514
526
|
print "\e[#{term_height};1H"
|
515
|
-
|
527
|
+
|
516
528
|
# Clear the line
|
517
529
|
print "\e[K"
|
518
|
-
|
530
|
+
|
519
531
|
# Print status bar at bottom of screen
|
520
532
|
print status_text
|
521
|
-
|
533
|
+
|
522
534
|
# Restore cursor position
|
523
535
|
print "\e8"
|
524
536
|
STDOUT.flush
|
525
537
|
end
|
526
|
-
|
538
|
+
|
527
539
|
def handle_game_start(data)
|
528
540
|
@game_state = :playing
|
529
541
|
@players = data['players']
|
530
542
|
@total_rounds = data['rounds']
|
531
|
-
|
543
|
+
|
532
544
|
clear_screen
|
533
|
-
|
545
|
+
|
534
546
|
# Display a fun "Game Starting" animation
|
535
547
|
puts "\n\n"
|
536
548
|
puts " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".colorize(:green)
|
537
549
|
puts " ┃ GAME STARTING... ┃".colorize(:green)
|
538
550
|
puts " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".colorize(:green)
|
539
551
|
puts "\n\n"
|
540
|
-
|
552
|
+
|
541
553
|
puts " Total rounds: #{@total_rounds}".colorize(:cyan)
|
542
554
|
puts " Players: #{@players.join(', ')}".colorize(:cyan)
|
543
555
|
puts "\n\n"
|
544
556
|
puts " Get ready for the first round!".colorize(:yellow)
|
545
557
|
puts "\n\n"
|
546
558
|
end
|
547
|
-
|
559
|
+
|
548
560
|
def handle_player_update(data)
|
549
561
|
# Update the players list
|
550
562
|
@players = data['players']
|
551
|
-
|
563
|
+
|
552
564
|
if @game_state == :lobby
|
553
565
|
# If we're in the lobby, refresh the waiting room UI with updated player list
|
554
566
|
display_waiting_room
|
555
|
-
|
567
|
+
|
556
568
|
# Show notification at the bottom
|
557
569
|
if data['type'] == 'player_joined'
|
558
570
|
puts "\n 🟢 #{data['name']} has joined the game".colorize(:green)
|
@@ -562,51 +574,51 @@ module GitGameShow
|
|
562
574
|
else
|
563
575
|
# During gameplay, just show a notification without disrupting the game UI
|
564
576
|
terminal_width = `tput cols`.to_i rescue 80
|
565
|
-
|
577
|
+
|
566
578
|
# Create a notification box that won't interfere with ongoing gameplay
|
567
579
|
puts "\n┏#{"━" * (terminal_width - 2)}┓".colorize(:cyan)
|
568
|
-
|
580
|
+
|
569
581
|
if data['type'] == 'player_joined'
|
570
582
|
puts "┃#{" 🟢 #{data['name']} has joined the game ".center(terminal_width - 2)}┃".colorize(:green)
|
571
583
|
else
|
572
584
|
puts "┃#{" 🔴 #{data['name']} has left the game ".center(terminal_width - 2)}┃".colorize(:yellow)
|
573
585
|
end
|
574
|
-
|
586
|
+
|
575
587
|
# Don't show all players during gameplay - can be too disruptive
|
576
588
|
# Just show the total count
|
577
589
|
puts "┃#{" Total players: #{data['players'].size} ".center(terminal_width - 2)}┃".colorize(:cyan)
|
578
590
|
puts "┗#{"━" * (terminal_width - 2)}┛".colorize(:cyan)
|
579
591
|
end
|
580
592
|
end
|
581
|
-
|
593
|
+
|
582
594
|
def handle_round_start(data)
|
583
595
|
clear_screen
|
584
|
-
|
596
|
+
|
585
597
|
# Draw a fancy round header
|
586
598
|
round_num = data['round']
|
587
599
|
total_rounds = data['total_rounds']
|
588
600
|
mini_game = data['mini_game']
|
589
601
|
description = data['description']
|
590
|
-
|
602
|
+
|
591
603
|
puts "\n\n"
|
592
|
-
|
604
|
+
|
593
605
|
# Box is drawn with exactly 45 "━" characters for the top and bottom borders
|
594
606
|
# The top and bottom including borders are 48 characters wide
|
595
607
|
box_top = " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
596
608
|
box_bottom = " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
597
|
-
|
609
|
+
|
598
610
|
# Get the text to center
|
599
611
|
round_text = "ROUND #{round_num} of #{total_rounds}"
|
600
|
-
|
612
|
+
|
601
613
|
# Find exact box width by measuring the top border
|
602
614
|
box_width = box_top.length # Should be 48 with Unicode characters
|
603
|
-
|
615
|
+
|
604
616
|
# The inner width is the box width minus the borders
|
605
617
|
inner_width = box_width - (" ┃".length + "┃".length)
|
606
|
-
|
618
|
+
|
607
619
|
# Simply use Ruby's built-in center method for reliable centering
|
608
620
|
box_middle = " ┃" + round_text.center(inner_width) + "┃"
|
609
|
-
|
621
|
+
|
610
622
|
# Output the box
|
611
623
|
puts box_top.colorize(:green)
|
612
624
|
puts box_middle.colorize(:green)
|
@@ -615,7 +627,7 @@ module GitGameShow
|
|
615
627
|
puts " Mini-game: #{mini_game}".colorize(:cyan)
|
616
628
|
puts " #{description}".colorize(:light_blue)
|
617
629
|
puts "\n"
|
618
|
-
|
630
|
+
|
619
631
|
# Count down to the start - don't sleep here as we're waiting for the server
|
620
632
|
# to send us the questions after a fixed delay
|
621
633
|
puts " Get ready for the first question...".colorize(:yellow)
|
@@ -623,99 +635,99 @@ module GitGameShow
|
|
623
635
|
puts " The host is controlling the timing of all questions.".colorize(:light_blue)
|
624
636
|
puts "\n\n"
|
625
637
|
end
|
626
|
-
|
638
|
+
|
627
639
|
def handle_question(data)
|
628
640
|
# Invalidate any previous timer
|
629
641
|
@current_timer_id = SecureRandom.uuid
|
630
|
-
|
642
|
+
|
631
643
|
# Clear the screen completely
|
632
644
|
clear_screen
|
633
|
-
|
645
|
+
|
634
646
|
question_num = data['question_number']
|
635
647
|
total_questions = data['total_questions']
|
636
648
|
question = data['question']
|
637
649
|
timeout = data['timeout']
|
638
|
-
|
650
|
+
|
639
651
|
# Store question data in thread-local storage for access in other methods
|
640
652
|
Thread.current[:question_data] = data
|
641
|
-
|
653
|
+
|
642
654
|
# No need to reserve space for timer - it will be at the bottom of the screen
|
643
|
-
|
655
|
+
|
644
656
|
# Display question header
|
645
657
|
puts "\n"
|
646
|
-
|
658
|
+
|
647
659
|
# Draw a simple box for the question header
|
648
660
|
box_top = " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
649
661
|
box_bottom = " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
650
662
|
question_text = "QUESTION #{question_num} of #{total_questions}"
|
651
663
|
inner_width = box_top.length - (" ┃".length + "┃".length)
|
652
664
|
box_middle = " ┃" + question_text.center(inner_width) + "┃"
|
653
|
-
|
665
|
+
|
654
666
|
# Output the question box
|
655
667
|
puts box_top.colorize(:cyan)
|
656
668
|
puts box_middle.colorize(:cyan)
|
657
669
|
puts box_bottom.colorize(:cyan)
|
658
670
|
puts "\n"
|
659
|
-
|
671
|
+
|
660
672
|
# Display question
|
661
673
|
puts " #{question}".colorize(:light_blue)
|
662
|
-
|
674
|
+
|
663
675
|
# Display commit info if available
|
664
676
|
if data['commit_info']
|
665
677
|
puts "\n Commit: #{data['commit_info']}".colorize(:yellow)
|
666
678
|
end
|
667
679
|
puts "\n"
|
668
|
-
|
680
|
+
|
669
681
|
# Create a unique timer ID for this question
|
670
682
|
timer_id = SecureRandom.uuid
|
671
683
|
@current_timer_id = timer_id
|
672
684
|
start_time = Time.now
|
673
685
|
end_time = start_time + timeout
|
674
|
-
|
686
|
+
|
675
687
|
# Static deadline info
|
676
688
|
puts " Deadline: #{end_time.strftime('%I:%M:%S %p')}".colorize(:light_blue)
|
677
689
|
puts "\n"
|
678
|
-
|
690
|
+
|
679
691
|
# Initialize remaining time for scoring
|
680
692
|
@time_remaining = timeout
|
681
|
-
|
693
|
+
|
682
694
|
# Update the timer display immediately
|
683
695
|
update_countdown_display(timeout, timeout)
|
684
|
-
|
696
|
+
|
685
697
|
# Variable to track if the timer has expired
|
686
698
|
@timer_expired = false
|
687
|
-
|
699
|
+
|
688
700
|
# Start countdown in a background thread with new approach
|
689
701
|
countdown_thread = Thread.new do
|
690
702
|
begin
|
691
703
|
remaining = timeout
|
692
|
-
|
704
|
+
|
693
705
|
while remaining > 0 && @current_timer_id == timer_id
|
694
706
|
# Update both window title and fixed position display
|
695
707
|
update_title_timer(remaining)
|
696
708
|
update_countdown_display(remaining, timeout)
|
697
|
-
|
709
|
+
|
698
710
|
# Sound alert when time is almost up (< 5 seconds)
|
699
711
|
if remaining < 5 && remaining > 0
|
700
712
|
print "\a" if remaining % 2 == 0 # Beep on even seconds
|
701
713
|
end
|
702
|
-
|
714
|
+
|
703
715
|
# Store time for scoring
|
704
716
|
@time_remaining = remaining
|
705
|
-
|
717
|
+
|
706
718
|
# Wait one second
|
707
719
|
sleep 1
|
708
720
|
remaining -= 1
|
709
721
|
end
|
710
|
-
|
722
|
+
|
711
723
|
# Final update when timer reaches zero
|
712
724
|
if @current_timer_id == timer_id
|
713
725
|
update_countdown_display(0, timeout)
|
714
|
-
|
726
|
+
|
715
727
|
# IMPORTANT: Send a timeout answer when time expires
|
716
728
|
# without waiting for user input
|
717
729
|
@timer_expired = true
|
718
|
-
|
730
|
+
|
719
731
|
# Clear the screen to break out of any prompt/UI state
|
720
732
|
clear_screen
|
721
733
|
|
@@ -742,7 +754,7 @@ module GitGameShow
|
|
742
754
|
# Silent failure for robustness
|
743
755
|
end
|
744
756
|
end
|
745
|
-
|
757
|
+
|
746
758
|
# Handle different question types - but wrap in a separate thread
|
747
759
|
# so that timeouts can interrupt the UI
|
748
760
|
input_thread = Thread.new do
|
@@ -775,7 +787,7 @@ module GitGameShow
|
|
775
787
|
end
|
776
788
|
end
|
777
789
|
end
|
778
|
-
|
790
|
+
|
779
791
|
# Wait for input but with timeout
|
780
792
|
answer = nil
|
781
793
|
begin
|
@@ -787,7 +799,7 @@ module GitGameShow
|
|
787
799
|
# If timeout occurs during join, kill the thread
|
788
800
|
input_thread.kill if input_thread.alive?
|
789
801
|
end
|
790
|
-
|
802
|
+
|
791
803
|
# Only send user answer if timer hasn't expired
|
792
804
|
unless @timer_expired
|
793
805
|
# Send answer back to server
|
@@ -797,47 +809,47 @@ module GitGameShow
|
|
797
809
|
answer: answer,
|
798
810
|
question_id: data['question_id']
|
799
811
|
})
|
800
|
-
|
812
|
+
|
801
813
|
puts "\n Answer submitted! Waiting for feedback...".colorize(:green)
|
802
814
|
end
|
803
|
-
|
815
|
+
|
804
816
|
# Stop the timer by invalidating its ID and terminating the thread
|
805
817
|
@current_timer_id = SecureRandom.uuid # Change timer ID to signal thread to stop
|
806
818
|
countdown_thread.kill if countdown_thread.alive? # Force kill the thread
|
807
|
-
|
819
|
+
|
808
820
|
# Reset window title
|
809
821
|
print "\033]0;Git Game Show\007"
|
810
|
-
|
822
|
+
|
811
823
|
# Clear the timer status line at bottom
|
812
824
|
term_height = `tput lines`.to_i rescue 24
|
813
825
|
print "\e7" # Save cursor position
|
814
826
|
print "\e[#{term_height};1H" # Move to bottom line
|
815
827
|
print "\e[K" # Clear line
|
816
828
|
print "\e8" # Restore cursor position
|
817
|
-
|
829
|
+
|
818
830
|
# The server will send ANSWER_FEEDBACK message right away, then we'll see feedback
|
819
831
|
end
|
820
|
-
|
832
|
+
|
821
833
|
# Handle immediate feedback after submitting an answer
|
822
834
|
def handle_answer_feedback(data)
|
823
835
|
# Invalidate any running timer and reset window title
|
824
836
|
@current_timer_id = SecureRandom.uuid
|
825
837
|
print "\033]0;Git Game Show\007" # Reset window title
|
826
|
-
|
838
|
+
|
827
839
|
# Clear the timer status line at bottom
|
828
840
|
term_height = `tput lines`.to_i rescue 24
|
829
841
|
print "\e7" # Save cursor position
|
830
842
|
print "\e[#{term_height};1H" # Move to bottom line
|
831
843
|
print "\e[K" # Clear line
|
832
844
|
print "\e8" # Restore cursor position
|
833
|
-
|
845
|
+
|
834
846
|
# Don't clear screen, just display the feedback under the question
|
835
847
|
# This keeps the context of the question while showing the result
|
836
|
-
|
848
|
+
|
837
849
|
# Add a visual separator
|
838
850
|
puts "\n #{"─" * 40}".colorize(:light_black)
|
839
851
|
puts "\n"
|
840
|
-
|
852
|
+
|
841
853
|
# Show immediate feedback
|
842
854
|
if data['answer'] == "TIMEOUT"
|
843
855
|
# Special handling for timeouts
|
@@ -848,7 +860,7 @@ module GitGameShow
|
|
848
860
|
# Correct answer
|
849
861
|
points_text = data['points'] > 0 ? " (+#{data['points']} points)" : ""
|
850
862
|
puts " ✅ CORRECT! Your answer was correct: #{data['answer']}#{points_text}".colorize(:green)
|
851
|
-
|
863
|
+
|
852
864
|
# Show bonus points details if applicable
|
853
865
|
if data['points'] > 10 # More than base points
|
854
866
|
bonus = data['points'] - 10
|
@@ -859,7 +871,7 @@ module GitGameShow
|
|
859
871
|
puts " ❌ INCORRECT! The correct answer was: #{data['correct_answer']}".colorize(:red)
|
860
872
|
puts " You answered: #{data['answer']} (0 points)".colorize(:yellow)
|
861
873
|
end
|
862
|
-
|
874
|
+
|
863
875
|
puts "\n Waiting for the round to complete. Please wait for the next question...".colorize(:light_blue)
|
864
876
|
end
|
865
877
|
|
@@ -868,43 +880,43 @@ module GitGameShow
|
|
868
880
|
# Invalidate any running timer and reset window title
|
869
881
|
@current_timer_id = SecureRandom.uuid
|
870
882
|
print "\033]0;Git Game Show - Round Results\007" # Reset window title with context
|
871
|
-
|
883
|
+
|
872
884
|
# Start with a clean screen
|
873
885
|
clear_screen
|
874
|
-
|
886
|
+
|
875
887
|
puts "\n"
|
876
|
-
|
888
|
+
|
877
889
|
# Box is drawn with exactly 45 "━" characters for the top and bottom borders
|
878
890
|
# The top and bottom including borders are 48 characters wide
|
879
891
|
box_top = " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"
|
880
892
|
box_bottom = " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
|
881
|
-
|
893
|
+
|
882
894
|
# Get the text to center
|
883
895
|
result_text = "ROUND RESULTS"
|
884
|
-
|
896
|
+
|
885
897
|
# Find exact box width by measuring the top border
|
886
898
|
box_width = box_top.length # Should be 48 with Unicode characters
|
887
|
-
|
899
|
+
|
888
900
|
# The inner width is the box width minus 2 characters for the borders
|
889
901
|
inner_width = box_width - (" ┃".length + "┃".length)
|
890
|
-
|
902
|
+
|
891
903
|
# Simply use Ruby's built-in center method for reliable centering
|
892
904
|
box_middle = " ┃" + result_text.center(inner_width) + "┃"
|
893
|
-
|
905
|
+
|
894
906
|
# Output the box
|
895
907
|
puts box_top.colorize(:cyan)
|
896
908
|
puts box_middle.colorize(:cyan)
|
897
909
|
puts box_bottom.colorize(:cyan)
|
898
910
|
puts "\n"
|
899
|
-
|
911
|
+
|
900
912
|
# Show question again
|
901
913
|
puts " Question: #{data['question'][:question]}".colorize(:light_blue)
|
902
914
|
puts " Correct answer: #{data['correct_answer']}".colorize(:green)
|
903
|
-
|
915
|
+
|
904
916
|
puts "\n All player results:".colorize(:cyan)
|
905
|
-
|
917
|
+
|
906
918
|
# Debug data temporarily removed
|
907
|
-
|
919
|
+
|
908
920
|
# Handle results based on structure
|
909
921
|
if data['results'].is_a?(Hash)
|
910
922
|
data['results'].each do |player, result|
|
@@ -914,11 +926,11 @@ module GitGameShow
|
|
914
926
|
correct = result[:correct] || result['correct'] || false
|
915
927
|
answer = result[:answer] || result['answer'] || "No answer"
|
916
928
|
points = result[:points] || result['points'] || 0
|
917
|
-
|
929
|
+
|
918
930
|
status = correct ? "✓" : "✗"
|
919
931
|
points_str = "(+#{points} points)"
|
920
932
|
player_str = player == name ? "#{player} (You)" : player
|
921
|
-
|
933
|
+
|
922
934
|
player_output = " #{player_str.ljust(20)} #{points_str.ljust(15)} #{answer} #{status}"
|
923
935
|
if correct
|
924
936
|
puts player_output.colorize(:green)
|
@@ -934,14 +946,14 @@ module GitGameShow
|
|
934
946
|
# Fallback message if results isn't a hash
|
935
947
|
puts " No detailed results available".colorize(:yellow)
|
936
948
|
end
|
937
|
-
|
949
|
+
|
938
950
|
# Display current scoreboard
|
939
951
|
if data['scores']
|
940
952
|
puts "\n Current Standings:".colorize(:yellow)
|
941
953
|
data['scores'].each_with_index do |(player, score), index|
|
942
954
|
player_str = player == name ? "#{player} (You)" : player
|
943
955
|
rank = index + 1
|
944
|
-
|
956
|
+
|
945
957
|
# Add medal emoji for top 3
|
946
958
|
rank_display = case rank
|
947
959
|
when 1 then "🥇"
|
@@ -949,50 +961,50 @@ module GitGameShow
|
|
949
961
|
when 3 then "🥉"
|
950
962
|
else "#{rank}."
|
951
963
|
end
|
952
|
-
|
964
|
+
|
953
965
|
output = " #{rank_display} #{player_str.ljust(20)} #{score} points"
|
954
|
-
|
966
|
+
|
955
967
|
if player == name
|
956
|
-
puts output.colorize(:light_yellow)
|
968
|
+
puts output.colorize(:light_yellow)
|
957
969
|
else
|
958
970
|
puts output.colorize(:light_blue)
|
959
971
|
end
|
960
972
|
end
|
961
973
|
end
|
962
|
-
|
974
|
+
|
963
975
|
puts "\n Next question coming up automatically...".colorize(:yellow)
|
964
976
|
end
|
965
|
-
|
977
|
+
|
966
978
|
def handle_scoreboard(data)
|
967
979
|
# Invalidate any running timer and reset window title
|
968
980
|
@current_timer_id = SecureRandom.uuid
|
969
981
|
print "\033]0;Git Game Show - Scoreboard\007" # Reset window title with context
|
970
|
-
|
982
|
+
|
971
983
|
# Always start with a clean screen for the scoreboard
|
972
984
|
clear_screen
|
973
|
-
|
985
|
+
|
974
986
|
puts "\n"
|
975
987
|
puts " ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".colorize(:yellow)
|
976
988
|
puts " ┃ SCOREBOARD ┃".colorize(:yellow)
|
977
989
|
puts " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".colorize(:yellow)
|
978
990
|
puts "\n"
|
979
|
-
|
991
|
+
|
980
992
|
# Get player positions
|
981
993
|
position = 1
|
982
994
|
last_score = nil
|
983
|
-
|
995
|
+
|
984
996
|
data['scores'].each do |player, score|
|
985
997
|
# Determine position (handle ties)
|
986
998
|
position = data['scores'].values.index(score) + 1 if last_score != score
|
987
999
|
last_score = score
|
988
|
-
|
1000
|
+
|
989
1001
|
# Highlight current player
|
990
1002
|
player_str = player == name ? "#{player} (You)" : player
|
991
|
-
|
1003
|
+
|
992
1004
|
# Format with position
|
993
1005
|
position_str = "#{position}."
|
994
1006
|
score_str = "#{score} points"
|
995
|
-
|
1007
|
+
|
996
1008
|
# Add emoji for top 3
|
997
1009
|
case position
|
998
1010
|
when 1
|
@@ -1008,28 +1020,28 @@ module GitGameShow
|
|
1008
1020
|
puts " #{position_str.ljust(5)} #{player_str.ljust(25)} #{score_str}"
|
1009
1021
|
end
|
1010
1022
|
end
|
1011
|
-
|
1023
|
+
|
1012
1024
|
puts "\n Next round coming up soon...".colorize(:cyan)
|
1013
1025
|
end
|
1014
|
-
|
1026
|
+
|
1015
1027
|
def handle_game_end(data)
|
1016
1028
|
# Invalidate any running timer and reset window title
|
1017
1029
|
@current_timer_id = SecureRandom.uuid
|
1018
1030
|
print "\033]0;Git Game Show - Game Over\007" # Reset window title with context
|
1019
|
-
|
1031
|
+
|
1020
1032
|
# Clear any timer status line at the bottom
|
1021
1033
|
term_height = `tput lines`.to_i rescue 24
|
1022
1034
|
print "\e7" # Save cursor position
|
1023
1035
|
print "\e[#{term_height};1H" # Move to bottom line
|
1024
1036
|
print "\e[K" # Clear line
|
1025
1037
|
print "\e8" # Restore cursor position
|
1026
|
-
|
1038
|
+
|
1027
1039
|
# Completely clear the screen
|
1028
1040
|
clear_screen
|
1029
1041
|
@game_state = :ended
|
1030
|
-
|
1042
|
+
|
1031
1043
|
winner = data['winner']
|
1032
|
-
|
1044
|
+
|
1033
1045
|
# ASCII trophy art
|
1034
1046
|
trophy = <<-TROPHY
|
1035
1047
|
___________
|
@@ -1042,7 +1054,7 @@ module GitGameShow
|
|
1042
1054
|
) (
|
1043
1055
|
_.' '._
|
1044
1056
|
TROPHY
|
1045
|
-
|
1057
|
+
|
1046
1058
|
puts "\n\n"
|
1047
1059
|
puts trophy.colorize(:yellow)
|
1048
1060
|
puts "\n"
|
@@ -1050,32 +1062,32 @@ module GitGameShow
|
|
1050
1062
|
puts " ┃ GAME OVER ┃".colorize(:green)
|
1051
1063
|
puts " ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".colorize(:green)
|
1052
1064
|
puts "\n"
|
1053
|
-
|
1065
|
+
|
1054
1066
|
winner_is_you = winner == name
|
1055
1067
|
if winner_is_you
|
1056
1068
|
puts " 🎉 Congratulations! You won! 🎉".colorize(:light_yellow)
|
1057
1069
|
else
|
1058
1070
|
puts " Winner: #{winner}! 🏆".colorize(:light_yellow)
|
1059
1071
|
end
|
1060
|
-
|
1072
|
+
|
1061
1073
|
puts "\n Final Scores:".colorize(:cyan)
|
1062
|
-
|
1074
|
+
|
1063
1075
|
# Get player positions
|
1064
1076
|
position = 1
|
1065
1077
|
last_score = nil
|
1066
|
-
|
1078
|
+
|
1067
1079
|
data['scores'].each do |player, score|
|
1068
1080
|
# Determine position (handle ties)
|
1069
1081
|
position = data['scores'].values.index(score) + 1 if last_score != score
|
1070
1082
|
last_score = score
|
1071
|
-
|
1083
|
+
|
1072
1084
|
# Highlight current player
|
1073
1085
|
player_str = player == name ? "#{player} (You)" : player
|
1074
|
-
|
1086
|
+
|
1075
1087
|
# Format with position
|
1076
1088
|
position_str = "#{position}."
|
1077
1089
|
score_str = "#{score} points"
|
1078
|
-
|
1090
|
+
|
1079
1091
|
# Add emoji for top 3
|
1080
1092
|
case position
|
1081
1093
|
when 1
|
@@ -1091,11 +1103,11 @@ module GitGameShow
|
|
1091
1103
|
puts " #{position_str.ljust(5)} #{player_str.ljust(25)} #{score_str}"
|
1092
1104
|
end
|
1093
1105
|
end
|
1094
|
-
|
1106
|
+
|
1095
1107
|
puts "\n\n Thanks for playing Git Game Show!".colorize(:green)
|
1096
1108
|
puts " Waiting for the host to start a new game...".colorize(:cyan)
|
1097
1109
|
puts " Press Ctrl+C to exit, or wait for the next game".colorize(:light_black)
|
1098
|
-
|
1110
|
+
|
1099
1111
|
# Keep client ready to receive a new game start or reset message
|
1100
1112
|
@game_over_timer = Thread.new do
|
1101
1113
|
begin
|
@@ -1109,31 +1121,31 @@ module GitGameShow
|
|
1109
1121
|
end
|
1110
1122
|
end
|
1111
1123
|
end
|
1112
|
-
|
1124
|
+
|
1113
1125
|
# Add a special method to handle game reset notifications
|
1114
1126
|
def handle_game_reset(data)
|
1115
1127
|
# Stop the game over timer if it's running
|
1116
1128
|
@game_over_timer&.kill if @game_over_timer&.alive?
|
1117
|
-
|
1129
|
+
|
1118
1130
|
# Reset game state
|
1119
1131
|
@game_state = :lobby
|
1120
|
-
|
1132
|
+
|
1121
1133
|
# Clear any lingering state
|
1122
1134
|
@players = @players || [] # Keep existing players list if we have one
|
1123
|
-
|
1135
|
+
|
1124
1136
|
# Show the waiting room again
|
1125
1137
|
clear_screen
|
1126
1138
|
display_waiting_room
|
1127
|
-
|
1139
|
+
|
1128
1140
|
# Show a prominent message that we're back in waiting room mode
|
1129
1141
|
puts "\n 🔄 The game has been reset by the host. Waiting for a new game to start...".colorize(:cyan)
|
1130
1142
|
puts " You can play again or press Ctrl+C to exit.".colorize(:cyan)
|
1131
1143
|
end
|
1132
|
-
|
1144
|
+
|
1133
1145
|
def handle_chat(data)
|
1134
1146
|
puts "[#{data['sender']}]: #{data['message']}".colorize(:light_blue)
|
1135
1147
|
end
|
1136
|
-
|
1148
|
+
|
1137
1149
|
def send_message(message)
|
1138
1150
|
begin
|
1139
1151
|
@ws.send(message.to_json)
|
@@ -1142,4 +1154,4 @@ module GitGameShow
|
|
1142
1154
|
end
|
1143
1155
|
end
|
1144
1156
|
end
|
1145
|
-
end
|
1157
|
+
end
|