git_game_show 0.1.3 → 0.1.5
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/lib/git_game_show/cli.rb +175 -123
- data/lib/git_game_show/game_server.rb +610 -233
- data/lib/git_game_show/player_client.rb +307 -292
- data/lib/git_game_show/updater.rb +17 -17
- data/lib/git_game_show/version.rb +1 -1
- data/lib/git_game_show.rb +4 -4
- data/mini_games/date_ordering_quiz.rb +78 -21
- metadata +2 -2
@@ -78,10 +78,16 @@ module GitGameShow
|
|
78
78
|
|
79
79
|
# Draw horizontal divider line between main area and command area
|
80
80
|
print @cursor.move_to(0, @command_line - 1)
|
81
|
-
print "
|
81
|
+
print "═" * (@terminal_width - @sidebar_width - 3) + "╧" + "═" * (@sidebar_width + 2)
|
82
82
|
|
83
83
|
# Draw vertical divider line between main area and sidebar
|
84
|
-
(0
|
84
|
+
print @cursor.move_to(@main_width, 0)
|
85
|
+
print "│"
|
86
|
+
print @cursor.move_to(@main_width, 1)
|
87
|
+
print "│"
|
88
|
+
print @cursor.move_to(@main_width, 2)
|
89
|
+
print "╞═"
|
90
|
+
(3...@command_line-1).each do |line|
|
85
91
|
print @cursor.move_to(@main_width, line)
|
86
92
|
print "│"
|
87
93
|
end
|
@@ -111,19 +117,19 @@ module GitGameShow
|
|
111
117
|
|
112
118
|
link_box_width = [@join_link.length + 6, @main_width - 10].min
|
113
119
|
start_x = (@main_width - link_box_width) / 2
|
114
|
-
start_y =
|
120
|
+
start_y = 8
|
115
121
|
|
116
122
|
print @cursor.move_to(start_x, start_y)
|
117
|
-
print "
|
123
|
+
print "╭" + "─" * (link_box_width - 2) + "╮"
|
118
124
|
|
119
125
|
print @cursor.move_to(start_x, start_y + 1)
|
120
|
-
print "│" + "
|
126
|
+
print "│" + " Join Link (Copied to Clipboard) ".center(link_box_width - 2).colorize(:green) + "│"
|
121
127
|
|
122
128
|
print @cursor.move_to(start_x, start_y + 2)
|
123
129
|
print "│" + @join_link.center(link_box_width - 2).colorize(:yellow) + "│"
|
124
130
|
|
125
131
|
print @cursor.move_to(start_x, start_y + 3)
|
126
|
-
print "
|
132
|
+
print "╰" + "─" * (link_box_width - 2) + "╯"
|
127
133
|
|
128
134
|
# Also log that the link was copied
|
129
135
|
log_message("Join link copied to clipboard", :green)
|
@@ -132,7 +138,7 @@ module GitGameShow
|
|
132
138
|
def draw_sidebar
|
133
139
|
# Draw sidebar header
|
134
140
|
print @cursor.move_to(@main_width + 2, 1)
|
135
|
-
print "
|
141
|
+
print "Players".colorize(:cyan)
|
136
142
|
|
137
143
|
print @cursor.move_to(@main_width + 2, 2)
|
138
144
|
print "═" * (@sidebar_width - 2)
|
@@ -250,7 +256,7 @@ module GitGameShow
|
|
250
256
|
end
|
251
257
|
|
252
258
|
def display_welcome_banner
|
253
|
-
|
259
|
+
banner = <<-BANNER.colorize(:green)
|
254
260
|
██████╗ ██╗████████╗ ██████╗ █████╗ ███╗ ███╗███████╗
|
255
261
|
██╔════╝ ██║╚══██╔══╝ ██╔════╝ ██╔══██╗████╗ ████║██╔════╝
|
256
262
|
██║ ███╗██║ ██║ ██║ ███╗███████║██╔████╔██║█████╗
|
@@ -258,7 +264,7 @@ module GitGameShow
|
|
258
264
|
╚██████╔╝██║ ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████╗
|
259
265
|
╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
|
260
266
|
BANNER
|
261
|
-
puts
|
267
|
+
banner.each{|line| puts line.center(80)}
|
262
268
|
end
|
263
269
|
|
264
270
|
private
|
@@ -410,22 +416,30 @@ module GitGameShow
|
|
410
416
|
log_message("#{truncated_name} timed out after #{time_taken.round(2)}s ⏰", :yellow)
|
411
417
|
else
|
412
418
|
# Regular answer processing
|
413
|
-
#
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
points =
|
419
|
-
|
420
|
-
#
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
419
|
+
# For ordering quizzes, we'll calculate points in evaluate_answers
|
420
|
+
# using the custom scoring systems in each mini-game
|
421
|
+
if current_question[:question_type] == 'ordering'
|
422
|
+
# Just store the answer and time, points will be calculated in evaluate_answers
|
423
|
+
correct = false # Will be properly set during evaluation
|
424
|
+
points = 0 # Will be properly set during evaluation
|
425
|
+
else
|
426
|
+
# For regular quizzes, calculate points immediately
|
427
|
+
correct = answer == current_question[:correct_answer]
|
428
|
+
points = 0
|
429
|
+
|
430
|
+
if correct
|
431
|
+
points = 10 # Base points for correct answer
|
432
|
+
|
433
|
+
# Bonus points for fast answers
|
434
|
+
if time_taken < 5
|
435
|
+
points += 5
|
436
|
+
elsif time_taken < 10
|
437
|
+
points += 3
|
438
|
+
end
|
425
439
|
end
|
426
440
|
end
|
427
441
|
|
428
|
-
# Store the answer
|
442
|
+
# Store the answer
|
429
443
|
@player_answers[player_name] = {
|
430
444
|
answer: answer,
|
431
445
|
time_taken: time_taken,
|
@@ -439,7 +453,11 @@ module GitGameShow
|
|
439
453
|
|
440
454
|
# Log this answer - ensure the name is not too long
|
441
455
|
truncated_name = player_name.length > 15 ? "#{player_name[0...12]}..." : player_name
|
442
|
-
|
456
|
+
if current_question[:question_type] == 'ordering'
|
457
|
+
log_message("#{truncated_name} submitted ordering in #{time_taken.round(2)}s ⏱️", :cyan)
|
458
|
+
else
|
459
|
+
log_message("#{truncated_name} answered in #{time_taken.round(2)}s: #{correct ? "Correct ✓" : "Wrong ✗"}", correct ? :green : :red)
|
460
|
+
end
|
443
461
|
end
|
444
462
|
|
445
463
|
# Check if all players have answered, regardless of timeout or manual answer
|
@@ -458,6 +476,14 @@ module GitGameShow
|
|
458
476
|
correct_answer: question[:correct_answer],
|
459
477
|
points: points # Include points in the feedback
|
460
478
|
}
|
479
|
+
|
480
|
+
# For ordering quizzes, we can't determine correctness immediately
|
481
|
+
# Instead we'll indicate that scoring will be calculated after timeout
|
482
|
+
if question[:question_type] == 'ordering'
|
483
|
+
feedback[:correct] = nil # nil means "scoring in progress"
|
484
|
+
feedback[:points] = nil
|
485
|
+
feedback[:message] = "Ordering submitted. Points will be calculated at the end of the round."
|
486
|
+
end
|
461
487
|
|
462
488
|
ws.send(feedback.to_json)
|
463
489
|
end
|
@@ -473,46 +499,156 @@ module GitGameShow
|
|
473
499
|
end
|
474
500
|
|
475
501
|
def evaluate_answers
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
# Just set a flag indicating that we've already evaluated this question
|
502
|
+
# Safety checks
|
503
|
+
return unless @current_mini_game
|
504
|
+
return unless @round_questions && @current_question_index < @round_questions.size
|
480
505
|
return if @question_already_evaluated
|
481
|
-
@question_already_evaluated = true
|
482
506
|
|
483
|
-
|
507
|
+
@question_already_evaluated = true
|
508
|
+
|
509
|
+
# Safety check - make sure we have a current question
|
510
|
+
begin
|
511
|
+
current_question = @round_questions[@current_question_index]
|
512
|
+
return unless current_question # Skip if no current question
|
513
|
+
rescue => e
|
514
|
+
log_message("Error accessing current question: #{e.message}", :red)
|
515
|
+
return
|
516
|
+
end
|
484
517
|
|
485
|
-
# Use our pre-calculated answers instead of running evaluation again
|
486
|
-
# This ensures consistency between immediate feedback and final results
|
487
518
|
results = {}
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
519
|
+
|
520
|
+
begin
|
521
|
+
# For ordering quizzes or other special types, use the mini-game's evaluation method
|
522
|
+
if current_question[:question_type] == 'ordering'
|
523
|
+
# Convert the player_answers to the format expected by the mini-game's evaluate_answers
|
524
|
+
mini_game_answers = {}
|
525
|
+
@player_answers.each do |player_name, answer_data|
|
526
|
+
next unless player_name && answer_data # Skip nil entries
|
527
|
+
|
528
|
+
mini_game_answers[player_name] = {
|
529
|
+
answer: answer_data[:answer],
|
530
|
+
time_taken: answer_data[:time_taken] || 20
|
531
|
+
}
|
532
|
+
end
|
533
|
+
|
534
|
+
# Call the mini-game's evaluate_answers method with error handling
|
535
|
+
begin
|
536
|
+
results = @current_mini_game.evaluate_answers(current_question, mini_game_answers) || {}
|
537
|
+
rescue => e
|
538
|
+
log_message("Error in mini-game evaluate_answers: #{e.message}", :red)
|
539
|
+
# Create fallback results
|
540
|
+
results = {}
|
541
|
+
@player_answers.each do |player_name, answer_data|
|
542
|
+
next unless player_name
|
543
|
+
|
544
|
+
results[player_name] = {
|
545
|
+
answer: answer_data[:answer] || [],
|
546
|
+
correct: false,
|
547
|
+
points: 0,
|
548
|
+
partial_score: "Error calculating score"
|
549
|
+
}
|
550
|
+
end
|
551
|
+
end
|
552
|
+
else
|
553
|
+
# For regular quizzes, use our pre-calculated points
|
554
|
+
results = {}
|
555
|
+
@player_answers.each do |player_name, answer_data|
|
556
|
+
next unless player_name && answer_data # Skip nil entries
|
557
|
+
|
558
|
+
results[player_name] = {
|
559
|
+
answer: answer_data[:answer] || "No answer",
|
560
|
+
correct: answer_data[:correct] || false,
|
561
|
+
points: answer_data[:points] || 0
|
562
|
+
}
|
563
|
+
end
|
564
|
+
end
|
495
565
|
|
496
|
-
|
497
|
-
|
498
|
-
|
566
|
+
# Verify that results have required fields
|
567
|
+
results.each do |player_name, result|
|
568
|
+
# Ensure each result has the required fields with fallback values
|
569
|
+
results[player_name][:answer] = result[:answer] || "No answer"
|
570
|
+
results[player_name][:correct] = !!result[:correct] # Convert to boolean
|
571
|
+
results[player_name][:points] = result[:points] || 0
|
572
|
+
end
|
573
|
+
|
574
|
+
# Update scores
|
575
|
+
results.each do |player, result|
|
576
|
+
@scores[player] = (@scores[player] || 0) + (result[:points] || 0)
|
577
|
+
end
|
578
|
+
rescue => e
|
579
|
+
log_message("Error evaluating answers: #{e.message}", :red)
|
499
580
|
end
|
500
581
|
|
501
|
-
# Send results to all players
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
results
|
506
|
-
|
507
|
-
|
508
|
-
|
582
|
+
# Send results to all players - with error handling
|
583
|
+
begin
|
584
|
+
# Ensure we have valid data to broadcast
|
585
|
+
safe_results = {}
|
586
|
+
results.each do |player, result|
|
587
|
+
safe_results[player] = {
|
588
|
+
answer: result[:answer] || "No answer",
|
589
|
+
correct: !!result[:correct], # Convert to boolean
|
590
|
+
points: result[:points] || 0,
|
591
|
+
partial_score: result[:partial_score] || ""
|
592
|
+
}
|
593
|
+
end
|
594
|
+
|
595
|
+
# Sort scores safely
|
596
|
+
safe_scores = {}
|
597
|
+
begin
|
598
|
+
safe_scores = @scores.sort_by { |_, score| -(score || 0) }.to_h
|
599
|
+
rescue => e
|
600
|
+
log_message("Error sorting scores: #{e.message}", :red)
|
601
|
+
safe_scores = @scores.dup # Use unsorted if sorting fails
|
602
|
+
end
|
603
|
+
|
604
|
+
# For ordering questions, format the correct_answer as a list with numbers
|
605
|
+
formatted_correct_answer = current_question[:correct_answer] || []
|
606
|
+
if current_question[:question_type] == 'ordering'
|
607
|
+
formatted_correct_answer = current_question[:correct_answer].map.with_index do |item, idx|
|
608
|
+
"#{idx + 1}. #{item}" # Add numbers for easier reading
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
broadcast_message({
|
613
|
+
type: MessageType::ROUND_RESULT,
|
614
|
+
question: current_question,
|
615
|
+
results: safe_results,
|
616
|
+
correct_answer: formatted_correct_answer,
|
617
|
+
scores: safe_scores
|
618
|
+
})
|
619
|
+
rescue => e
|
620
|
+
log_message("Error broadcasting results: #{e.message}", :red)
|
621
|
+
end
|
509
622
|
|
510
|
-
# Log current scores for the host
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
623
|
+
# Log current scores for the host - with error handling
|
624
|
+
begin
|
625
|
+
log_message("Current scores:", :cyan)
|
626
|
+
|
627
|
+
# Safety check for scores
|
628
|
+
if @scores.nil? || @scores.empty?
|
629
|
+
log_message("No scores available", :yellow)
|
630
|
+
else
|
631
|
+
# Sort scores safely
|
632
|
+
begin
|
633
|
+
sorted_scores = @scores.sort_by { |_, score| -(score || 0) }
|
634
|
+
rescue => e
|
635
|
+
log_message("Error sorting scores for display: #{e.message}", :red)
|
636
|
+
sorted_scores = @scores.to_a
|
637
|
+
end
|
638
|
+
|
639
|
+
# Display each score with error handling
|
640
|
+
sorted_scores.each do |player_entry|
|
641
|
+
# Extract player and score safely
|
642
|
+
player = player_entry[0].to_s
|
643
|
+
score = player_entry[1] || 0
|
644
|
+
|
645
|
+
# Truncate player names if too long
|
646
|
+
truncated_name = player.length > 15 ? "#{player[0...12]}..." : player
|
647
|
+
log_message("#{truncated_name}: #{score} points", :light_blue)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
rescue => e
|
651
|
+
log_message("Error displaying scores: #{e.message}", :red)
|
516
652
|
end
|
517
653
|
|
518
654
|
# Move to next question or round
|
@@ -628,29 +764,71 @@ module GitGameShow
|
|
628
764
|
|
629
765
|
# Send question to all players
|
630
766
|
# Use mini-game specific timeout if available, otherwise use default
|
631
|
-
timeout
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
timeout
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
767
|
+
# Ensure timeout is a number
|
768
|
+
timeout = 0
|
769
|
+
begin
|
770
|
+
if @current_mini_game.class.respond_to?(:question_timeout)
|
771
|
+
timeout = @current_mini_game.class.question_timeout.to_i
|
772
|
+
else
|
773
|
+
timeout = (GitGameShow::DEFAULT_CONFIG[:question_timeout] || 20).to_i
|
774
|
+
end
|
775
|
+
# Make sure we have a positive timeout value
|
776
|
+
timeout = 20 if timeout <= 0
|
777
|
+
rescue => e
|
778
|
+
log_message("Error getting timeout value: #{e.message}", :red)
|
779
|
+
timeout = 20 # Default fallback
|
780
|
+
end
|
645
781
|
|
646
|
-
#
|
647
|
-
|
648
|
-
question_data
|
782
|
+
# Prepare question data with type safety
|
783
|
+
begin
|
784
|
+
question_data = {
|
785
|
+
type: MessageType::QUESTION,
|
786
|
+
question_id: @current_question_id.to_s,
|
787
|
+
question: current_question[:question].to_s,
|
788
|
+
options: current_question[:options] || [],
|
789
|
+
timeout: timeout, # Now guaranteed to be a number
|
790
|
+
round: @current_round.to_i,
|
791
|
+
question_number: (@current_question_index + 1).to_i,
|
792
|
+
total_questions: @round_questions.size.to_i
|
793
|
+
}
|
794
|
+
rescue => e
|
795
|
+
log_message("Error preparing question data: #{e.message}", :red)
|
796
|
+
# Create a minimal fallback question if something went wrong
|
797
|
+
question_data = {
|
798
|
+
type: MessageType::QUESTION,
|
799
|
+
question_id: "#{@current_round}-#{@current_question_index}",
|
800
|
+
question: "Question #{@current_question_index + 1}",
|
801
|
+
options: ["Option 1", "Option 2", "Option 3", "Option 4"],
|
802
|
+
timeout: 20,
|
803
|
+
round: @current_round.to_i,
|
804
|
+
question_number: (@current_question_index + 1).to_i,
|
805
|
+
total_questions: @round_questions.size.to_i
|
806
|
+
}
|
649
807
|
end
|
650
808
|
|
651
|
-
# Add
|
652
|
-
|
653
|
-
|
809
|
+
# Add additional question data safely
|
810
|
+
begin
|
811
|
+
# Add question_type if it's a special question type (like ordering)
|
812
|
+
if current_question && current_question[:question_type]
|
813
|
+
question_data[:question_type] = current_question[:question_type].to_s
|
814
|
+
end
|
815
|
+
|
816
|
+
# Add commit info if available (for AuthorQuiz)
|
817
|
+
if current_question && current_question[:commit_info]
|
818
|
+
# Make a safe copy to avoid potential issues with the original object
|
819
|
+
if current_question[:commit_info].is_a?(Hash)
|
820
|
+
safe_commit_info = {}
|
821
|
+
current_question[:commit_info].each do |key, value|
|
822
|
+
safe_commit_info[key.to_s] = value.to_s
|
823
|
+
end
|
824
|
+
question_data[:commit_info] = safe_commit_info
|
825
|
+
else
|
826
|
+
question_data[:commit_info] = current_question[:commit_info].to_s
|
827
|
+
end
|
828
|
+
end
|
829
|
+
rescue => e
|
830
|
+
log_message("Error adding additional question data: #{e.message}", :red)
|
831
|
+
# Continue without the additional data
|
654
832
|
end
|
655
833
|
|
656
834
|
# Don't log detailed question info to prevent author lists from showing
|
@@ -660,7 +838,7 @@ module GitGameShow
|
|
660
838
|
broadcast_message(question_data)
|
661
839
|
|
662
840
|
# Set a timer for question timeout - ALWAYS evaluate after timeout
|
663
|
-
# Use same timeout value we sent to clients
|
841
|
+
# Use same timeout value we sent to clients (already guaranteed to be a number)
|
664
842
|
EM.add_timer(timeout) do
|
665
843
|
log_message("Question timeout (#{timeout}s) - evaluating", :yellow)
|
666
844
|
evaluate_answers unless @current_question_index >= @round_questions.size
|
@@ -668,63 +846,132 @@ module GitGameShow
|
|
668
846
|
end
|
669
847
|
|
670
848
|
def broadcast_scoreboard
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
849
|
+
begin
|
850
|
+
# Create a safe copy of scores
|
851
|
+
safe_scores = {}
|
852
|
+
if @scores && !@scores.empty?
|
853
|
+
@scores.each do |player, score|
|
854
|
+
next unless player && player.to_s != ""
|
855
|
+
safe_scores[player.to_s] = score.to_i
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
# Sort scores safely
|
860
|
+
sorted_scores = {}
|
861
|
+
begin
|
862
|
+
sorted_scores = safe_scores.sort_by { |_, score| -(score || 0) }.to_h
|
863
|
+
rescue => e
|
864
|
+
log_message("Error sorting scores for scoreboard: #{e.message}", :red)
|
865
|
+
sorted_scores = safe_scores # Use unsorted if sorting fails
|
866
|
+
end
|
867
|
+
|
868
|
+
broadcast_message({
|
869
|
+
type: MessageType::SCOREBOARD,
|
870
|
+
scores: sorted_scores
|
871
|
+
})
|
872
|
+
rescue => e
|
873
|
+
log_message("Error broadcasting scoreboard: #{e.message}", :red)
|
874
|
+
end
|
675
875
|
end
|
676
876
|
|
677
877
|
def end_game
|
678
878
|
@game_state = :ended
|
679
879
|
|
680
|
-
#
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
@
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
880
|
+
# Initialize winner variable outside the begin block so it's visible throughout the method
|
881
|
+
winner = nil
|
882
|
+
|
883
|
+
# Wrap the main logic in a begin/rescue block
|
884
|
+
begin
|
885
|
+
# Safety check - make sure we have scores and they're not nil
|
886
|
+
if @scores.nil? || @scores.empty?
|
887
|
+
log_message("Game ended, but no scores were recorded.", :yellow)
|
888
|
+
|
889
|
+
# Reset game state for potential restart
|
890
|
+
@current_round = 0
|
891
|
+
@game_state = :lobby
|
892
|
+
@current_mini_game = nil
|
893
|
+
@round_questions = []
|
894
|
+
@current_question_index = 0
|
895
|
+
@question_already_evaluated = false
|
896
|
+
@player_answers = {}
|
897
|
+
@scores = {}
|
898
|
+
|
899
|
+
# Update UI
|
900
|
+
update_player_list
|
901
|
+
log_message("Ready for a new game! Type 'start' when players have joined.", :green)
|
902
|
+
return
|
903
|
+
end
|
692
904
|
|
693
|
-
#
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
905
|
+
# Create a safe copy of scores to work with
|
906
|
+
safe_scores = {}
|
907
|
+
@scores.each do |player, score|
|
908
|
+
next unless player && player != ""
|
909
|
+
safe_scores[player] = score || 0
|
910
|
+
end
|
911
|
+
|
912
|
+
# Determine the winner with safety checks
|
913
|
+
begin
|
914
|
+
winner = safe_scores.max_by { |_, score| score || 0 }
|
915
|
+
rescue => e
|
916
|
+
log_message("Error determining winner: #{e.message}", :red)
|
917
|
+
end
|
698
918
|
|
699
|
-
|
700
|
-
|
919
|
+
# Safety check - ensure winner isn't nil and has valid data
|
920
|
+
if winner.nil? || winner[0].nil? || winner[1].nil?
|
921
|
+
log_message("Error: Could not determine winner. No valid scores found.", :red)
|
922
|
+
|
923
|
+
# Create a synthetic winner as a fallback
|
924
|
+
if !safe_scores.empty?
|
925
|
+
# Take the first player as a last resort
|
926
|
+
player_name = safe_scores.keys.first.to_s
|
927
|
+
player_score = safe_scores.values.first || 0
|
928
|
+
winner = [player_name, player_score]
|
929
|
+
log_message("Using fallback winner: #{player_name}", :yellow)
|
930
|
+
else
|
931
|
+
# Reset and return early if we truly have no scores
|
932
|
+
@scores = {}
|
933
|
+
@current_round = 0
|
934
|
+
@game_state = :lobby
|
935
|
+
update_player_list
|
936
|
+
return
|
937
|
+
end
|
938
|
+
end
|
701
939
|
|
702
|
-
|
703
|
-
|
704
|
-
|
940
|
+
# Sort scores safely
|
941
|
+
sorted_scores = {}
|
942
|
+
begin
|
943
|
+
sorted_scores = safe_scores.sort_by { |_, score| -(score || 0) }.to_h
|
944
|
+
rescue => e
|
945
|
+
log_message("Error sorting scores: #{e.message}", :red)
|
946
|
+
sorted_scores = safe_scores # Use unsorted if sorting fails
|
947
|
+
end
|
705
948
|
|
706
|
-
#
|
949
|
+
# Notify all players
|
950
|
+
begin
|
951
|
+
broadcast_message({
|
952
|
+
type: MessageType::GAME_END,
|
953
|
+
winner: winner[0].to_s,
|
954
|
+
scores: sorted_scores
|
955
|
+
})
|
956
|
+
rescue => e
|
957
|
+
log_message("Error broadcasting final results: #{e.message}", :red)
|
958
|
+
end
|
959
|
+
rescue => e
|
960
|
+
# Catch-all for any unhandled exceptions
|
961
|
+
log_message("Critical error in end_game: #{e.message}", :red)
|
962
|
+
# Still try to reset game state
|
963
|
+
@game_state = :lobby
|
707
964
|
@scores = {}
|
708
965
|
@current_round = 0
|
709
|
-
@game_state = :lobby
|
710
|
-
update_player_list
|
711
|
-
return
|
712
966
|
end
|
713
967
|
|
714
|
-
#
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
scores: @scores.sort_by { |_, score| -score }.to_h
|
720
|
-
})
|
721
|
-
rescue => e
|
722
|
-
log_message("Error broadcasting final results: #{e.message}", :red)
|
968
|
+
# Display the final results on screen - with safety check
|
969
|
+
if winner && winner[0] && winner[1]
|
970
|
+
display_final_results(winner)
|
971
|
+
else
|
972
|
+
log_message("No valid winner data to display final results", :red)
|
723
973
|
end
|
724
974
|
|
725
|
-
# Display the final results on screen
|
726
|
-
display_final_results(winner)
|
727
|
-
|
728
975
|
# Reset game state for potential restart
|
729
976
|
@scores = {}
|
730
977
|
@current_round = 0
|
@@ -751,25 +998,47 @@ module GitGameShow
|
|
751
998
|
|
752
999
|
def display_final_results(winner)
|
753
1000
|
begin
|
1001
|
+
# Safety check - make sure we have a main_width value
|
1002
|
+
main_width = @main_width || 80
|
1003
|
+
|
754
1004
|
# Use log messages instead of clearing screen
|
755
|
-
divider = "=" * (
|
1005
|
+
divider = "=" * (main_width - 5)
|
756
1006
|
log_message(divider, :yellow)
|
757
1007
|
log_message("🏆 GAME OVER - FINAL SCORES 🏆", :yellow)
|
758
1008
|
|
759
|
-
# Safety check for winner
|
1009
|
+
# Safety check for winner - we already checked in end_game but double-check here
|
760
1010
|
if !winner || !winner[0] || !winner[1]
|
761
1011
|
log_message("Error: Invalid winner data", :red)
|
762
1012
|
log_message("Ready for a new game! Type 'start' when players have joined.", :green)
|
763
1013
|
return
|
764
1014
|
end
|
765
1015
|
|
766
|
-
# Announce winner
|
767
|
-
|
768
|
-
|
769
|
-
|
1016
|
+
# Announce winner with defensive processing
|
1017
|
+
begin
|
1018
|
+
winner_name = winner[0].to_s
|
1019
|
+
winner_name = winner_name.length > 20 ? "#{winner_name[0...17]}..." : winner_name
|
1020
|
+
winner_score = winner[1].to_i
|
1021
|
+
log_message("Winner: #{winner_name} with #{winner_score} points!", :green)
|
1022
|
+
rescue => e
|
1023
|
+
log_message("Error displaying winner: #{e.message}", :red)
|
1024
|
+
log_message("A winner was determined but couldn't be displayed", :yellow)
|
1025
|
+
end
|
770
1026
|
|
1027
|
+
# Create a safe copy of scores to work with
|
1028
|
+
safe_scores = {}
|
1029
|
+
begin
|
1030
|
+
if @scores && !@scores.empty?
|
1031
|
+
@scores.each do |player, score|
|
1032
|
+
next unless player && player.to_s != ""
|
1033
|
+
safe_scores[player.to_s] = score.to_i
|
1034
|
+
end
|
1035
|
+
end
|
1036
|
+
rescue => e
|
1037
|
+
log_message("Error copying scores: #{e.message}", :red)
|
1038
|
+
end
|
1039
|
+
|
771
1040
|
# Safety check for scores
|
772
|
-
if
|
1041
|
+
if safe_scores.empty?
|
773
1042
|
log_message("No scores available to display", :yellow)
|
774
1043
|
log_message(divider, :yellow)
|
775
1044
|
log_message("Ready for a new game! Type 'start' when players have joined.", :green)
|
@@ -782,65 +1051,91 @@ module GitGameShow
|
|
782
1051
|
leaderboard_entries = []
|
783
1052
|
|
784
1053
|
# Sort scores safely
|
1054
|
+
sorted_scores = []
|
785
1055
|
begin
|
786
|
-
sorted_scores =
|
1056
|
+
sorted_scores = safe_scores.sort_by { |_, score| -(score || 0) }.to_a
|
787
1057
|
rescue => e
|
788
|
-
log_message("Error sorting scores: #{e.message}", :red)
|
789
|
-
sorted_scores =
|
1058
|
+
log_message("Error sorting scores for display: #{e.message}", :red)
|
1059
|
+
sorted_scores = safe_scores.to_a
|
790
1060
|
end
|
791
1061
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
1062
|
+
max_to_show = 10
|
1063
|
+
|
1064
|
+
# Show limited entries in console with extra safety checks
|
1065
|
+
begin
|
1066
|
+
# Ensure we don't try to take more entries than exist
|
1067
|
+
entries_to_show = [sorted_scores.size, max_to_show].min
|
1068
|
+
|
1069
|
+
sorted_scores.take(entries_to_show).each_with_index do |score_entry, index|
|
1070
|
+
# Extra safety check for each entry
|
1071
|
+
next unless score_entry && score_entry.is_a?(Array) && score_entry.size >= 2
|
1072
|
+
|
1073
|
+
name = score_entry[0]
|
1074
|
+
score = score_entry[1]
|
1075
|
+
|
1076
|
+
# Safely handle name and score
|
1077
|
+
player_name = name.to_s
|
1078
|
+
player_score = score.to_i
|
1079
|
+
|
1080
|
+
# Truncate name if needed
|
1081
|
+
display_name = player_name.length > 15 ? "#{player_name[0...12]}..." : player_name
|
1082
|
+
|
1083
|
+
# Format based on position
|
1084
|
+
case index
|
1085
|
+
when 0
|
1086
|
+
log_message("🥇 #{display_name}: #{player_score} points", :yellow)
|
1087
|
+
when 1
|
1088
|
+
log_message("🥈 #{display_name}: #{player_score} points", :light_blue)
|
1089
|
+
when 2
|
1090
|
+
log_message("🥉 #{display_name}: #{player_score} points", :light_magenta)
|
1091
|
+
else
|
1092
|
+
log_message("#{(index + 1).to_s}. #{display_name}: #{player_score} points", :white)
|
1093
|
+
end
|
811
1094
|
end
|
1095
|
+
rescue => e
|
1096
|
+
log_message("Error displaying leaderboard entries: #{e.message}", :red)
|
812
1097
|
end
|
813
1098
|
|
814
1099
|
# If there are more players than shown, add a note
|
815
|
-
if sorted_scores.size >
|
816
|
-
log_message("... and #{sorted_scores.size -
|
1100
|
+
if sorted_scores.size > max_to_show
|
1101
|
+
log_message("... and #{sorted_scores.size - max_to_show} more (see full results in file)", :light_black)
|
817
1102
|
end
|
818
1103
|
|
819
|
-
# Build complete entries array for file
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
1104
|
+
# Build complete entries array for file with safety checks
|
1105
|
+
begin
|
1106
|
+
sorted_scores.each_with_index do |score_entry, index|
|
1107
|
+
# Skip invalid entries
|
1108
|
+
next unless score_entry && score_entry.is_a?(Array) && score_entry.size >= 2
|
1109
|
+
|
1110
|
+
# Use safe values
|
1111
|
+
player_name = score_entry[0].to_s
|
1112
|
+
player_score = score_entry[1].to_i
|
1113
|
+
|
1114
|
+
# Add medals for file format
|
1115
|
+
medal = case index
|
1116
|
+
when 0 then "🥇"
|
1117
|
+
when 1 then "🥈"
|
1118
|
+
when 2 then "🥉"
|
1119
|
+
else "#{index + 1}."
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
leaderboard_entries << "#{medal} #{player_name}: #{player_score} points"
|
1123
|
+
end
|
1124
|
+
rescue => e
|
1125
|
+
log_message("Error preparing leaderboard entries for file: #{e.message}", :red)
|
834
1126
|
end
|
835
1127
|
|
836
|
-
#
|
837
|
-
filename =
|
1128
|
+
# Only try to save file if we have entries
|
1129
|
+
filename = nil
|
1130
|
+
if !leaderboard_entries.empty? && winner
|
1131
|
+
filename = save_leaderboard_to_file(winner, leaderboard_entries)
|
1132
|
+
end
|
838
1133
|
|
839
1134
|
log_message(divider, :yellow)
|
840
1135
|
if filename
|
841
1136
|
log_message("Leaderboard saved to: #{filename}", :cyan)
|
842
1137
|
else
|
843
|
-
log_message("
|
1138
|
+
log_message("No leaderboard file generated", :yellow)
|
844
1139
|
end
|
845
1140
|
log_message("Ready for a new game! Type 'start' when players have joined.", :green)
|
846
1141
|
rescue => e
|
@@ -852,17 +1147,23 @@ module GitGameShow
|
|
852
1147
|
|
853
1148
|
def save_leaderboard_to_file(winner, leaderboard_entries)
|
854
1149
|
begin
|
855
|
-
# Validate parameters
|
856
|
-
if !winner || !
|
857
|
-
log_message("Error: Invalid data for leaderboard file", :red)
|
1150
|
+
# Validate parameters with thorough checks
|
1151
|
+
if !winner || !winner.is_a?(Array) || winner.size < 2 || winner[0].nil? || winner[1].nil?
|
1152
|
+
log_message("Error: Invalid winner data for leaderboard file", :red)
|
1153
|
+
return nil
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
if !leaderboard_entries || !leaderboard_entries.is_a?(Array) || leaderboard_entries.empty?
|
1157
|
+
log_message("Error: Invalid entries data for leaderboard file", :red)
|
858
1158
|
return nil
|
859
1159
|
end
|
860
1160
|
|
861
1161
|
# Create a unique filename with timestamp
|
862
|
-
timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
|
1162
|
+
timestamp = Time.now.strftime("%Y%m%d_%H%M%S") rescue "unknown_time"
|
863
1163
|
filename = "git_game_show_results_#{timestamp}.txt"
|
864
1164
|
|
865
1165
|
# Use a base path that should be writable
|
1166
|
+
file_path = nil
|
866
1167
|
begin
|
867
1168
|
# First try current directory
|
868
1169
|
file_path = File.join(Dir.pwd, filename)
|
@@ -873,56 +1174,88 @@ module GitGameShow
|
|
873
1174
|
file_path = File.join(Dir.home, filename)
|
874
1175
|
filename = File.join(Dir.home, filename) # Update filename to show full path
|
875
1176
|
end
|
876
|
-
rescue
|
1177
|
+
rescue => e
|
1178
|
+
log_message("Error with file path: #{e.message}", :red)
|
877
1179
|
# If all else fails, use /tmp (Unix) or %TEMP% (Windows)
|
878
|
-
|
879
|
-
|
880
|
-
|
1180
|
+
begin
|
1181
|
+
temp_dir = ENV['TEMP'] || ENV['TMP'] || '/tmp'
|
1182
|
+
file_path = File.join(temp_dir, filename)
|
1183
|
+
filename = file_path # Update filename to show full path
|
1184
|
+
rescue => e2
|
1185
|
+
log_message("Error setting up temp file path: #{e2.message}", :red)
|
1186
|
+
return nil
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
# Make sure we have a valid file path
|
1191
|
+
unless file_path && !file_path.empty?
|
1192
|
+
log_message("Could not determine a valid file path for leaderboard", :red)
|
1193
|
+
return nil
|
881
1194
|
end
|
882
1195
|
|
883
1196
|
# Get repo name from git directory path safely
|
1197
|
+
repo_name = "Unknown"
|
1198
|
+
begin
|
1199
|
+
if @repo && @repo.respond_to?(:dir) && @repo.dir && @repo.dir.respond_to?(:path)
|
1200
|
+
path = @repo.dir.path
|
1201
|
+
repo_name = path ? File.basename(path) : "Unknown"
|
1202
|
+
end
|
1203
|
+
rescue => e
|
1204
|
+
log_message("Error getting repo name: #{e.message}", :yellow)
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
# Get player count safely
|
1208
|
+
player_count = 0
|
884
1209
|
begin
|
885
|
-
|
886
|
-
rescue
|
887
|
-
|
1210
|
+
player_count = @players && @players.respond_to?(:keys) ? @players.keys.size : 0
|
1211
|
+
rescue => e
|
1212
|
+
log_message("Error getting player count: #{e.message}", :yellow)
|
888
1213
|
end
|
889
1214
|
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
1215
|
+
# Extract winner data safely
|
1216
|
+
winner_name = "Unknown"
|
1217
|
+
winner_score = 0
|
1218
|
+
begin
|
1219
|
+
winner_name = winner[0].to_s
|
1220
|
+
winner_score = winner[1].to_i
|
1221
|
+
rescue => e
|
1222
|
+
log_message("Error extracting winner data: #{e.message}", :yellow)
|
1223
|
+
end
|
898
1224
|
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
1225
|
+
# Write the file with error handling
|
1226
|
+
begin
|
1227
|
+
File.open(file_path, "w") do |file|
|
1228
|
+
# Write header
|
1229
|
+
file.puts "Git Game Show - Final Results"
|
1230
|
+
file.puts "═════════════════════════════"
|
1231
|
+
file.puts "Date: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
|
1232
|
+
file.puts "Repository: #{repo_name}"
|
1233
|
+
file.puts "Players: #{player_count}"
|
1234
|
+
file.puts ""
|
1235
|
+
|
1236
|
+
# Write winner
|
903
1237
|
file.puts "WINNER: #{winner_name} with #{winner_score} points!"
|
904
|
-
|
905
|
-
file.puts "WINNER: Unknown (error retrieving winner data)"
|
906
|
-
end
|
907
|
-
file.puts ""
|
1238
|
+
file.puts ""
|
908
1239
|
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
if leaderboard_entries.empty?
|
913
|
-
file.puts "No entries recorded"
|
914
|
-
else
|
1240
|
+
# Write full leaderboard
|
1241
|
+
file.puts "Full Leaderboard:"
|
1242
|
+
file.puts "─────────────────"
|
915
1243
|
leaderboard_entries.each do |entry|
|
916
1244
|
file.puts entry.to_s
|
1245
|
+
rescue => e
|
1246
|
+
file.puts "Error with entry: #{e.message}"
|
917
1247
|
end
|
1248
|
+
|
1249
|
+
# Write footer
|
1250
|
+
file.puts ""
|
1251
|
+
file.puts "Thanks for playing Git Game Show!"
|
918
1252
|
end
|
919
1253
|
|
920
|
-
|
921
|
-
|
922
|
-
|
1254
|
+
return filename
|
1255
|
+
rescue => e
|
1256
|
+
log_message("Error writing leaderboard file: #{e.message}", :red)
|
1257
|
+
return nil
|
923
1258
|
end
|
924
|
-
|
925
|
-
return filename
|
926
1259
|
rescue => e
|
927
1260
|
log_message("Error saving leaderboard: #{e.message}", :red)
|
928
1261
|
return nil
|
@@ -932,10 +1265,44 @@ module GitGameShow
|
|
932
1265
|
# Removed old full-screen methods as we now use log_message based approach
|
933
1266
|
|
934
1267
|
def broadcast_message(message, exclude: nil)
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
1268
|
+
return if message.nil?
|
1269
|
+
|
1270
|
+
begin
|
1271
|
+
# Convert message to JSON safely
|
1272
|
+
json_message = nil
|
1273
|
+
begin
|
1274
|
+
json_message = message.to_json
|
1275
|
+
rescue => e
|
1276
|
+
log_message("Error converting message to JSON: #{e.message}", :red)
|
1277
|
+
|
1278
|
+
# Try to simplify the message to make it JSON-compatible
|
1279
|
+
simplified_message = {
|
1280
|
+
type: message[:type] || "unknown",
|
1281
|
+
message: "Error processing full message"
|
1282
|
+
}
|
1283
|
+
json_message = simplified_message.to_json
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
return unless json_message
|
1287
|
+
|
1288
|
+
# Send to each player with error handling
|
1289
|
+
@players.each do |player_name, ws|
|
1290
|
+
# Skip excluded player if specified
|
1291
|
+
next if exclude && player_name == exclude
|
1292
|
+
|
1293
|
+
# Skip nil websockets
|
1294
|
+
next unless ws
|
1295
|
+
|
1296
|
+
# Send with error handling for each individual player
|
1297
|
+
begin
|
1298
|
+
ws.send(json_message)
|
1299
|
+
rescue => e
|
1300
|
+
log_message("Error sending to #{player_name}: #{e.message}", :yellow)
|
1301
|
+
# We don't remove the player here, as they might just have temporary connection issues
|
1302
|
+
end
|
1303
|
+
end
|
1304
|
+
rescue => e
|
1305
|
+
log_message("Fatal error in broadcast_message: #{e.message}", :red)
|
939
1306
|
end
|
940
1307
|
end
|
941
1308
|
|
@@ -1070,34 +1437,30 @@ module GitGameShow
|
|
1070
1437
|
if !@ui_drawn
|
1071
1438
|
system("clear") || system("cls")
|
1072
1439
|
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
██║ ██║██║ ██║ ██║ ██║██╔══██║██║╚██╔╝██║██╔══╝
|
1079
|
-
╚██████╔╝██║ ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████╗
|
1080
|
-
╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
|
1081
|
-
HEADER
|
1440
|
+
display_welcome_banner
|
1441
|
+
|
1442
|
+
puts "\n Server Started - Port: #{port}\n".colorize(:light_blue).center(80)
|
1443
|
+
|
1444
|
+
@ui_drawn = true
|
1082
1445
|
else
|
1083
1446
|
# Just print a separator for subsequent updates
|
1084
|
-
puts "\n\n" + ("
|
1085
|
-
puts "
|
1086
|
-
puts ("
|
1447
|
+
puts "\n\n" + ("═" * 60)
|
1448
|
+
puts "Git Game Show - Status Update".center(60).colorize(:green)
|
1449
|
+
puts ("═" * 60)
|
1087
1450
|
end
|
1088
1451
|
|
1089
1452
|
# Server info
|
1090
|
-
puts "\n
|
1453
|
+
puts "\n════════════════════ Server Info ════════════════════".colorize(:cyan)
|
1091
1454
|
puts "Status: #{game_state_text}".colorize(game_state_color)
|
1092
1455
|
puts "Rounds: #{@current_round}/#{rounds}".colorize(:light_blue)
|
1093
1456
|
puts "Repository: #{repo.dir.path}".colorize(:light_blue)
|
1094
1457
|
|
1095
1458
|
# Display join link prominently
|
1096
|
-
puts "\n
|
1459
|
+
puts "\n════════════════════ Join Link ═════════════════════".colorize(:green)
|
1097
1460
|
puts @join_link.to_s.colorize(:yellow)
|
1098
1461
|
|
1099
1462
|
# Player list
|
1100
|
-
puts "\n
|
1463
|
+
puts "\n════════════════════ Players ═══════════════════════".colorize(:cyan)
|
1101
1464
|
if @players.empty?
|
1102
1465
|
puts "No players have joined yet".colorize(:yellow)
|
1103
1466
|
else
|
@@ -1113,13 +1476,13 @@ module GitGameShow
|
|
1113
1476
|
puts "Players can join using the link above.".colorize(:yellow)
|
1114
1477
|
puts "Type 'players' to see the current list of players.".colorize(:yellow)
|
1115
1478
|
when :playing
|
1116
|
-
puts "\n
|
1479
|
+
puts "\n════════════════════ Game Info ═══════════════════════".colorize(:cyan)
|
1117
1480
|
puts "Current round: #{@current_round}/#{rounds}".colorize(:light_blue)
|
1118
1481
|
puts "Current mini-game: #{@current_mini_game&.class&.name || 'N/A'}".colorize(:light_blue)
|
1119
1482
|
puts "Question: #{@current_question_index + 1}/#{@round_questions.size}".colorize(:light_blue) if @round_questions&.any?
|
1120
1483
|
|
1121
1484
|
# Show scoreboard
|
1122
|
-
puts "\n
|
1485
|
+
puts "\n═══════════════════ Scoreboard ══════════════════════".colorize(:cyan)
|
1123
1486
|
if @scores.empty?
|
1124
1487
|
puts "No scores yet".colorize(:yellow)
|
1125
1488
|
else
|
@@ -1149,7 +1512,8 @@ module GitGameShow
|
|
1149
1512
|
end
|
1150
1513
|
|
1151
1514
|
def print_help_message
|
1152
|
-
puts "
|
1515
|
+
puts ""
|
1516
|
+
puts "═══════════════════ Help ═════════════════════════"
|
1153
1517
|
puts "Available commands:"
|
1154
1518
|
puts " help - Show this help message"
|
1155
1519
|
puts " start - Start the game with current players"
|
@@ -1157,7 +1521,7 @@ module GitGameShow
|
|
1157
1521
|
puts " status - Refresh the status display"
|
1158
1522
|
puts " end - End the current game"
|
1159
1523
|
puts " exit - Shut down the server and exit"
|
1160
|
-
puts "
|
1524
|
+
puts "══════════════════════════════════════════════════"
|
1161
1525
|
end
|
1162
1526
|
|
1163
1527
|
def print_status_message(message, status)
|
@@ -1188,10 +1552,22 @@ module GitGameShow
|
|
1188
1552
|
|
1189
1553
|
# Select the next mini-game to ensure variety and avoid repetition
|
1190
1554
|
def select_next_mini_game
|
1555
|
+
# Special case for when only one mini-game type is enabled
|
1556
|
+
if @mini_games.size == 1
|
1557
|
+
selected_game = @mini_games.first
|
1558
|
+
log_message("Only one mini-game type available: #{selected_game.name}", :light_black)
|
1559
|
+
return selected_game
|
1560
|
+
end
|
1561
|
+
|
1191
1562
|
# If we have no more available mini-games, reset the cycle
|
1192
1563
|
if @available_mini_games.empty?
|
1193
|
-
#
|
1194
|
-
|
1564
|
+
# Handle the case where we might have only one game left after excluding the last used
|
1565
|
+
if @mini_games.size <= 2
|
1566
|
+
@available_mini_games = @mini_games.dup
|
1567
|
+
else
|
1568
|
+
# Repopulate with all mini-games except the last one used (if possible)
|
1569
|
+
@available_mini_games = @mini_games.reject { |game| game == @used_mini_games.last }
|
1570
|
+
end
|
1195
1571
|
|
1196
1572
|
# Log that we're starting a new cycle
|
1197
1573
|
log_message("Starting a new cycle of mini-games", :light_black)
|
@@ -1199,6 +1575,7 @@ module GitGameShow
|
|
1199
1575
|
|
1200
1576
|
# Select a random game from the available ones
|
1201
1577
|
selected_game = @available_mini_games.sample
|
1578
|
+
return @mini_games.first if selected_game.nil? # Fallback for safety
|
1202
1579
|
|
1203
1580
|
# Remove the selected game from available and add to used
|
1204
1581
|
@available_mini_games.delete(selected_game)
|
@@ -1214,9 +1591,9 @@ module GitGameShow
|
|
1214
1591
|
def load_mini_games
|
1215
1592
|
# Enable all mini-games
|
1216
1593
|
[
|
1217
|
-
GitGameShow::AuthorQuiz,
|
1218
|
-
GitGameShow::CommitMessageQuiz,
|
1219
|
-
GitGameShow::CommitMessageCompletion,
|
1594
|
+
# GitGameShow::AuthorQuiz,
|
1595
|
+
# GitGameShow::CommitMessageQuiz,
|
1596
|
+
# GitGameShow::CommitMessageCompletion,
|
1220
1597
|
GitGameShow::DateOrderingQuiz
|
1221
1598
|
]
|
1222
1599
|
end
|