git_game_show 0.1.10 → 0.2.1

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.
@@ -2,23 +2,38 @@ module GitGameShow
2
2
  class DateOrderingQuiz < MiniGame
3
3
  self.name = "Commit Timeline"
4
4
  self.description = "Put these commits in chronological order! (20 seconds per question)"
5
+ self.example = <<~EXAMPLE
6
+ Put these commits in chronological order (oldest to newest):
7
+
8
+ Current order:
9
+ Add payment gateway integration (m2n3o4p)
10
+ Fix login page styling issues (e4f5g6h)
11
+ Update README with API documentation (q5r6s7t)
12
+ Implement password reset functionality (i7j8k9l)
13
+
14
+ Drag items to reorder:
15
+ \e[0;32;49m1. Create README.md (q5r6s7t)\e[0m
16
+ \e[0;32;49m2. Fix login page styling issues (e4f5g6h)\e[0m
17
+ \e[0;32;49m3. Implement password reset functionality (i7j8k9l)\e[0m
18
+ \e[0;32;49m4. Add payment gateway integration (m2n3o4p)\e[0m
19
+ EXAMPLE
5
20
  self.questions_per_round = 5
6
-
21
+
7
22
  # Custom timing for this mini-game
8
23
  def self.question_timeout
9
24
  20 # 20 seconds per question
10
25
  end
11
-
26
+
12
27
  def self.question_display_time
13
28
  5 # 5 seconds between questions
14
29
  end
15
-
30
+
16
31
  def generate_questions(repo)
17
32
  begin
18
33
  # Get commits with valid dates
19
34
  all_commits = get_all_commits(repo)
20
35
  commits = all_commits.select { |commit| commit.date.is_a?(Time) || commit.date.respond_to?(:to_time) }
21
-
36
+
22
37
  # If we don't have enough commits for the game, generate sample questions
23
38
  if commits.size < 10
24
39
  return generate_sample_questions
@@ -27,9 +42,9 @@ module GitGameShow
27
42
  # If any errors occur, fall back to sample questions
28
43
  return generate_sample_questions
29
44
  end
30
-
45
+
31
46
  questions = []
32
-
47
+
33
48
  # Generate questions
34
49
  self.class.questions_per_round.times do
35
50
  begin
@@ -37,30 +52,30 @@ module GitGameShow
37
52
  # to avoid ties in the ordering
38
53
  pool = commits.dup
39
54
  selected_commits = []
40
-
55
+
41
56
  # Select 4 commits with different dates
42
57
  while selected_commits.size < 4 && !pool.empty?
43
58
  commit = pool.sample
44
59
  pool.delete(commit)
45
-
60
+
46
61
  # Check if date is unique among selected commits
47
62
  date_duplicate = selected_commits.any? do |selected|
48
63
  # Convert dates to Time objects for comparison
49
64
  commit_time = commit.date.is_a?(Time) ? commit.date : commit.date.to_time
50
65
  selected_time = selected.date.is_a?(Time) ? selected.date : selected.date.to_time
51
-
66
+
52
67
  # Check if times are within 1 minute of each other (avoid duplicates)
53
68
  (commit_time - selected_time).abs < 60
54
69
  end
55
-
70
+
56
71
  selected_commits << commit unless date_duplicate
57
72
  end
58
-
73
+
59
74
  # If we couldn't get 4 commits with different dates, try again with the full pool
60
75
  if selected_commits.size < 4
61
76
  selected_commits = commits.sample(4)
62
77
  end
63
-
78
+
64
79
  # Create the options using commit message and short SHA
65
80
  options = selected_commits.map do |commit|
66
81
  # Get first line of commit message, handle multi-line messages
@@ -69,23 +84,23 @@ module GitGameShow
69
84
  message = message.length > 40 ? "#{message[0...37]}..." : message
70
85
  "#{message} (#{commit.sha[0..6]})"
71
86
  end
72
-
87
+
73
88
  # Shuffle options for initial display
74
89
  shuffled_options = options.shuffle
75
-
90
+
76
91
  # Determine correct order by date
77
92
  correct_order = selected_commits.sort_by(&:date).map do |commit|
78
93
  message = commit.message.lines.first&.strip || "No message"
79
94
  message = message.length > 40 ? "#{message[0...37]}..." : message
80
95
  "#{message} (#{commit.sha[0..6]})"
81
96
  end
82
-
97
+
83
98
  # Get commit dates for displaying in results
84
99
  commit_dates = selected_commits.map do |commit|
85
100
  date_string = commit.date.strftime('%Y-%m-%d %H:%M:%S')
86
101
  "#{commit.sha[0..6]}: #{date_string}"
87
102
  end
88
-
103
+
89
104
  # Store the question data
90
105
  questions << {
91
106
  question: "Put these commits in chronological order (oldest to newest):",
@@ -99,20 +114,20 @@ module GitGameShow
99
114
  next
100
115
  end
101
116
  end
102
-
117
+
103
118
  # If we couldn't generate enough questions, fill with sample questions
104
119
  if questions.size < self.class.questions_per_round
105
120
  sample_questions = generate_sample_questions
106
121
  questions += sample_questions[0...(self.class.questions_per_round - questions.size)]
107
122
  end
108
-
123
+
109
124
  questions
110
125
  end
111
-
126
+
112
127
  # Generate sample questions when we don't have enough commits
113
128
  def generate_sample_questions
114
129
  questions = []
115
-
130
+
116
131
  # Sample data sets with commit messages and dates
117
132
  sample_data = [
118
133
  [
@@ -146,57 +161,58 @@ module GitGameShow
146
161
  { message: "Fix responsive design issues", sha: "y1z2a3b", date: "2023-05-25 16:45:00" }
147
162
  ]
148
163
  ]
149
-
164
+
150
165
  # Generate one question from each sample set
151
166
  self.class.questions_per_round.times do |i|
152
167
  # Use modulo to cycle through samples if we have fewer samples than questions
153
168
  sample_set = sample_data[i % sample_data.size]
154
-
169
+
155
170
  # Format the options
156
171
  options = sample_set.map { |item| "#{item[:message]} (#{item[:sha]})" }
157
-
172
+
158
173
  # Determine correct order (they're already in order in our samples)
159
174
  correct_order = options.dup
160
-
175
+
161
176
  # Shuffle options for initial display
162
177
  shuffled_options = options.shuffle
163
-
178
+
164
179
  # Format dates for feedback
165
180
  date_strings = sample_set.map { |item| "#{item[:sha]}: #{item[:date]}" }
166
-
181
+
167
182
  questions << {
168
183
  question: "Put these commits in chronological order (oldest to newest):",
169
184
  options: shuffled_options,
170
- correct_answer: correct_order,
185
+ correct_answer: correct_order,
171
186
  question_type: 'ordering',
172
187
  commit_dates: date_strings.join("\n")
173
188
  }
174
189
  end
175
-
190
+
176
191
  questions
177
192
  end
178
-
193
+
194
+
179
195
  def evaluate_answers(question, player_answers)
180
196
  results = {}
181
-
197
+
182
198
  # Safety check for nil or empty responses
183
199
  return results if player_answers.nil? || player_answers.empty?
184
200
  return results unless question && question[:correct_answer]
185
-
201
+
186
202
  # Get total number of items in the correct answer
187
203
  total_items = question[:correct_answer].size
188
-
204
+
189
205
  player_answers.each do |player_name, answer_data|
190
206
  # Skip nil entries
191
207
  next unless player_name && answer_data
192
-
208
+
193
209
  # Extract player's answer with defensive checks
194
210
  player_answer = answer_data[:answer]
195
211
  time_taken = answer_data[:time_taken] || 20
196
-
212
+
197
213
  # Initialize points
198
214
  points = 0
199
-
215
+
200
216
  # New scoring system: checks positions relative to each other item
201
217
  if player_answer && !player_answer.empty?
202
218
  # Create a mapping from item to its position in player's answer
@@ -204,26 +220,26 @@ module GitGameShow
204
220
  player_answer.each_with_index do |item, index|
205
221
  item_positions[item] = index if item # Skip nil items
206
222
  end
207
-
223
+
208
224
  # Create mapping from item to correct position
209
225
  correct_positions = {}
210
226
  question[:correct_answer].each_with_index do |item, index|
211
227
  correct_positions[item] = index if item # Skip nil items
212
228
  end
213
-
229
+
214
230
  # For each item, calculate points based on relative positions
215
231
  question[:correct_answer].each_with_index do |item, correct_index|
216
232
  # Skip if the item isn't in the player's answer
217
233
  next unless item && item_positions.key?(item)
218
-
234
+
219
235
  player_index = item_positions[item]
220
-
236
+
221
237
  # Check position relative to other items
222
238
  question[:correct_answer].each_with_index do |other_item, other_correct_index|
223
239
  next if !other_item || item == other_item || !item_positions.key?(other_item)
224
-
240
+
225
241
  other_player_index = item_positions[other_item]
226
-
242
+
227
243
  # If this item should be before the other item
228
244
  if correct_index < other_correct_index
229
245
  points += 1 if player_index < other_player_index
@@ -234,12 +250,12 @@ module GitGameShow
234
250
  end
235
251
  end
236
252
  end
237
-
253
+
238
254
  # Bonus points for perfect answer
239
255
  perfect_score = total_items * (total_items - 1)
240
256
  perfect_score = 1 if perfect_score <= 0 # Prevent division by zero
241
257
  fully_correct = points == perfect_score
242
-
258
+
243
259
  if fully_correct
244
260
  # Additional time-based bonus (faster answers get more points)
245
261
  if time_taken < 8 # Really fast (under 8 seconds)
@@ -248,7 +264,7 @@ module GitGameShow
248
264
  points += 2
249
265
  end
250
266
  end
251
-
267
+
252
268
  # Create detailed feedback
253
269
  max_possible = total_items * (total_items - 1)
254
270
  max_possible = 1 if max_possible <= 0 # Prevent division by zero
@@ -260,7 +276,7 @@ module GitGameShow
260
276
  feedback += "\n • #{date_line}"
261
277
  end
262
278
  end
263
-
279
+
264
280
  # Ensure we return all required fields
265
281
  results[player_name] = {
266
282
  answer: player_answer || [],
@@ -269,7 +285,7 @@ module GitGameShow
269
285
  partial_score: feedback || ""
270
286
  }
271
287
  end
272
-
288
+
273
289
  # Return a default result if somehow we ended up with empty results
274
290
  if results.empty? && !player_answers.empty?
275
291
  player_name = player_answers.keys.first
@@ -280,8 +296,8 @@ module GitGameShow
280
296
  partial_score: "Error calculating score"
281
297
  }
282
298
  end
283
-
299
+
284
300
  results
285
301
  end
286
302
  end
287
- end
303
+ end
@@ -5,6 +5,19 @@ module GitGameShow
5
5
  class FileQuiz < MiniGame
6
6
  self.name = "File Quiz"
7
7
  self.description = "Match the commit message to the right changed file!"
8
+ self.example = <<~EXAMPLE
9
+ Which file was most likely changed in this commit?
10
+
11
+ "Update documentation with new API endpoints"
12
+
13
+ abc123f (Mar 15, 2025)
14
+
15
+ Choose your answer:
16
+ src/main.js
17
+ css/styles.css
18
+ \e[0;32;49m> README.md\e[0m
19
+ lib/utils.js
20
+ EXAMPLE
8
21
  self.questions_per_round = 5
9
22
 
10
23
  # Custom timing for this mini-game (same as AuthorQuiz)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_game_show
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Paulson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-10 00:00:00.000000000 Z
11
+ date: 2025-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -213,6 +213,7 @@ files:
213
213
  - lib/git_game_show/updater.rb
214
214
  - lib/git_game_show/version.rb
215
215
  - mini_games/author_quiz.rb
216
+ - mini_games/blame_game.rb
216
217
  - mini_games/branch_detective.rb
217
218
  - mini_games/commit_message_completion.rb
218
219
  - mini_games/date_ordering_quiz.rb