Only return board from Poll, add optional PieceKind to Move
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
Aode (lion) 2022-01-07 22:09:24 -06:00
parent 6010d16cd4
commit 8f52495788
3 changed files with 56 additions and 72 deletions

View file

@ -34,13 +34,7 @@ pub(crate) struct Move {
pub(crate) piece: Piece,
pub(crate) from: Coordinates,
pub(crate) to: Coordinates,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Promote {
pub(crate) location: Coordinates,
pub(crate) kind: PieceKind,
pub(crate) kind: Option<PieceKind>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
@ -63,6 +57,25 @@ pub(crate) struct GameStart {
pub(crate) game_id: GameId,
}
#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct PollResponse {
pub(crate) board: Vec<(File, Rank, PieceKind, Color)>,
pub(crate) game_state: GameState,
}
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
)]
#[serde(rename_all = "camelCase")]
pub(crate) enum GameState {
White,
Black,
Win,
Lose,
Draw,
}
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
)]
@ -131,6 +144,15 @@ impl GameId {
}
}
impl GameState {
pub(crate) fn from_color(color: Color) -> Self {
match color {
Color::White => GameState::White,
Color::Black => GameState::Black,
}
}
}
impl Color {
pub(crate) fn opposite(&self) -> Self {
match self {
@ -198,6 +220,12 @@ impl File {
}
}
impl Default for Color {
fn default() -> Self {
Color::White
}
}
impl std::fmt::Display for GameId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.inner, f)

View file

@ -1,7 +1,7 @@
use crate::api_types::{
self,
Color::{self, White},
Coordinates, Move, PieceKind,
Coordinates, Move, PieceKind, PollResponse,
};
use std::{
cell::RefCell,
@ -266,6 +266,7 @@ pub(crate) struct GameState {
visible: HashMap<Color, HashSet<Position>>,
en_passant_target: Option<Position>,
castle: HashMap<Color, CastleState>,
allowed_turn: Color,
}
impl GameState {
@ -303,10 +304,9 @@ impl GameState {
this
}
pub(crate) fn to_serializable(
&self,
) -> Vec<(api_types::File, api_types::Rank, PieceKind, Color)> {
self.board
pub(crate) fn to_serializable(&self) -> PollResponse {
let board = self
.board
.iter()
.map(|(pos, piece)| {
(
@ -316,7 +316,11 @@ impl GameState {
piece.color.clone(),
)
})
.collect()
.collect();
let game_state = api_types::GameState::from_color(self.allowed_turn.clone());
PollResponse { board, game_state }
}
fn generate_visible(&mut self) {
@ -451,7 +455,8 @@ impl GameState {
.clone();
if piece.get_possible_moves(&from_pos, self).contains(&to_pos) {
self.apply_move(from_pos, to_pos)
self.apply_move(from_pos, to_pos);
self.allowed_turn = self.allowed_turn.opposite();
}
}
}

View file

@ -19,29 +19,12 @@ mod board_state;
mod init_tracing;
mod long_poller;
use api_types::{ApiMessage, GameId, GameStart, Move, Promote, Start};
use api_types::{ApiMessage, GameId, GameStart, Move, Start};
use long_poller::LongPoller;
#[derive(Debug)]
struct Reply {
board_state: board_state::GameState,
}
#[derive(Debug)]
enum Action {
Move(Move),
Promote(Promote),
}
#[derive(Debug)]
struct Session {
action: Action,
reply: tokio::sync::oneshot::Sender<Reply>,
}
#[derive(Clone)]
struct GameData {
sender: Sender<Session>,
sender: Sender<Move>,
poller: Arc<LongPoller<board_state::GameState>>,
}
@ -115,18 +98,10 @@ async fn start(Json(_start): Json<Start>, game_state: Data<GameState>) -> HttpRe
actix_web::rt::spawn(
async move {
while let Ok(Some(msg)) =
while let Ok(Some(action)) =
actix_web::rt::time::timeout(Duration::from_secs(60 * 5), rx.recv()).await
{
match msg.action {
Action::Move(action) => board_state.handle(action),
Action::Promote(_) => unimplemented!(),
}
let _ = msg.reply.send(Reply {
board_state: board_state.clone(),
});
board_state.handle(action);
poller.update(board_state.clone());
}
@ -136,47 +111,24 @@ async fn start(Json(_start): Json<Start>, game_state: Data<GameState>) -> HttpRe
);
HttpResponse::Ok().json(GameStart {
board: serializable,
board: serializable.board,
game_id,
})
}
#[tracing::instrument]
async fn make_move(
Json(action): Json<ApiMessage<Move>>,
Json(message): Json<ApiMessage<Move>>,
game_state: Data<GameState>,
) -> HttpResponse {
send_message(action.game_id, Action::Move(action.data), game_state).await
}
#[tracing::instrument]
async fn promote_pawn(
Json(action): Json<ApiMessage<Promote>>,
game_state: Data<GameState>,
) -> HttpResponse {
send_message(action.game_id, Action::Promote(action.data), game_state).await
}
#[tracing::instrument]
async fn send_message(
game_id: GameId,
action: Action,
game_state: Data<GameState>,
) -> HttpResponse {
if let Some(data) = game_state.data_for_id(&game_id) {
let (reply, rx) = tokio::sync::oneshot::channel();
let res = data.sender.send(Session { action, reply }).await;
if let Some(data) = game_state.data_for_id(&message.game_id) {
let res = data.sender.send(message.data).await;
if res.is_err() {
return HttpResponse::InternalServerError().finish();
}
if let Ok(reply) = rx.await {
return HttpResponse::Ok().json(reply.board_state.to_serializable());
}
return HttpResponse::InternalServerError().finish();
return HttpResponse::Accepted().finish();
}
HttpResponse::BadRequest().finish()
@ -215,7 +167,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
)
.route("/start", actix_web::web::post().to(start))
.route("/move", actix_web::web::post().to(make_move))
.route("/promote", actix_web::web::post().to(promote_pawn))
.route("/poll/{id}", actix_web::web::get().to(long_poll))
})
.bind("0.0.0.0:8000")?