Set up a per-game interpretation layer atop the SGF, and bind all games together in a Game data structure #49

Merged
savanni merged 6 commits from feature/sgf-interpretation-layer into main 2023-07-27 22:20:24 +00:00
4 changed files with 20 additions and 14 deletions
Showing only changes of commit 92ca170a24 - Show all commits

View File

@ -1,6 +1,6 @@
use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf}; use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf};
use sgf::{parse_sgf, GameTree}; use sgf::{go, parse_sgf, Game};
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -20,12 +20,12 @@ impl From<std::io::Error> for Error {
#[derive(Debug)] #[derive(Debug)]
pub struct Database { pub struct Database {
path: PathBuf, path: PathBuf,
games: Vec<GameTree>, games: Vec<go::Game>,
} }
impl Database { impl Database {
pub fn open_path(path: PathBuf) -> Result<Database, Error> { pub fn open_path(path: PathBuf) -> Result<Database, Error> {
let mut games: Vec<GameTree> = Vec::new(); let mut games: Vec<go::Game> = Vec::new();
let extension = PathBuf::from("sgf").into_os_string(); let extension = PathBuf::from("sgf").into_os_string();
@ -39,8 +39,12 @@ impl Database {
.unwrap() .unwrap()
.read_to_string(&mut buffer) .read_to_string(&mut buffer)
.unwrap(); .unwrap();
let sgf = parse_sgf(&buffer).unwrap(); for sgf in parse_sgf(&buffer).unwrap() {
games.extend(sgf); match sgf {
Game::Go(game) => games.push(game),
Game::Unsupported(_) => {}
}
}
} }
} }
Err(err) => println!("failed entry: {:?}", err), Err(err) => println!("failed entry: {:?}", err),
@ -54,7 +58,7 @@ impl Database {
self.games.len() self.games.len()
} }
pub fn all_games(&self) -> impl Iterator<Item = &GameTree> { pub fn all_games(&self) -> impl Iterator<Item = &go::Game> {
self.games.iter() self.games.iter()
} }
} }
@ -63,7 +67,7 @@ impl Database {
mod test { mod test {
use super::*; use super::*;
use cool_asserts::assert_matches; use cool_asserts::assert_matches;
use sgf::{Date, GameType}; use sgf::Date;
#[test] #[test]
fn it_reads_empty_database() { fn it_reads_empty_database() {
@ -77,9 +81,7 @@ mod test {
let db = let db =
Database::open_path(PathBuf::from("fixtures/five_games/")).expect("database to open"); Database::open_path(PathBuf::from("fixtures/five_games/")).expect("database to open");
assert_eq!(db.all_games().count(), 5); assert_eq!(db.all_games().count(), 5);
for game in db.all_games() { for game in db.all_games() {}
assert_eq!(game.game_type, GameType::Go);
}
assert_matches!(db.all_games().find(|g| g.info.black_player == Some("Steve".to_owned())), assert_matches!(db.all_games().find(|g| g.info.black_player == Some("Steve".to_owned())),
Some(game) => { Some(game) => {

View File

@ -1,5 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sgf::{Date, GameTree, Rank}; use sgf::{
go::{Game, Rank},
Date,
};
use typeshare::typeshare; use typeshare::typeshare;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
@ -13,7 +16,7 @@ pub struct GamePreviewElement {
} }
impl GamePreviewElement { impl GamePreviewElement {
pub fn new(game: &GameTree) -> GamePreviewElement { pub fn new(game: &Game) -> GamePreviewElement {
GamePreviewElement { GamePreviewElement {
date: game.info.date.clone(), date: game.info.date.clone(),
black_player: game black_player: game

View File

@ -1,6 +1,6 @@
use crate::ui::{Action, GamePreviewElement}; use crate::ui::{Action, GamePreviewElement};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sgf::GameTree; use sgf::go::Game;
use typeshare::typeshare; use typeshare::typeshare;
fn rank_strings() -> Vec<String> { fn rank_strings() -> Vec<String> {
@ -56,7 +56,7 @@ pub struct HomeView {
pub start_game: Action<()>, pub start_game: Action<()>,
} }
pub fn home<'a>(games: impl Iterator<Item = &'a GameTree>) -> HomeView { pub fn home<'a>(games: impl Iterator<Item = &'a Game>) -> HomeView {
let black_player = PlayerElement::Hotseat(HotseatPlayerElement { let black_player = PlayerElement::Hotseat(HotseatPlayerElement {
placeholder: Some("black player".to_owned()), placeholder: Some("black player".to_owned()),
default_rank: None, default_rank: None,

View File

@ -76,6 +76,7 @@ use crate::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typeshare::typeshare; use typeshare::typeshare;
#[derive(Clone, Debug)]
pub struct Game { pub struct Game {
pub file_format: i8, pub file_format: i8,
pub app_name: Option<String>, pub app_name: Option<String>,