Skip to content

Commit

Permalink
refactor: move reversi move to general move
Browse files Browse the repository at this point in the history
  • Loading branch information
LeoDog896 committed May 28, 2024
1 parent 9cdda7f commit 52e6a1c
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 58 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/games/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ array2d = "0.3"
ndarray = "0.15"
itertools = "0.13"
clap = { version = "4.5", features = ["derive"] }
ordinal = "0.3.2"
2 changes: 2 additions & 0 deletions crates/games/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod util;

pub mod chomp;
pub mod domineering;
pub mod nim;
Expand Down
4 changes: 2 additions & 2 deletions crates/games/src/reversi/cli.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt;

use clap::Args;
use crate::reversi::{Reversi, ReversiMove};
use crate::{reversi::{Reversi, ReversiMove}, util::move_natural::NaturalMove};
use game_solver::{game::{Game, ZeroSumPlayer}, par_move_scores};

use super::{HEIGHT, WIDTH};
Expand Down Expand Up @@ -29,7 +29,7 @@ impl fmt::Display for Reversi {

for y in 0..HEIGHT {
for x in 0..WIDTH {
let character = if moves.contains(&ReversiMove((x, y))) {
let character = if moves.contains(&NaturalMove([x, y])) {
'*'
} else {
player_to_char(*self.board.get(x, y).unwrap())
Expand Down
23 changes: 12 additions & 11 deletions crates/games/src/reversi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
//!
//! More information: <https://en.wikipedia.org/wiki/Reversi>
pub mod mv;
pub mod cli;

use array2d::Array2D;
use game_solver::game::{Game, ZeroSumPlayer};
use std::hash::Hash;

use self::mv::ReversiMove;
use crate::util::move_natural::NaturalMove;

pub const WIDTH: usize = 6;
pub const HEIGHT: usize = 6;

pub type ReversiMove = NaturalMove<2>;

#[derive(Clone, Hash, Eq, PartialEq)]
struct Reversi {
/// None if empty, Some(Player) if occupied
Expand Down Expand Up @@ -51,7 +52,7 @@ impl Reversi {
}

fn is_valid_move(&self, m: &<Self as Game>::Move) -> Option<Vec<<Self as Game>::Move>> {
let cell = *self.board.get(m.0.0, m.0.1).unwrap();
let cell = *self.board.get(m.0[0], m.0[1]).unwrap();

if cell.is_some() {
return None;
Expand All @@ -73,8 +74,8 @@ impl Reversi {
];

for (x_dir, y_dir) in directions {
let mut x = m.0.0;
let mut y = m.0.1;
let mut x = m.0[0];
let mut y = m.0[1];

x = x.wrapping_add_signed(*x_dir);
y = y.wrapping_add_signed(*y_dir);
Expand Down Expand Up @@ -104,11 +105,11 @@ impl Reversi {
x = x.checked_add_signed(-*x_dir).unwrap();
y = y.checked_add_signed(-*y_dir).unwrap();

if x == m.0.0 && y == m.0.1 {
if x == m.0[0] && y == m.0[1] {
break;
}

tiles_to_flip.push(ReversiMove((x, y)));
tiles_to_flip.push(NaturalMove([x, y]));
}
}
}
Expand Down Expand Up @@ -166,10 +167,10 @@ impl Game for Reversi {
fn make_move(&mut self, m: &Self::Move) -> bool {
let move_set = self.is_valid_move(m).unwrap();

self.board.set(m.0.0, m.0.1, Some(self.player())).unwrap();
self.board.set(m.0[0], m.0[1], Some(self.player())).unwrap();

for idx in move_set {
self.board.set(idx.0.0, idx.0.1, Some(self.player())).unwrap();
self.board.set(idx.0[0], idx.0[1], Some(self.player())).unwrap();
}

self.move_count += 1;
Expand All @@ -181,8 +182,8 @@ impl Game for Reversi {
let mut moves = Vec::new();
for x in 0..WIDTH {
for y in 0..HEIGHT {
if self.is_valid_move(&ReversiMove((x, y))).is_some() {
moves.push(ReversiMove((x, y)));
if self.is_valid_move(&NaturalMove([x, y])).is_some() {
moves.push(NaturalMove([x, y]));
}
}
}
Expand Down
45 changes: 0 additions & 45 deletions crates/games/src/reversi/mv.rs

This file was deleted.

1 change: 1 addition & 0 deletions crates/games/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod move_natural;
48 changes: 48 additions & 0 deletions crates/games/src/util/move_natural.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// TODO: make generic as some n-tuple move (macro generation / dynamic type?)

use std::{fmt::Display, iter, str::FromStr};

use itertools::Itertools;

#[derive(Clone, Debug, Copy, PartialEq)]
pub struct NaturalMove<const LENGTH: usize>(pub [usize; LENGTH]);

impl<const LENGTH: usize> FromStr for NaturalMove<LENGTH> {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
assert!(LENGTH > 0, "Length must be greater than 0");

let numbers = s.split("-").collect::<Vec<_>>();

if numbers.len() != LENGTH {
return Err(
format!(
"Must be {} numbers separated by a hyphen ({})",
LENGTH,
iter::repeat("x").take(LENGTH).join("-")
)
);
}

let numbers = numbers.iter()
.map(|num| num.parse::<usize>())
.collect::<Vec<_>>();

if let Some((position, _)) = numbers.iter().find_position(|x| x.is_err()) {
let ordinal = ordinal::Ordinal(position + 1).to_string();

return Err(format!("The {} number is not a number.", ordinal));
}

numbers.iter().map(|x| x.clone().unwrap()).collect::<Vec<_>>().try_into()
.map_err(|_| "Could not convert Vec to fixed array; this is a bug.".to_string())
.map(|x| NaturalMove(x))
}
}

impl<const LENGTH: usize> Display for NaturalMove<LENGTH> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.iter().join("-"))
}
}

0 comments on commit 52e6a1c

Please sign in to comment.