Skip to content

Commit 8f52ce3

Browse files
committed
feat: capture AI stderr during game
1 parent 2721536 commit 8f52ce3

File tree

3 files changed

+31
-16
lines changed

3 files changed

+31
-16
lines changed

backend/README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Creates a game against the user's submission. Fails if the user already has a ga
2222

2323
#### Response
2424

25-
The initial `GameState`.
25+
The initial `TurnStatus`.
2626

2727
---
2828

@@ -32,7 +32,7 @@ Get the current state of the game.
3232

3333
### Response
3434

35-
The current `GameState`.
35+
The current `TurnStatus`.
3636

3737
---
3838

@@ -48,7 +48,7 @@ type Body = { from: [number, number]; to: [number, number] }[];
4848

4949
### Response
5050

51-
The `GameState` after the AI has played.
51+
The `TurnStatus` after the AI has played.
5252

5353
---
5454

@@ -95,6 +95,10 @@ Errors are returned as status code. Most notable ones are:
9595
interface GameState {
9696
board: Board;
9797
current_player: Player;
98+
}
99+
100+
interface TurnStatus {
101+
game: GameState;
98102
ai_output: string; // Everything printed by the AI on stderr since the start/last move.
99103
}
100104

backend/src/api/play.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{AppState, Error, User};
2-
use crate::game::{GameState, Move, Player};
2+
use crate::game::{GameState, Move, Player, TurnStatus};
33
use async_process::{Child, ChildStderr, ChildStdin, ChildStdout};
44
use rocket::{
55
futures::{io::BufReader, AsyncBufReadExt, AsyncWriteExt},
@@ -24,7 +24,7 @@ fn convert_cell_id(id: &[char]) -> (usize, usize) {
2424
}
2525

2626
impl Game {
27-
pub async fn play_ai(&mut self) -> Result<(), Error> {
27+
pub async fn play_ai(&mut self) -> Result<String, Error> {
2828
self.stdin
2929
.write_all(self.checkers.to_csv_string().as_bytes())
3030
.await
@@ -40,7 +40,9 @@ impl Game {
4040
.apply_move(convert_cell_id(&char[0..=1]), convert_cell_id(&char[2..=3]))?;
4141
}
4242

43-
Ok(())
43+
let mut res = vec![];
44+
self.stderr.read_until(1, &mut res);
45+
Ok(String::from_utf8_lossy(&res).to_string())
4446
}
4547

4648
pub async fn play_human(&mut self, moves: Vec<Move>) -> Result<(), Error> {
@@ -72,7 +74,7 @@ pub async fn start(
7274
state: &AppState,
7375
user: User,
7476
is_first_player: bool,
75-
) -> Result<Json<GameState>, Error> {
77+
) -> Result<Json<TurnStatus>, Error> {
7678
let game = {
7779
let lock = state.lock().unwrap();
7880
lock.games.get(&user.name).cloned()
@@ -91,15 +93,14 @@ pub async fn start(
9193
.ok_or(Error::NotFound)?
9294
.start()?
9395
};
94-
let mut checkers: GameState = Default::default();
96+
97+
let checkers: GameState = Default::default();
9598

9699
let mut stderr = BufReader::new(child.stderr.take().unwrap());
97100

98101
let mut output = vec![];
99102
stderr.read_until(1, &mut output).await?;
100103

101-
checkers.ai_output = String::from_utf8_lossy(&output).to_string();
102-
103104
let mut lock = state.lock().unwrap();
104105
lock.games.insert(
105106
user.name,
@@ -117,15 +118,18 @@ pub async fn start(
117118
})),
118119
);
119120

120-
Ok(Json(checkers))
121+
Ok(Json(TurnStatus {
122+
game: checkers,
123+
ai_output: String::from_utf8_lossy(&output).to_string(),
124+
}))
121125
}
122126

123127
#[post("/game", format = "json", data = "<moves>")]
124128
pub async fn play(
125129
state: &AppState,
126130
user: User,
127131
moves: Json<Vec<Move>>,
128-
) -> Result<Json<GameState>, Error> {
132+
) -> Result<Json<TurnStatus>, Error> {
129133
let game = state.lock().unwrap().games.get(&user.name).map(Arc::clone);
130134

131135
if game.is_none() {
@@ -136,9 +140,12 @@ pub async fn play(
136140
let mut lock = game.lock().await;
137141

138142
lock.play_human(moves.into_inner()).await?;
139-
lock.play_ai().await?;
143+
let output = lock.play_ai().await?;
140144

141-
Ok(Json(lock.checkers.clone()))
145+
Ok(Json(TurnStatus {
146+
game: lock.checkers.clone(),
147+
ai_output: output,
148+
}))
142149
}
143150

144151
#[post("/game/stop")]

backend/src/game.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,23 @@ fn default_board() -> Board {
7979
board
8080
}
8181

82+
#[derive(Debug, Serialize, Clone)]
83+
pub struct TurnStatus {
84+
pub game: GameState,
85+
pub ai_output: String,
86+
}
87+
8288
#[derive(Debug, Serialize, Clone)]
8389
pub struct GameState {
8490
pub board: Board,
8591
pub current_player: Player,
86-
pub ai_output: String,
8792
}
8893

8994
impl Default for GameState {
9095
fn default() -> Self {
9196
Self {
9297
board: default_board(),
9398
current_player: Player::White,
94-
ai_output: Default::default(),
9599
}
96100
}
97101
}

0 commit comments

Comments
 (0)