Implement the basic rules of Go #40

Merged
savanni merged 13 commits from feature/go-rules into main 2023-05-04 02:34:40 +00:00
2 changed files with 23 additions and 79 deletions
Showing only changes of commit d68e088500 - Show all commits

View File

@ -2,9 +2,10 @@ use crate::{Color, Size};
use grid::Grid;
use std::collections::HashSet;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
InvalidPosition,
SelfCapture,
}
#[derive(Clone, Debug)]
@ -69,6 +70,8 @@ impl Board {
return Err(Error::InvalidPosition);
}
let old_groups = self.groups.clone();
let mut friendly_group = self
.adjacencies(&coordinate)
.into_iter()
@ -95,6 +98,11 @@ impl Board {
}
}
if self.liberties(&friendly_group) == 0 {
self.groups = old_groups;
return Err(Error::SelfCapture);
}
Ok(())
}
@ -117,13 +125,11 @@ impl Board {
pub fn adjacent_groups(&self, group: &Group) -> Vec<Group> {
let adjacent_spaces = self.group_halo(group).into_iter();
println!("adjacent spaces: {:?}", adjacent_spaces);
let mut grps: Vec<Group> = Vec::new();
adjacent_spaces.for_each(|coord| match self.group(&coord) {
None => return,
Some(adj) => {
println!("group found: {:?}", adj.color);
if group.color == adj.color {
return;
}
@ -151,32 +157,6 @@ impl Board {
.into_iter()
.filter(|c| self.stone(&c) == None)
.count()
// let adjacencies: HashSet<Coordinate> = self.adjacencies(group.coordinates.iter()).collect();
/*
println!("adjacencies: {:?}", adjacencies);
let opposing_spaces = adjacencies
.iter()
.filter(|coord| match self.grid.get(coord.row, coord.column) {
None => true,
Some(&None) => false,
Some(&Some(c)) => c != group.color,
})
.cloned()
.collect::<HashSet<Coordinate>>();
println!("opposition: {:?}", opposing_spaces);
adjacencies.len() - opposing_spaces.len()
*/
/*
group
.adjacencies(self.size.width as u8 - 1, self.size.height as u8 - 1)
.into_iter()
.filter(|coordinate| self.stone(*coordinate).is_none())
.collect::<Vec<Coordinate>>()
.len()
*/
}
pub fn adjacencies(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
@ -204,41 +184,6 @@ impl Board {
v.into_iter().filter(|c| self.within_board(c)).collect()
}
/*
pub fn adjacencies<'a>(
&'a self,
coordinates: impl Iterator<Item = &'a Coordinate> + 'a,
) -> impl Iterator<Item = Coordinate> + 'a {
coordinates
.map(|coordinate| {
let mut v = Vec::new();
if coordinate.column > 0 {
v.push(Coordinate {
column: coordinate.column - 1,
row: coordinate.row,
});
}
if coordinate.row > 0 {
v.push(Coordinate {
column: coordinate.column,
row: coordinate.row - 1,
});
}
v.push(Coordinate {
column: coordinate.column + 1,
row: coordinate.row,
});
v.push(Coordinate {
column: coordinate.column,
row: coordinate.row + 1,
});
v
})
.flatten()
.filter(|coordinate| self.within_board(coordinate))
}
*/
pub fn within_board(&self, coordinate: &Coordinate) -> bool {
coordinate.column < self.size.width && coordinate.row < self.size.height
}
@ -256,18 +201,6 @@ impl Group {
}
}
/*
impl Group {
pub fn adjacencies(&self, max_column: usize, max_row: usize) -> HashSet<Coordinate> {
self.coordinates
.iter()
.map(|stone| stone.adjacencies(max_column, max_row))
.flatten()
.collect()
}
}
*/
#[cfg(test)]
mod test {
use super::*;
@ -329,6 +262,10 @@ mod test {
(Coordinate { column: 6, row: 16 }, Color::White),
(Coordinate { column: 7, row: 17 }, Color::White),
(Coordinate { column: 7, row: 18 }, Color::White),
/* */
(Coordinate { column: 17, row: 0 }, Color::White),
(Coordinate { column: 17, row: 1 }, Color::White),
(Coordinate { column: 18, row: 1 }, Color::White),
]
.into_iter(),
);
@ -594,8 +531,15 @@ mod test {
});
}
fn suicide_is_forbidden() {
assert!(false);
#[test]
fn self_capture_is_forbidden() {
with_example_board(|mut board| {
let res = board.place_stone(Coordinate { column: 18, row: 0 }, Color::Black);
assert_eq!(res, Err(Error::SelfCapture));
let res = board.place_stone(Coordinate { column: 5, row: 18 }, Color::Black);
assert_eq!(res, Err(Error::SelfCapture));
});
}
fn captures_preceed_self_capture() {

View File

@ -2,4 +2,4 @@ release:
cargo build --release
dev:
cargo watch -x run
cargo watch -x 'run --bin kifu-gtk'