git_game_show 0.1.9 → 0.2.0
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/game_server.rb +65 -17
- data/lib/git_game_show/mini_game.rb +12 -12
- data/lib/git_game_show/player_client.rb +42 -14
- data/lib/git_game_show/version.rb +1 -1
- data/mini_games/author_quiz.rb +45 -32
- data/mini_games/blame_game.rb +392 -0
- data/mini_games/branch_detective.rb +241 -0
- data/mini_games/commit_message_completion.rb +49 -36
- data/mini_games/date_ordering_quiz.rb +64 -48
- data/mini_games/file_quiz.rb +13 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a9bd7f2e076ca47a5bb8205267ce51f3568e9ee9d03acb599c4014ae259278e
|
4
|
+
data.tar.gz: 2752fe1f922c36d5ccbcf46c5f45cb13e0377a08f46f6d71629d9eb6cba63d8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2dccfb2deae7c56d482f0429e5d70d17f781be4d9bce8db78d8c02aa58b50b61465fb55e8a692e9eb93d2d706f7786dd0ae20b68f0957a3050481e05f207b39
|
7
|
+
data.tar.gz: ddb0d3486564fbbaaa1086d4705404150096e7975374e8c0accd3294fbc2e0eda855cdc8a04309693fe3281d007308ea1fc9efe46a72d21fe7e81f42cc1f5bda
|
@@ -165,28 +165,60 @@ module GitGameShow
|
|
165
165
|
print @cursor.move_to(@main_width + 2, 5)
|
166
166
|
print "Waiting for players...".colorize(:light_black)
|
167
167
|
else
|
168
|
+
# Sort players by score (highest first)
|
169
|
+
sorted_players = @players.keys.sort_by { |name| -(@scores[name] || 0) }
|
170
|
+
|
168
171
|
# Show scrolling indicator if needed
|
169
172
|
if @players.size > max_visible_players
|
170
173
|
print @cursor.move_to(@main_width + 2, 4)
|
171
174
|
print "Showing #{max_visible_players} of #{@players.size}:".colorize(:light_yellow)
|
172
175
|
end
|
173
176
|
|
174
|
-
# Determine which players to display (
|
175
|
-
visible_players =
|
177
|
+
# Determine which players to display (show top N players by score)
|
178
|
+
visible_players = sorted_players.take(max_visible_players)
|
176
179
|
|
177
|
-
# Display visible players
|
180
|
+
# Display visible players with their scores
|
178
181
|
visible_players.each_with_index do |name, index|
|
179
182
|
print @cursor.move_to(@main_width + 2, 5 + index)
|
180
|
-
# Truncate long names
|
181
|
-
truncated_name = name.length > (@sidebar_width - 6) ?
|
182
|
-
"#{name[0...(@sidebar_width-9)]}..." :
|
183
|
-
name
|
184
183
|
|
185
|
-
if
|
186
|
-
|
184
|
+
# Get score (default to 0 if not found)
|
185
|
+
score = @scores[name] || 0
|
186
|
+
score_str = score.to_s
|
187
|
+
|
188
|
+
# Calculate available space for name and right-justified score
|
189
|
+
# Allow space for prefix (like "🥇 " or "10. ") + minimum 3 chars of name + 2 spaces + score
|
190
|
+
usable_width = @sidebar_width - 6
|
191
|
+
prefix_width = 3 # Account for emoji or number + dot + space
|
192
|
+
|
193
|
+
# Apply medal emoji for top 3 players when in game
|
194
|
+
prefix = ""
|
195
|
+
if @game_state == :playing && @scores.any?
|
196
|
+
prefix = case index
|
197
|
+
when 0 then "🥇 "
|
198
|
+
when 1 then "🥈 "
|
199
|
+
when 2 then "🥉 "
|
200
|
+
else "#{index + 1}. "
|
201
|
+
end
|
187
202
|
else
|
188
|
-
|
203
|
+
prefix = "#{index + 1}. "
|
189
204
|
end
|
205
|
+
|
206
|
+
# Calculate how much space we have for the name
|
207
|
+
max_name_length = usable_width - score_str.length - 1 # 2 spaces before score
|
208
|
+
|
209
|
+
# Truncate long names
|
210
|
+
truncated_name = name.length > max_name_length ?
|
211
|
+
"#{name[0...(max_name_length-3)]}..." :
|
212
|
+
name
|
213
|
+
|
214
|
+
# Print player name
|
215
|
+
print @cursor.move_to(@main_width + 2, 5 + index)
|
216
|
+
print "#{prefix}#{truncated_name}".colorize(:light_blue)
|
217
|
+
|
218
|
+
# Print right-justified score
|
219
|
+
score_position = @main_width + usable_width
|
220
|
+
print @cursor.move_to(score_position, 5 + index)
|
221
|
+
print score_str.colorize(:light_blue)
|
190
222
|
end
|
191
223
|
|
192
224
|
# If there are more players than can be shown, add an indicator
|
@@ -391,6 +423,8 @@ module GitGameShow
|
|
391
423
|
current_question = @round_questions[@current_question_index]
|
392
424
|
|
393
425
|
# Handle nil answer (timeout) differently
|
426
|
+
points = 0
|
427
|
+
|
394
428
|
if answer.nil?
|
395
429
|
# For timeouts, set a special "TIMEOUT" answer with 0 points
|
396
430
|
@player_answers[player_name] = {
|
@@ -398,7 +432,7 @@ module GitGameShow
|
|
398
432
|
time_taken: time_taken,
|
399
433
|
answered: true,
|
400
434
|
correct: false,
|
401
|
-
points:
|
435
|
+
points: points
|
402
436
|
}
|
403
437
|
|
404
438
|
# Send timeout feedback to the player
|
@@ -407,7 +441,7 @@ module GitGameShow
|
|
407
441
|
answer: "TIMEOUT",
|
408
442
|
correct: false,
|
409
443
|
correct_answer: current_question[:correct_answer],
|
410
|
-
points:
|
444
|
+
points: points
|
411
445
|
}
|
412
446
|
@players[player_name]&.send(feedback.to_json)
|
413
447
|
|
@@ -421,7 +455,8 @@ module GitGameShow
|
|
421
455
|
if current_question[:question_type] == 'ordering'
|
422
456
|
# Just store the answer and time, points will be calculated in evaluate_answers
|
423
457
|
correct = false # Will be properly set during evaluation
|
424
|
-
points =
|
458
|
+
points = @current_mini_game.evaluate_answers(current_question, {player_name => {answer: answer, time_taken: time_taken}})
|
459
|
+
points = points.values.first[:points]
|
425
460
|
else
|
426
461
|
# For regular quizzes, calculate points immediately
|
427
462
|
correct = answer == current_question[:correct_answer]
|
@@ -575,6 +610,9 @@ module GitGameShow
|
|
575
610
|
results.each do |player, result|
|
576
611
|
@scores[player] = (@scores[player] || 0) + (result[:points] || 0)
|
577
612
|
end
|
613
|
+
|
614
|
+
# Update the player list in sidebar to reflect new scores and ranking
|
615
|
+
update_player_list
|
578
616
|
rescue => e
|
579
617
|
log_message("Error evaluating answers: #{e.message}", :red)
|
580
618
|
end
|
@@ -727,8 +765,6 @@ module GitGameShow
|
|
727
765
|
|
728
766
|
# Select mini-game for this round with better variety
|
729
767
|
@current_mini_game = select_next_mini_game.new
|
730
|
-
@round_questions = @current_mini_game.generate_questions(@repo)
|
731
|
-
@current_question_index = 0
|
732
768
|
|
733
769
|
# Announce new round
|
734
770
|
broadcast_message({
|
@@ -736,9 +772,14 @@ module GitGameShow
|
|
736
772
|
round: @current_round,
|
737
773
|
total_rounds: @rounds,
|
738
774
|
mini_game: @current_mini_game.class.name,
|
739
|
-
description: @current_mini_game.class.description
|
775
|
+
description: @current_mini_game.class.description,
|
776
|
+
example: @current_mini_game.class.example
|
740
777
|
})
|
741
778
|
|
779
|
+
@round_questions = @current_mini_game.generate_questions(@repo)
|
780
|
+
@current_question_index = 0
|
781
|
+
|
782
|
+
|
742
783
|
log_message("Starting round #{@current_round}: #{@current_mini_game.class.name}", :cyan)
|
743
784
|
|
744
785
|
# Start the first question after a short delay
|
@@ -826,6 +867,11 @@ module GitGameShow
|
|
826
867
|
question_data[:commit_info] = current_question[:commit_info].to_s
|
827
868
|
end
|
828
869
|
end
|
870
|
+
|
871
|
+
# Add context if available (for BlameGame)
|
872
|
+
if current_question && current_question[:context]
|
873
|
+
question_data[:context] = current_question[:context].to_s
|
874
|
+
end
|
829
875
|
rescue => e
|
830
876
|
log_message("Error adding additional question data: #{e.message}", :red)
|
831
877
|
# Continue without the additional data
|
@@ -1594,7 +1640,9 @@ module GitGameShow
|
|
1594
1640
|
GitGameShow::AuthorQuiz,
|
1595
1641
|
GitGameShow::FileQuiz,
|
1596
1642
|
GitGameShow::CommitMessageCompletion,
|
1597
|
-
GitGameShow::DateOrderingQuiz
|
1643
|
+
GitGameShow::DateOrderingQuiz,
|
1644
|
+
GitGameShow::BranchDetective,
|
1645
|
+
GitGameShow::BlameGame
|
1598
1646
|
]
|
1599
1647
|
end
|
1600
1648
|
end
|
@@ -5,53 +5,53 @@ module GitGameShow
|
|
5
5
|
def descendants
|
6
6
|
@descendants ||= []
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def inherited(subclass)
|
10
10
|
descendants << subclass
|
11
11
|
end
|
12
|
-
|
13
|
-
attr_accessor :name, :description, :questions_per_round
|
12
|
+
|
13
|
+
attr_accessor :name, :description, :example, :questions_per_round
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# Default number of questions per round
|
17
17
|
self.questions_per_round = 5
|
18
|
-
|
18
|
+
|
19
19
|
# Default name and description
|
20
20
|
self.name = "Base Mini Game"
|
21
21
|
self.description = "This is a base mini game class. You should not see this in the actual game."
|
22
|
-
|
22
|
+
|
23
23
|
# Method to generate questions based on Git repo data
|
24
24
|
# This should be overridden by subclasses
|
25
25
|
def generate_questions(repo)
|
26
26
|
raise NotImplementedError, "#{self.class} must implement #generate_questions"
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Method to evaluate player answers and return results
|
30
30
|
# This should be overridden by subclasses
|
31
31
|
def evaluate_answers(question, player_answers)
|
32
32
|
raise NotImplementedError, "#{self.class} must implement #evaluate_answers"
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
# Helper method to get all commits from a repo
|
36
36
|
def get_all_commits(repo)
|
37
37
|
# Get a larger number of commits to ensure more diversity
|
38
38
|
repo.log(1000).each.to_a
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
# Helper method to get unique authors from commits
|
42
42
|
def get_commit_authors(commits)
|
43
43
|
commits.map { |commit| commit.author.name }.uniq
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
# Helper method to get commit messages
|
47
47
|
def get_commit_messages(commits)
|
48
48
|
commits.map(&:message)
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# Helper method to shuffle an array with the option to exclude certain items
|
52
52
|
def shuffled_excluding(array, exclude = nil)
|
53
53
|
items = exclude ? array.reject { |item| item == exclude } : array.dup
|
54
54
|
items.shuffle
|
55
55
|
end
|
56
56
|
end
|
57
|
-
end
|
57
|
+
end
|
@@ -115,7 +115,7 @@ module GitGameShow
|
|
115
115
|
rescue JSON::ParserError => e
|
116
116
|
puts "Invalid message format: #{e.message}".colorize(:red)
|
117
117
|
rescue => e
|
118
|
-
puts "Error processing message: #{e.message}".colorize(:red)
|
118
|
+
puts "Error processing message: #{e.message}\n#{e.backtrace.join("\n")}".colorize(:red)
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -599,6 +599,7 @@ module GitGameShow
|
|
599
599
|
total_rounds = data['total_rounds']
|
600
600
|
mini_game = data['mini_game']
|
601
601
|
description = data['description']
|
602
|
+
example = data['example']
|
602
603
|
|
603
604
|
# Box is drawn with exactly 45 "━" characters for the top and bottom borders
|
604
605
|
# The top and bottom including borders are 48 characters wide
|
@@ -616,7 +617,8 @@ module GitGameShow
|
|
616
617
|
puts " Mini-game: #{mini_game}".colorize(:light_blue)
|
617
618
|
puts " #{description}".colorize(:light_blue)
|
618
619
|
puts "\n"
|
619
|
-
|
620
|
+
puts " Example: #{example}"
|
621
|
+
puts "\n"
|
620
622
|
# Count down to the start - don't sleep here as we're waiting for the server
|
621
623
|
# to send us the questions after a fixed delay
|
622
624
|
puts " Get ready for the first question...".colorize(:yellow)
|
@@ -662,6 +664,19 @@ module GitGameShow
|
|
662
664
|
if data['commit_info']
|
663
665
|
puts "\n Commit: #{data['commit_info']}".colorize(:yellow)
|
664
666
|
end
|
667
|
+
|
668
|
+
# Display code context if available (for BlameGame)
|
669
|
+
if data['context']
|
670
|
+
puts "\n Code Context:".colorize(:light_blue)
|
671
|
+
data['context'].split("\n").each do |line|
|
672
|
+
# Check if this is the target line (with the > prefix)
|
673
|
+
if line.start_with?('>')
|
674
|
+
puts " #{line}".colorize(:yellow) # Highlight the target line
|
675
|
+
else
|
676
|
+
puts " #{line}".colorize(:white)
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
665
680
|
puts "\n"
|
666
681
|
|
667
682
|
# Create a unique timer ID for this question
|
@@ -830,6 +845,8 @@ module GitGameShow
|
|
830
845
|
puts "\n #{"─" * 40}".colorize(:light_black)
|
831
846
|
puts "\n"
|
832
847
|
|
848
|
+
points_text = "(#{data['points']} points)"
|
849
|
+
|
833
850
|
# Show immediate feedback
|
834
851
|
if data['answer'] == "TIMEOUT"
|
835
852
|
# Special handling for timeouts
|
@@ -838,7 +855,6 @@ module GitGameShow
|
|
838
855
|
puts " (0 points)".colorize(:light_black)
|
839
856
|
elsif data['correct']
|
840
857
|
# Correct answer
|
841
|
-
points_text = data['points'] > 0 ? " (+#{data['points']} points)" : ""
|
842
858
|
puts " ✅ CORRECT! Your answer was correct: #{data['answer']}#{points_text}".colorize(:green)
|
843
859
|
|
844
860
|
# Show bonus points details if applicable
|
@@ -847,9 +863,21 @@ module GitGameShow
|
|
847
863
|
puts " 🎉 SPEED BONUS: +#{bonus} points for fast answer!".colorize(:light_yellow)
|
848
864
|
end
|
849
865
|
else
|
850
|
-
|
851
|
-
|
852
|
-
|
866
|
+
if data['correct_answer'].is_a?(Array)
|
867
|
+
puts "Correct Order".rjust(39).colorize(:green) + " Your Order"
|
868
|
+
0.upto(data['correct_answer'].size - 1) do |i|
|
869
|
+
answer_color = data['correct_answer'][i] == data['answer'][i] ? :green : :red
|
870
|
+
truncated_1 = data['correct_answer'][i].length > 38 ? data['correct_answer'][i][0..35] + "..." : data['correct_answer'][i]
|
871
|
+
truncated_2 = data['answer'][i].length > 38 ? data['answer'][i][0..35] + "..." : data['answer'][i]
|
872
|
+
puts "#{truncated_1}".rjust(38).colorize(:green) + " #{truncated_2}".colorize(answer_color)
|
873
|
+
end
|
874
|
+
puts "\n\n"
|
875
|
+
puts points_text.center(80).colorize(:yellow)
|
876
|
+
else
|
877
|
+
# Incorrect answer
|
878
|
+
puts " ❌ INCORRECT! The correct answer was: #{data['correct_answer']}".colorize(:red)
|
879
|
+
puts " You answered: #{data['answer']} (0 points)".colorize(:yellow)
|
880
|
+
end
|
853
881
|
end
|
854
882
|
|
855
883
|
puts "\n Waiting for the round to complete. Please wait for the next question...".colorize(:light_blue)
|
@@ -859,7 +887,7 @@ module GitGameShow
|
|
859
887
|
def handle_round_result(data)
|
860
888
|
# Invalidate any running timer and reset window title
|
861
889
|
@current_timer_id = SecureRandom.uuid
|
862
|
-
print "\033]0;Git Game Show -
|
890
|
+
print "\033]0;Git Game Show - Question Results\007" # Reset window title with context
|
863
891
|
|
864
892
|
# Start with a clean screen
|
865
893
|
clear_screen
|
@@ -869,7 +897,7 @@ module GitGameShow
|
|
869
897
|
box_width = 40
|
870
898
|
box_top = ("╭" + "─" * box_width + "╮").center(@game_width)
|
871
899
|
box_bottom = ("╰" + "─" * box_width + "╯").center(@game_width)
|
872
|
-
box_middle = "│#{'
|
900
|
+
box_middle = "│#{'Question Results'.center(box_width)}│".center(@game_width)
|
873
901
|
|
874
902
|
# Output the box
|
875
903
|
puts "\n"
|
@@ -882,8 +910,8 @@ module GitGameShow
|
|
882
910
|
puts " Question: #{data['question'][:question]}".colorize(:light_blue)
|
883
911
|
|
884
912
|
# Handle different display formats for correct answers
|
885
|
-
if data['
|
886
|
-
puts " Correct order
|
913
|
+
if data['correct_answer'].is_a?(Array)
|
914
|
+
puts " Correct order".colorize(:green)
|
887
915
|
data['correct_answer'].each do |item|
|
888
916
|
puts " #{item}".colorize(:green)
|
889
917
|
end
|
@@ -901,9 +929,9 @@ module GitGameShow
|
|
901
929
|
# Ensure result is a hash with the expected keys
|
902
930
|
if result.is_a?(Hash)
|
903
931
|
# Check if 'correct' is a boolean or check string equality if it's a string
|
904
|
-
correct = result[
|
905
|
-
answer = result[
|
906
|
-
points = result[
|
932
|
+
correct = result['correct'] || false
|
933
|
+
answer = result['answer'].is_a?(Array) ? "" : (result['answer'] || "No answer")
|
934
|
+
points = result['points'] || 0
|
907
935
|
|
908
936
|
status = correct ? "✓" : "✗"
|
909
937
|
points_str = "(+#{points} points)"
|
@@ -986,7 +1014,7 @@ module GitGameShow
|
|
986
1014
|
box_width = 40
|
987
1015
|
puts "\n"
|
988
1016
|
puts ("╭" + "─" * box_width + "╮").center(@game_width).colorize(:yellow)
|
989
|
-
puts "│#{'Scoreboard'.center(box_width)}
|
1017
|
+
puts "│#{'Scoreboard'.center(box_width)}│".center(@game_width).colorize(:yellow)
|
990
1018
|
puts ("╰" + "─" * box_width + "╯").center(@game_width).colorize(:yellow)
|
991
1019
|
puts "\n"
|
992
1020
|
|
data/mini_games/author_quiz.rb
CHANGED
@@ -2,28 +2,41 @@ module GitGameShow
|
|
2
2
|
class AuthorQuiz < MiniGame
|
3
3
|
self.name = "Author Quiz"
|
4
4
|
self.description = "Guess which team member made each commit!"
|
5
|
+
self.example = <<~EXAMPLE
|
6
|
+
Who authored this commit?
|
7
|
+
|
8
|
+
"Add user authentication features"
|
9
|
+
|
10
|
+
abc123d (Feb 15, 2025)
|
11
|
+
|
12
|
+
Choose your answer:
|
13
|
+
Bob
|
14
|
+
\e[0;32;49m> Alice\e[0m
|
15
|
+
Charlie
|
16
|
+
David
|
17
|
+
EXAMPLE
|
5
18
|
self.questions_per_round = 5
|
6
|
-
|
19
|
+
|
7
20
|
# Custom timing for this mini-game (overrides default config)
|
8
21
|
def self.question_timeout
|
9
22
|
15 # 15 seconds per question
|
10
23
|
end
|
11
|
-
|
24
|
+
|
12
25
|
def self.question_display_time
|
13
26
|
5 # 5 seconds between questions
|
14
27
|
end
|
15
|
-
|
28
|
+
|
16
29
|
def generate_questions(repo)
|
17
30
|
# For testing, manually add some questions if we can't get meaningful ones from repo
|
18
31
|
questions = []
|
19
|
-
|
32
|
+
|
20
33
|
begin
|
21
34
|
# Get commits from the past year
|
22
35
|
one_year_ago = Time.now - (365 * 24 * 60 * 60) # One year in seconds
|
23
|
-
|
36
|
+
|
24
37
|
# Get all commits
|
25
38
|
all_commits = get_all_commits(repo)
|
26
|
-
|
39
|
+
|
27
40
|
# Filter commits from the past year, if any
|
28
41
|
commits_from_past_year = all_commits.select do |commit|
|
29
42
|
# Be safe with date parsing
|
@@ -34,39 +47,39 @@ module GitGameShow
|
|
34
47
|
false # If we can't parse the date, exclude it
|
35
48
|
end
|
36
49
|
end
|
37
|
-
|
50
|
+
|
38
51
|
# If we don't have enough commits from the past year, use all commits
|
39
52
|
commits = commits_from_past_year.size >= 10 ? commits_from_past_year : all_commits
|
40
|
-
|
53
|
+
|
41
54
|
authors = get_commit_authors(commits)
|
42
|
-
|
55
|
+
|
43
56
|
# We need at least 2 authors for this game to be meaningful
|
44
57
|
if authors.size < 2
|
45
58
|
return generate_sample_questions
|
46
59
|
end
|
47
|
-
|
60
|
+
|
48
61
|
# Shuffle all commits to ensure randomness, then select commits for questions
|
49
62
|
selected_commits = commits.shuffle.sample(self.class.questions_per_round)
|
50
|
-
|
63
|
+
|
51
64
|
selected_commits.each do |commit|
|
52
65
|
# Get the real author
|
53
66
|
correct_author = commit.author.name
|
54
|
-
|
67
|
+
|
55
68
|
# Get incorrect options (other authors)
|
56
69
|
incorrect_authors = shuffled_excluding(authors, correct_author).take(3)
|
57
|
-
|
70
|
+
|
58
71
|
# Create options array with the correct answer and incorrect ones
|
59
72
|
all_options = ([correct_author] + incorrect_authors).shuffle
|
60
|
-
|
73
|
+
|
61
74
|
# Extract the commit message, but handle multi-line messages gracefully
|
62
75
|
message_lines = commit.message.lines.reject(&:empty?)
|
63
76
|
message_preview = message_lines.first&.strip || "No message"
|
64
|
-
|
77
|
+
|
65
78
|
# For longer messages, add an indication that there's more
|
66
79
|
if message_lines.size > 1
|
67
|
-
message_preview += "..."
|
80
|
+
message_preview += "..."
|
68
81
|
end
|
69
|
-
|
82
|
+
|
70
83
|
# Create a more compact question format to avoid overflows
|
71
84
|
# Add proper indentation to the commit message with spaces
|
72
85
|
questions << {
|
@@ -80,27 +93,27 @@ module GitGameShow
|
|
80
93
|
# Silently fail and use sample questions instead
|
81
94
|
return generate_sample_questions
|
82
95
|
end
|
83
|
-
|
96
|
+
|
84
97
|
# If we couldn't generate enough questions, add sample ones
|
85
98
|
if questions.empty?
|
86
99
|
return generate_sample_questions
|
87
100
|
end
|
88
|
-
|
101
|
+
|
89
102
|
questions
|
90
103
|
end
|
91
|
-
|
104
|
+
|
92
105
|
def generate_sample_questions
|
93
106
|
# Create sample questions in case the repo doesn't have enough data
|
94
107
|
sample_authors = ["Alice", "Bob", "Charlie", "David", "Emma"]
|
95
|
-
|
108
|
+
|
96
109
|
questions = []
|
97
|
-
|
110
|
+
|
98
111
|
5.times do |i|
|
99
112
|
correct_author = sample_authors.sample
|
100
113
|
incorrect_authors = sample_authors.reject { |a| a == correct_author }.sample(3)
|
101
|
-
|
114
|
+
|
102
115
|
all_options = ([correct_author] + incorrect_authors).shuffle
|
103
|
-
|
116
|
+
|
104
117
|
questions << {
|
105
118
|
question: "Who authored this commit?\n\n \"Sample commit message ##{i+1}\"",
|
106
119
|
commit_info: "abc123#{i} (Jan #{i+1}, 2025)",
|
@@ -108,35 +121,35 @@ module GitGameShow
|
|
108
121
|
correct_answer: correct_author
|
109
122
|
}
|
110
123
|
end
|
111
|
-
|
124
|
+
|
112
125
|
questions
|
113
126
|
end
|
114
|
-
|
127
|
+
|
115
128
|
def evaluate_answers(question, player_answers)
|
116
129
|
results = {}
|
117
|
-
|
130
|
+
|
118
131
|
player_answers.each do |player_name, answer_data|
|
119
132
|
answered = answer_data[:answered] || false
|
120
133
|
player_answer = answer_data[:answer]
|
121
134
|
correct = player_answer == question[:correct_answer]
|
122
|
-
|
135
|
+
|
123
136
|
points = correct ? 10 : 0
|
124
|
-
|
137
|
+
|
125
138
|
# Bonus points for fast answers (if correct)
|
126
139
|
if correct && answer_data[:time_taken] < 5
|
127
140
|
points += 5
|
128
141
|
elsif correct && answer_data[:time_taken] < 10
|
129
142
|
points += 3
|
130
143
|
end
|
131
|
-
|
144
|
+
|
132
145
|
results[player_name] = {
|
133
146
|
answer: player_answer,
|
134
147
|
correct: correct,
|
135
148
|
points: points
|
136
149
|
}
|
137
150
|
end
|
138
|
-
|
151
|
+
|
139
152
|
results
|
140
153
|
end
|
141
154
|
end
|
142
|
-
end
|
155
|
+
end
|