git_game_show 0.2.1 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c1276258a9e2d5888ea51d9c44275c81a6b062b6b0be1959ad35e707f8d0b25
4
- data.tar.gz: 1a0de92893ef2f8fd80762f0c36e00516ffbdd1d46c77c36afca4dfcac30ef26
3
+ metadata.gz: 3abc81a3656def2b0880a2e4127ceeca7cf43e101a774ce6ff5f4fd4a5dc2340
4
+ data.tar.gz: 5ac77e86bfc2814742302ab80a56594dc956add3beeae6f3bd2b6368060f98ac
5
5
  SHA512:
6
- metadata.gz: c30984bf5db7535d12ea5ce36d4dfbeaf02856676bcad043da143ee7a0e142b5f3406c50f761de03c812bcf090754c9119b2155c446b3f57967ba0fda58ae9bf
7
- data.tar.gz: b2a882dec2a57908ebcd4574aee757df13ba3cdf084f642f6ff5775d65dc8ff224d1244dcf08e3f2eebb2ec04f2fab05d18e7520c6d040b2b4045cdcd87022eb
6
+ metadata.gz: b0ed039456447007b222d5a48a3175593ba059faebff0be7bf056e044afd6128fd508b9a598b9f1de95294260a220eaa3010b65408b707686b05e6dfe5078e2a
7
+ data.tar.gz: 5a4e54ec376ee4036697b83be7629099d6fbff2f6988b7055b246adc0a4d9f251dafb4ce0ea38fe75c0fa538a3eac10bd0b299674b9e493f6c5c0c526730b45e
data/README.md CHANGED
@@ -114,6 +114,10 @@ The game includes several mini-games based on Git repository data:
114
114
 
115
115
  MIT
116
116
 
117
+ ## Inspiration
118
+
119
+ Git Game Show was inspired by https://github.com/jsomers/git-game.
120
+
117
121
  ## Contributing
118
122
 
119
123
  1. Fork the repository
@@ -0,0 +1,120 @@
1
+ module GitGameShow
2
+ # Manages the state of the game
3
+ class GameState
4
+ attr_reader :state, :current_round, :total_rounds, :current_mini_game
5
+ attr_reader :round_questions, :current_question_index, :question_start_time
6
+ attr_reader :player_answers, :current_question_id, :question_already_evaluated
7
+
8
+ def initialize(total_rounds)
9
+ @total_rounds = total_rounds
10
+ @current_round = 0
11
+ @state = :lobby # :lobby, :playing, :ended
12
+ @current_mini_game = nil
13
+ @round_questions = []
14
+ @current_question_index = 0
15
+ @question_start_time = nil
16
+ @player_answers = {}
17
+ @current_question_id = nil
18
+ @question_already_evaluated = false
19
+ @used_mini_games = [] # Track which mini-games have been used
20
+ @available_mini_games = [] # Mini-games still available in the current cycle
21
+ end
22
+
23
+ def lobby?
24
+ @state == :lobby
25
+ end
26
+
27
+ def playing?
28
+ @state == :playing
29
+ end
30
+
31
+ def ended?
32
+ @state == :ended
33
+ end
34
+
35
+ def start_game
36
+ return false unless @state == :lobby
37
+ @state = :playing
38
+ @current_round = 0
39
+ # Reset the mini-game tracking for a new game
40
+ @used_mini_games = []
41
+ @available_mini_games = []
42
+ true
43
+ end
44
+
45
+ def end_game
46
+ @state = :ended
47
+ true
48
+ end
49
+
50
+ def reset_game
51
+ @state = :lobby
52
+ @current_round = 0
53
+ @current_mini_game = nil
54
+ @round_questions = []
55
+ @current_question_index = 0
56
+ @question_already_evaluated = false
57
+ @player_answers = {}
58
+ true
59
+ end
60
+
61
+ def start_next_round(mini_game)
62
+ @current_round += 1
63
+ # Reset question evaluation flag for the new round
64
+ @question_already_evaluated = false
65
+
66
+ # Set the current mini-game
67
+ @current_mini_game = mini_game
68
+ true
69
+ end
70
+
71
+ def set_round_questions(questions)
72
+ @round_questions = questions
73
+ @current_question_index = 0
74
+ true
75
+ end
76
+
77
+ def prepare_next_question
78
+ return false if @current_question_index >= @round_questions.size
79
+
80
+ @question_already_evaluated = false
81
+ @current_question_id = "#{@current_round}-#{@current_question_index}"
82
+ @question_start_time = Time.now
83
+ @player_answers = {}
84
+ true
85
+ end
86
+
87
+ def current_question
88
+ return nil if @current_question_index >= @round_questions.size
89
+ @round_questions[@current_question_index]
90
+ end
91
+
92
+ def move_to_next_question
93
+ @current_question_index += 1
94
+ @player_answers = {}
95
+ @question_already_evaluated = false
96
+ end
97
+
98
+ def last_question_in_round?
99
+ @current_question_index >= @round_questions.size - 1
100
+ end
101
+
102
+ def last_round?
103
+ @current_round >= @total_rounds
104
+ end
105
+
106
+ def record_player_answer(player_name, answer, time_taken, correct = nil, points = 0)
107
+ @player_answers[player_name] = {
108
+ answer: answer,
109
+ time_taken: time_taken,
110
+ answered: true,
111
+ correct: correct,
112
+ points: points
113
+ }
114
+ end
115
+
116
+ def mark_question_evaluated
117
+ @question_already_evaluated = true
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,55 @@
1
+ module GitGameShow
2
+ # Handles loading and selecting mini-games
3
+ class MiniGameLoader
4
+ attr_reader :mini_games
5
+
6
+ def initialize
7
+ @mini_games = load_mini_games
8
+ @used_mini_games = []
9
+ @available_mini_games = []
10
+ end
11
+
12
+ def select_next_mini_game
13
+ # Special case for when only one mini-game type is enabled
14
+ if @mini_games.size == 1
15
+ return @mini_games.first.new
16
+ end
17
+
18
+ # If we have no more available mini-games, reset the cycle
19
+ if @available_mini_games.empty?
20
+ # Handle the case where we might have only one game left after excluding the last used
21
+ if @mini_games.size <= 2
22
+ @available_mini_games = @mini_games.dup
23
+ else
24
+ # Repopulate with all mini-games except the last one used (if possible)
25
+ @available_mini_games = @mini_games.reject { |game| game == @used_mini_games.last }
26
+ end
27
+ end
28
+
29
+ # Select a random game from the available ones
30
+ selected_game = @available_mini_games.sample
31
+ return @mini_games.first.new if selected_game.nil? # Fallback for safety
32
+
33
+ # Remove the selected game from available and add to used
34
+ @available_mini_games.delete(selected_game)
35
+ @used_mini_games << selected_game
36
+
37
+ # Return a new instance of the selected game class
38
+ selected_game.new
39
+ end
40
+
41
+ private
42
+
43
+ def load_mini_games
44
+ # Enable all mini-games
45
+ [
46
+ GitGameShow::AuthorQuiz,
47
+ GitGameShow::FileQuiz,
48
+ GitGameShow::CommitMessageCompletion,
49
+ GitGameShow::DateOrderingQuiz,
50
+ GitGameShow::BranchDetective,
51
+ GitGameShow::BlameGame
52
+ ]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,61 @@
1
+ module GitGameShow
2
+ # Manages player connections, scores, and related operations
3
+ class PlayerManager
4
+ attr_reader :players, :scores
5
+
6
+ def initialize
7
+ @players = {} # WebSocket connections by player name
8
+ @scores = {} # Player scores
9
+ end
10
+
11
+ def add_player(name, ws)
12
+ return false if @players.key?(name)
13
+ @players[name] = ws
14
+ @scores[name] = 0
15
+ true
16
+ end
17
+
18
+ def remove_player(name)
19
+ return false unless @players.key?(name)
20
+ @players.delete(name)
21
+ true
22
+ end
23
+
24
+ def find_player_by_ws(ws)
25
+ @players.key(ws)
26
+ end
27
+
28
+ def player_exists?(name)
29
+ @players.key?(name)
30
+ end
31
+
32
+ def get_ws(name)
33
+ @players[name]
34
+ end
35
+
36
+ def player_count
37
+ @players.size
38
+ end
39
+
40
+ def player_names
41
+ @players.keys
42
+ end
43
+
44
+ def update_score(name, points)
45
+ @scores[name] = (@scores[name] || 0) + points
46
+ end
47
+
48
+ def reset_scores
49
+ @players.keys.each { |name| @scores[name] = 0 }
50
+ end
51
+
52
+ def sorted_scores
53
+ @scores.sort_by { |_, score| -score }.to_h
54
+ end
55
+
56
+ def top_player
57
+ sorted = sorted_scores
58
+ sorted.empty? ? nil : sorted.first
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,120 @@
1
+ module GitGameShow
2
+ # Manages question generation, evaluation, and scoring
3
+ class QuestionManager
4
+ def initialize(game_state, player_manager)
5
+ @game_state = game_state
6
+ @player_manager = player_manager
7
+ end
8
+
9
+ def generate_questions(repo)
10
+ mini_game = @game_state.current_mini_game
11
+ return [] unless mini_game
12
+
13
+ begin
14
+ questions = mini_game.generate_questions(repo)
15
+ @game_state.set_round_questions(questions)
16
+ questions
17
+ rescue => e
18
+ # Handle error gracefully
19
+ []
20
+ end
21
+ end
22
+
23
+ def evaluate_answers
24
+ return false if @game_state.question_already_evaluated
25
+
26
+ @game_state.mark_question_evaluated
27
+ current_question = @game_state.current_question
28
+ return false unless current_question
29
+
30
+ mini_game = @game_state.current_mini_game
31
+ return false unless mini_game
32
+
33
+ player_answers = @game_state.player_answers
34
+
35
+ results = {}
36
+
37
+ if current_question[:question_type] == 'ordering'
38
+ # Convert player_answers to the format expected by mini-game's evaluate_answers
39
+ mini_game_answers = {}
40
+ player_answers.each do |player_name, answer_data|
41
+ next unless player_name && answer_data
42
+
43
+ mini_game_answers[player_name] = {
44
+ answer: answer_data[:answer],
45
+ time_taken: answer_data[:time_taken] || 20
46
+ }
47
+ end
48
+
49
+ # Call the mini-game's evaluate_answers method
50
+ begin
51
+ results = mini_game.evaluate_answers(current_question, mini_game_answers) || {}
52
+ rescue => e
53
+ # Create fallback results in case of error
54
+ player_answers.each do |player_name, answer_data|
55
+ next unless player_name
56
+
57
+ results[player_name] = {
58
+ answer: answer_data[:answer] || [],
59
+ correct: false,
60
+ points: 0,
61
+ partial_score: "Error calculating score"
62
+ }
63
+ end
64
+ end
65
+ else
66
+ # For regular quizzes, use pre-calculated points
67
+ player_answers.each do |player_name, answer_data|
68
+ next unless player_name && answer_data
69
+
70
+ results[player_name] = {
71
+ answer: answer_data[:answer] || "No answer",
72
+ correct: answer_data[:correct] || false,
73
+ points: answer_data[:points] || 0
74
+ }
75
+ end
76
+ end
77
+
78
+ # Update scores in player manager
79
+ results.each do |player, result|
80
+ @player_manager.update_score(player, result[:points] || 0)
81
+ end
82
+
83
+ # Format correct answer for ordering questions
84
+ if current_question[:question_type] == 'ordering'
85
+ formatted_correct_answer = current_question[:correct_answer].map.with_index do |item, idx|
86
+ "#{idx + 1}. #{item}" # Add numbers for easier reading
87
+ end
88
+ current_question[:formatted_correct_answer] = formatted_correct_answer
89
+ end
90
+
91
+ # Return the results and the current question
92
+ return {
93
+ results: results,
94
+ question: current_question
95
+ }
96
+ end
97
+
98
+ def question_timeout
99
+ # Get mini-game specific timeout if available
100
+ if @game_state.current_mini_game.class.respond_to?(:question_timeout)
101
+ timeout = @game_state.current_mini_game.class.question_timeout.to_i
102
+ return timeout > 0 ? timeout : 20
103
+ end
104
+
105
+ # Default timeout
106
+ GitGameShow::DEFAULT_CONFIG[:question_timeout] || 20
107
+ end
108
+
109
+ def question_display_time
110
+ # Get mini-game specific display time if available
111
+ if @game_state.current_mini_game.class.respond_to?(:question_display_time)
112
+ display_time = @game_state.current_mini_game.class.question_display_time.to_i
113
+ return display_time > 0 ? display_time : 5
114
+ end
115
+
116
+ # Default display time
117
+ GitGameShow::DEFAULT_CONFIG[:question_display_time] || 5
118
+ end
119
+ end
120
+ end