Skip to content

Commit 110007b

Browse files
Merge pull request #33 from unhappychoice/feat/retry-button
feat: Add retry button to play same challenge again
2 parents 79a86ef + c3ed536 commit 110007b

File tree

2 files changed

+67
-36
lines changed

2 files changed

+67
-36
lines changed

src/game/screens/result_screen.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub enum ResultAction {
1515
Restart,
1616
BackToTitle,
1717
Quit,
18+
Retry,
1819
}
1920

2021
pub struct ResultScreen;
@@ -330,6 +331,7 @@ impl ResultScreen {
330331

331332
// Display options
332333
let options = vec![
334+
"[R] Retry",
333335
"[T/ENTER] Back to Title",
334336
"[ESC] Quit",
335337
];
@@ -351,13 +353,29 @@ impl ResultScreen {
351353

352354
stdout.flush()?;
353355

354-
// Wait for user input before returning
356+
Ok(())
357+
}
358+
359+
pub fn show_session_summary_with_input(
360+
_total_stages: usize,
361+
_completed_stages: usize,
362+
stage_engines: &[(String, ScoringEngine)],
363+
) -> Result<ResultAction> {
364+
Self::show_session_summary(_total_stages, _completed_stages, stage_engines)?;
365+
366+
// Wait for user input and return action
355367
loop {
356368
if event::poll(std::time::Duration::from_millis(100))? {
357369
if let Event::Key(key_event) = event::read()? {
358370
match key_event.code {
359-
KeyCode::Char('t') | KeyCode::Char('T') | KeyCode::Enter | KeyCode::Esc => {
360-
return Ok(());
371+
KeyCode::Char('r') | KeyCode::Char('R') => {
372+
return Ok(ResultAction::Retry);
373+
},
374+
KeyCode::Char('t') | KeyCode::Char('T') | KeyCode::Enter => {
375+
return Ok(ResultAction::BackToTitle);
376+
},
377+
KeyCode::Esc => {
378+
return Ok(ResultAction::Quit);
361379
},
362380
KeyCode::Char('c') if key_event.modifiers.contains(KeyModifiers::CONTROL) => {
363381
std::process::exit(0);

src/game/stage_manager.rs

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::scoring::{TypingMetrics, ScoringEngine};
33
use crossterm::terminal;
44
use super::{
55
challenge::Challenge,
6-
screens::{TitleScreen, ResultScreen, CountdownScreen, TypingScreen, TitleAction},
6+
screens::{TitleScreen, ResultScreen, CountdownScreen, TypingScreen, TitleAction, result_screen::ResultAction},
77
stage_builder::{StageBuilder, GameMode, DifficultyLevel},
88
};
99

@@ -12,6 +12,7 @@ pub struct StageManager {
1212
current_challenges: Vec<Challenge>,
1313
current_stage: usize,
1414
stage_engines: Vec<(String, ScoringEngine)>,
15+
current_game_mode: Option<GameMode>,
1516
}
1617

1718
impl StageManager {
@@ -21,6 +22,7 @@ impl StageManager {
2122
current_challenges: Vec::new(),
2223
current_stage: 0,
2324
stage_engines: Vec::new(),
25+
current_game_mode: None,
2426
}
2527
}
2628

@@ -48,33 +50,39 @@ impl StageManager {
4850
difficulty: difficulty.clone(),
4951
};
5052

51-
let stage_builder = StageBuilder::with_mode(game_mode);
52-
self.current_challenges = stage_builder.build_stages(self.available_challenges.clone());
53+
self.current_game_mode = Some(game_mode.clone());
5354

54-
// Debug output
55-
println!("Selected difficulty: {:?}", difficulty);
56-
println!("Built {} challenges with difficulty {:?}", self.current_challenges.len(), difficulty);
57-
for (i, challenge) in self.current_challenges.iter().enumerate() {
58-
println!(" Challenge {}: {} ({} lines)", i+1, challenge.id, challenge.code_content.lines().count());
59-
}
60-
61-
if self.current_challenges.is_empty() {
62-
println!("No challenges found for difficulty {:?}", difficulty);
63-
continue; // Go back to title screen
64-
}
65-
66-
// Reset session metrics
67-
self.current_stage = 0;
68-
self.stage_engines.clear();
69-
70-
match self.run_stages() {
71-
Ok(_session_complete) => {
72-
// After session completes, continue to title screen
73-
// User can choose to play again or quit
74-
},
75-
Err(e) => {
76-
terminal::disable_raw_mode()?;
77-
return Err(e);
55+
loop {
56+
let stage_builder = StageBuilder::with_mode(game_mode.clone());
57+
self.current_challenges = stage_builder.build_stages(self.available_challenges.clone());
58+
59+
// Debug output
60+
println!("Selected difficulty: {:?}", difficulty);
61+
println!("Built {} challenges with difficulty {:?}", self.current_challenges.len(), difficulty);
62+
for (i, challenge) in self.current_challenges.iter().enumerate() {
63+
println!(" Challenge {}: {} ({} lines)", i+1, challenge.id, challenge.code_content.lines().count());
64+
}
65+
66+
if self.current_challenges.is_empty() {
67+
println!("No challenges found for difficulty {:?}", difficulty);
68+
break; // Go back to title screen
69+
}
70+
71+
// Reset session metrics
72+
self.current_stage = 0;
73+
self.stage_engines.clear();
74+
75+
match self.run_stages() {
76+
Ok(session_complete) => {
77+
if !session_complete {
78+
break; // User chose to quit or back to title
79+
}
80+
// If session_complete is true, retry with same settings
81+
},
82+
Err(e) => {
83+
terminal::disable_raw_mode()?;
84+
return Err(e);
85+
}
7886
}
7987
}
8088
},
@@ -113,8 +121,14 @@ impl StageManager {
113121
}
114122

115123
// All stages completed - show final results (raw mode still enabled)
116-
self.show_session_summary()?;
117-
Ok(true) // Return true to indicate session completed
124+
match self.show_session_summary()? {
125+
ResultAction::Retry => Ok(true), // Return true to indicate retry requested
126+
ResultAction::Quit => {
127+
terminal::disable_raw_mode()?;
128+
std::process::exit(0);
129+
},
130+
_ => Ok(false), // Return false for back to title
131+
}
118132
}
119133

120134
fn show_stage_completion(&self, metrics: &TypingMetrics) -> Result<()> {
@@ -135,13 +149,12 @@ impl StageManager {
135149
}
136150

137151

138-
fn show_session_summary(&self) -> Result<()> {
139-
let _result = ResultScreen::show_session_summary(
152+
fn show_session_summary(&self) -> Result<ResultAction> {
153+
ResultScreen::show_session_summary_with_input(
140154
self.current_challenges.len(),
141155
self.stage_engines.len(),
142156
&self.stage_engines,
143-
)?;
144-
Ok(())
157+
)
145158
}
146159

147160
pub fn get_current_stage(&self) -> usize {

0 commit comments

Comments
 (0)