Initial commit
This commit is contained in:
commit
4148ec387b
11 changed files with 471529 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "word-engine"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
|
serde_json = "1.0.106"
|
||||||
|
thiserror = "1.0.48"
|
135
bag.json
Normal file
135
bag.json
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
{
|
||||||
|
"blank_tiles" : 2,
|
||||||
|
"tiles": [
|
||||||
|
{
|
||||||
|
"letter": "E",
|
||||||
|
"value": 1,
|
||||||
|
"count": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "A",
|
||||||
|
"value": 1,
|
||||||
|
"count": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "I",
|
||||||
|
"value": 1,
|
||||||
|
"count": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "O",
|
||||||
|
"value": 1,
|
||||||
|
"count": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "N",
|
||||||
|
"value": 1,
|
||||||
|
"count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "R",
|
||||||
|
"value": 1,
|
||||||
|
"count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "T",
|
||||||
|
"value": 1,
|
||||||
|
"count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "L",
|
||||||
|
"value": 1,
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "S",
|
||||||
|
"value": 1,
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "U",
|
||||||
|
"value": 1,
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "D",
|
||||||
|
"value": 2,
|
||||||
|
"count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "G",
|
||||||
|
"value": 2,
|
||||||
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "B",
|
||||||
|
"value": 3,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "C",
|
||||||
|
"value": 3,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "M",
|
||||||
|
"value": 3,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "P",
|
||||||
|
"value": 3,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "F",
|
||||||
|
"value": 4,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "H",
|
||||||
|
"value": 4,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "V",
|
||||||
|
"value": 4,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "W",
|
||||||
|
"value": 4,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "Y",
|
||||||
|
"value": 4,
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "K",
|
||||||
|
"value": 5,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "J",
|
||||||
|
"value": 8,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "X",
|
||||||
|
"value": 8,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "Q",
|
||||||
|
"value": 10,
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"letter": "Z",
|
||||||
|
"value": 10,
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
279077
lexicons/CSW22.txt
Normal file
279077
lexicons/CSW22.txt
Normal file
File diff suppressed because it is too large
Load diff
191852
lexicons/NWL2020.txt
Normal file
191852
lexicons/NWL2020.txt
Normal file
File diff suppressed because it is too large
Load diff
73
src/baggy.rs
Normal file
73
src/baggy.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::data::BagData;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum BagError {
|
||||||
|
#[error("Not enough tiles")]
|
||||||
|
NotEnoughTiles,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Tile {
|
||||||
|
letter: char,
|
||||||
|
value: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
pub fn letter(&self) -> char {
|
||||||
|
self.letter
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> u8 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Bag {
|
||||||
|
tiles: Vec<Tile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bag {
|
||||||
|
pub fn take(&mut self, count: usize) -> Result<Bag, BagError> {
|
||||||
|
if count > self.tiles.len() {
|
||||||
|
return Err(BagError::NotEnoughTiles);
|
||||||
|
}
|
||||||
|
let mut tiles = Vec::new();
|
||||||
|
for _ in 0..count {
|
||||||
|
let random_tile = self
|
||||||
|
.tiles
|
||||||
|
.remove(rand::random::<usize>() % self.tiles.len());
|
||||||
|
tiles.push(random_tile);
|
||||||
|
}
|
||||||
|
Ok(Bag { tiles })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BagData> for Bag {
|
||||||
|
fn from(data: BagData) -> Self {
|
||||||
|
let mut tiles = Vec::new();
|
||||||
|
for tile in data.tiles() {
|
||||||
|
for _ in 0..tile.count() {
|
||||||
|
tiles.push(Tile {
|
||||||
|
letter: tile.letter(),
|
||||||
|
value: tile.value(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bag { tiles }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Bag {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Bag {{ tiles: [")?;
|
||||||
|
for tile in &self.tiles {
|
||||||
|
write!(f, "{}, ", tile.letter)?;
|
||||||
|
}
|
||||||
|
write!(f, "] }}")
|
||||||
|
}
|
||||||
|
}
|
183
src/board.rs
Normal file
183
src/board.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{baggy::Tile, dictionary::Dictionary};
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum MoveError {
|
||||||
|
#[error("Out of bounds")]
|
||||||
|
OutOfBounds,
|
||||||
|
#[error("Occupied")]
|
||||||
|
Occupied,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum BoardError {
|
||||||
|
#[error("Invalid space")]
|
||||||
|
MoveError(#[from] MoveError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MoveResult {
|
||||||
|
Valid(u32),
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
pub enum SpaceKind {
|
||||||
|
#[default]
|
||||||
|
Normal,
|
||||||
|
Start,
|
||||||
|
DoubleLetter,
|
||||||
|
TripleLetter,
|
||||||
|
DoubleWord,
|
||||||
|
TripleWord,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
|
pub struct Space {
|
||||||
|
pub kind: SpaceKind,
|
||||||
|
pub tile: Option<Tile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
struct Move {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
tile: Tile,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Board {
|
||||||
|
board: Vec<Vec<Space>>,
|
||||||
|
pending_move: Vec<Move>,
|
||||||
|
dictionary: Dictionary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
pub fn new(dictionary: Dictionary) -> Board {
|
||||||
|
let mut board = vec![vec![Space::default(); 15]; 15];
|
||||||
|
|
||||||
|
// Start space
|
||||||
|
board[7][7].kind = SpaceKind::Start;
|
||||||
|
|
||||||
|
// Triple word spaces
|
||||||
|
board[0][0].kind = SpaceKind::TripleWord;
|
||||||
|
board[0][7].kind = SpaceKind::TripleWord;
|
||||||
|
board[0][14].kind = SpaceKind::TripleWord;
|
||||||
|
board[7][0].kind = SpaceKind::TripleWord;
|
||||||
|
board[7][14].kind = SpaceKind::TripleWord;
|
||||||
|
board[14][0].kind = SpaceKind::TripleWord;
|
||||||
|
board[14][7].kind = SpaceKind::TripleWord;
|
||||||
|
board[14][14].kind = SpaceKind::TripleWord;
|
||||||
|
|
||||||
|
// Double word spaces
|
||||||
|
board[1][1].kind = SpaceKind::DoubleWord;
|
||||||
|
board[2][2].kind = SpaceKind::DoubleWord;
|
||||||
|
board[3][3].kind = SpaceKind::DoubleWord;
|
||||||
|
board[4][4].kind = SpaceKind::DoubleWord;
|
||||||
|
board[10][10].kind = SpaceKind::DoubleWord;
|
||||||
|
board[11][11].kind = SpaceKind::DoubleWord;
|
||||||
|
board[12][12].kind = SpaceKind::DoubleWord;
|
||||||
|
board[13][13].kind = SpaceKind::DoubleWord;
|
||||||
|
board[1][13].kind = SpaceKind::DoubleWord;
|
||||||
|
board[2][12].kind = SpaceKind::DoubleWord;
|
||||||
|
board[3][11].kind = SpaceKind::DoubleWord;
|
||||||
|
board[4][10].kind = SpaceKind::DoubleWord;
|
||||||
|
board[10][4].kind = SpaceKind::DoubleWord;
|
||||||
|
board[11][3].kind = SpaceKind::DoubleWord;
|
||||||
|
board[12][2].kind = SpaceKind::DoubleWord;
|
||||||
|
board[13][1].kind = SpaceKind::DoubleWord;
|
||||||
|
|
||||||
|
// Triple letter spaces
|
||||||
|
board[1][5].kind = SpaceKind::TripleLetter;
|
||||||
|
board[1][9].kind = SpaceKind::TripleLetter;
|
||||||
|
board[5][1].kind = SpaceKind::TripleLetter;
|
||||||
|
board[5][5].kind = SpaceKind::TripleLetter;
|
||||||
|
board[5][9].kind = SpaceKind::TripleLetter;
|
||||||
|
board[5][13].kind = SpaceKind::TripleLetter;
|
||||||
|
board[9][1].kind = SpaceKind::TripleLetter;
|
||||||
|
board[9][5].kind = SpaceKind::TripleLetter;
|
||||||
|
board[9][9].kind = SpaceKind::TripleLetter;
|
||||||
|
board[9][13].kind = SpaceKind::TripleLetter;
|
||||||
|
board[13][5].kind = SpaceKind::TripleLetter;
|
||||||
|
board[13][9].kind = SpaceKind::TripleLetter;
|
||||||
|
|
||||||
|
// Double letter spaces
|
||||||
|
board[0][3].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[0][11].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[2][6].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[2][8].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[3][0].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[3][7].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[3][14].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[6][2].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[6][6].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[6][8].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[6][12].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[7][3].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[7][11].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[8][2].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[8][6].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[8][8].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[8][12].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[11][0].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[11][7].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[11][14].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[12][6].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[12][8].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[14][3].kind = SpaceKind::DoubleLetter;
|
||||||
|
board[14][11].kind = SpaceKind::DoubleLetter;
|
||||||
|
|
||||||
|
Board {
|
||||||
|
board,
|
||||||
|
pending_move: Vec::new(),
|
||||||
|
dictionary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_space_for_move(&self) -> Result<(), MoveError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn place_tile(&mut self, x: usize, y: usize, tile: Tile) -> Result<(), BoardError> {
|
||||||
|
self.check_space_for_move()?;
|
||||||
|
self.pending_move.push(Move { x, y, tile });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_move(&self) -> MoveResult {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit_move() -> MoveResult {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print the board as a grid
|
||||||
|
impl std::fmt::Display for Board {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "Board {{")?;
|
||||||
|
for row in &self.board {
|
||||||
|
write!(f, " [")?;
|
||||||
|
let mut row = row.iter().peekable();
|
||||||
|
while let Some(space) = row.next() {
|
||||||
|
match space.tile {
|
||||||
|
Some(tile) => write!(f, "{}", tile.letter())?,
|
||||||
|
None => match space.kind {
|
||||||
|
SpaceKind::Normal => write!(f, "■")?,
|
||||||
|
SpaceKind::Start => write!(f, "☆")?,
|
||||||
|
SpaceKind::DoubleLetter => write!(f, "2")?,
|
||||||
|
SpaceKind::TripleLetter => write!(f, "3")?,
|
||||||
|
SpaceKind::DoubleWord => write!(f, "②")?,
|
||||||
|
SpaceKind::TripleWord => write!(f, "③")?,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if row.peek().is_some() {
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f, "]")?;
|
||||||
|
}
|
||||||
|
write!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
37
src/data.rs
Normal file
37
src/data.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TileData {
|
||||||
|
letter: char,
|
||||||
|
value: u8,
|
||||||
|
count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TileData {
|
||||||
|
pub fn letter(&self) -> char {
|
||||||
|
self.letter
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> u8 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count(&self) -> u8 {
|
||||||
|
self.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct BagData {
|
||||||
|
tiles: Vec<TileData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BagData {
|
||||||
|
pub fn load_from_json(json: &str) -> serde_json::Result<Self> {
|
||||||
|
serde_json::from_str(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tiles(&self) -> &Vec<TileData> {
|
||||||
|
&self.tiles
|
||||||
|
}
|
||||||
|
}
|
42
src/dictionary.rs
Normal file
42
src/dictionary.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use crate::baggy::Tile;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Word {
|
||||||
|
tiles: Vec<Tile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Word {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for tile in &self.tiles {
|
||||||
|
write!(f, "{}", tile.letter())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Dictionary {
|
||||||
|
words: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dictionary {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let words = include_str!("../lexicons/CSW22.txt");
|
||||||
|
Dictionary {
|
||||||
|
words: words.lines().map(|x| x.to_string()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a word is in the dictionary
|
||||||
|
pub fn contains(&self, word: Word) -> bool {
|
||||||
|
self.words.contains(&word.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Dictionary {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
83
src/lib.rs
Normal file
83
src/lib.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
use player::PlayerId;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
mod baggy;
|
||||||
|
mod board;
|
||||||
|
mod data;
|
||||||
|
mod dictionary;
|
||||||
|
mod player;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum GameError {
|
||||||
|
#[error("Not enough tiles in bag")]
|
||||||
|
NotEnoughTiles(#[from] baggy::BagError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Game {
|
||||||
|
board: board::Board,
|
||||||
|
bag: baggy::Bag,
|
||||||
|
players: Vec<player::Player>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn new() -> Game {
|
||||||
|
let bag_data = data::BagData::load_from_json(include_str!("../bag.json")).unwrap();
|
||||||
|
let bag = baggy::Bag::from(bag_data);
|
||||||
|
let dictionary = dictionary::Dictionary::new();
|
||||||
|
Game {
|
||||||
|
board: board::Board::new(dictionary),
|
||||||
|
bag,
|
||||||
|
players: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn players(&self) -> &Vec<player::Player> {
|
||||||
|
&self.players
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bag(&self) -> &baggy::Bag {
|
||||||
|
&self.bag
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn board(&self) -> &board::Board {
|
||||||
|
&self.board
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_player(&mut self) -> Result<PlayerId, GameError> {
|
||||||
|
let id = PlayerId(self.players.len() as u32);
|
||||||
|
self.players
|
||||||
|
.push(player::Player::new(id, self.bag.take(7)?));
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_players(&mut self, count: usize) -> Result<Vec<PlayerId>, GameError> {
|
||||||
|
let mut ids = Vec::new();
|
||||||
|
for _ in 0..count {
|
||||||
|
ids.push(self.add_player()?);
|
||||||
|
}
|
||||||
|
Ok(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Game {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::Game;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_game() {
|
||||||
|
let mut game = Game::new();
|
||||||
|
game.add_players(2).unwrap();
|
||||||
|
for player in game.players() {
|
||||||
|
println!("Player bag: {}", player.bag());
|
||||||
|
}
|
||||||
|
println!("Game bag: {}", game.bag());
|
||||||
|
println!("Game board: {}", game.board());
|
||||||
|
}
|
||||||
|
}
|
33
src/player.rs
Normal file
33
src/player.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::baggy::Bag;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct PlayerId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Player {
|
||||||
|
id: PlayerId,
|
||||||
|
score: u32,
|
||||||
|
bag: Bag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
pub fn new(id: PlayerId, bag: Bag) -> Self {
|
||||||
|
Player { id, score: 0, bag }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> PlayerId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn score(&self) -> u32 {
|
||||||
|
self.score
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bag(&self) -> &Bag {
|
||||||
|
&self.bag
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn give_points(&mut self, points: u32) {
|
||||||
|
self.score = self.score.saturating_add(points);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue