-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
417 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "lib-tic-tac-toe" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["P. Todd Decker <[email protected]>"] | ||
|
||
[dependencies] | ||
rand = "0.9.0-alpha.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,12 @@ | ||
# lib-tic-tac-toe | ||
Rust-based Tic-Tac-Toe Library | ||
# Rust-based Tic-Tac-Toe Library (lib-tic-tac-toe) | ||
|
||
This is a Rust-based Tic-Tac-Toe library meant to be incorporated into various | ||
Tic-Tac-Toe game implementations. | ||
|
||
## no_std Compatibility | ||
|
||
This library is designed to be compatible with no_std environments. It does not | ||
require the Rust standard library (std) and depends only on the core allocation | ||
(alloc) library for memory management tasks. This makes it suitable for use in | ||
bare-metal, embedded, or other high-performance or resource-constrained | ||
environments. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
//! Tic-Tac-Toe Game Board | ||
|
||
use super::*; | ||
|
||
use crate::mark::Mark; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
#[repr(transparent)] | ||
pub(crate) struct Space(u8); | ||
|
||
impl TryFrom<u8> for Space { | ||
type Error = Error; | ||
|
||
fn try_from(value: u8) -> Result<Self, Self::Error> { | ||
if value > 8 { | ||
Err(Error::InvalidSpace) | ||
} else { | ||
Ok(Space(value)) | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
pub(crate) struct Board { | ||
spaces: [Mark; 9], | ||
} | ||
|
||
impl Board { | ||
pub(crate) fn new() -> Self { | ||
Board { | ||
spaces: [Mark::Blank; 9], | ||
} | ||
} | ||
|
||
fn random() -> Self { | ||
let mut rng = rand::thread_rng(); | ||
let spaces: [Mark; 9] = rng.gen(); | ||
Board { spaces } | ||
} | ||
|
||
pub(crate) fn mark(&mut self, space: Space, mark: Mark) -> Result<(), Error> { | ||
self.spaces[space.0 as usize] = mark; | ||
Ok(()) | ||
} | ||
|
||
fn get(&self, space: Space) -> Result<Mark, Error> { | ||
Ok(self.spaces[space.0 as usize]) | ||
} | ||
} | ||
|
||
impl fmt::Display for Board { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
let lines = [(0, 1, 2), (3, 4, 5), (6, 7, 8)]; | ||
|
||
for (i, line) in lines.iter().enumerate() { | ||
if i > 0 { | ||
writeln!(f, "---+---+---")?; | ||
} | ||
writeln!( | ||
f, | ||
" {} | {} | {} ", | ||
self.spaces[line.0], self.spaces[line.1], self.spaces[line.2] | ||
)?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn blank_board_display() { | ||
let board_display = alloc::format!("{}", Board::new()); | ||
let expected_display = " | | \n---+---+---\n | | \n---+---+---\n | | \n"; | ||
assert_eq!(board_display, expected_display); | ||
} | ||
|
||
#[test] | ||
fn random_boards_not_equal() { | ||
assert_ne!(Board::random(), Board::random()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
//! Tic-Tac-Toe Errors | ||
|
||
use super::*; | ||
|
||
#[derive(Debug, Clone)] | ||
pub enum Error { | ||
InvalidSpace, | ||
InvalidMove, | ||
HistoryFull, | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match self { | ||
Error::InvalidSpace => write!(f, "invalid space"), | ||
Error::InvalidMove => write!(f, "invalid move"), | ||
Error::HistoryFull => write!(f, "game history full"), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//! Tic-Tac-Toe Game | ||
|
||
use super::*; | ||
|
||
use crate::{ | ||
board::Board, | ||
history::History, | ||
mark::Mark, | ||
}; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
struct Game { | ||
turn: Mark, | ||
board: Board, | ||
history: History, | ||
} | ||
|
||
impl Game { | ||
pub fn new() -> Self { | ||
Self { | ||
turn: Mark::X, | ||
board: Board::new(), | ||
history: History::new(), | ||
} | ||
} | ||
pub fn mark(&mut self, space: u8) -> Result<(), Error> { | ||
let space = space.try_into()?; | ||
self.board.mark(space, self.turn)?; | ||
self.history.add(space)?; | ||
self.turn.next(); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//! Tic-Tac-Toe History | ||
|
||
use super::*; | ||
|
||
use crate::board::Space; | ||
|
||
const MAX_HISTORY_SIZE: usize = 9; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | ||
#[repr(transparent)] | ||
pub(crate) struct History((u8, [Option<Space>; MAX_HISTORY_SIZE])); | ||
|
||
impl History { | ||
pub(crate) fn new() -> Self { | ||
History((0u8, [None; MAX_HISTORY_SIZE])) | ||
} | ||
fn len(&self) -> usize { | ||
self.0 .0 as usize | ||
} | ||
pub(crate) fn add(&mut self, space: Space) -> Result<(), Error> { | ||
if self.0 .0 as usize == MAX_HISTORY_SIZE { | ||
return Err(Error::HistoryFull); | ||
}; | ||
self.0 .0 += 1; | ||
self.0 .1[self.0 .0 as usize] = Some(space); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//! Tic-Tac-Toe Library | ||
#![no_std] | ||
#![allow(dead_code)] | ||
|
||
extern crate alloc; | ||
|
||
mod board; | ||
mod error; | ||
mod game; | ||
mod history; | ||
mod mark; | ||
|
||
use core::fmt; | ||
use rand::{ | ||
distributions::{Distribution, Standard}, | ||
Rng, | ||
}; | ||
|
||
pub use error::Error; |
Oops, something went wrong.