Set up a per-game interpretation layer atop the SGF, and bind all games together in a Game
data structure #49
|
@ -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) => {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
Loading…
Reference in New Issue