I have a board whitch i am able to index with a glam::IVec2
struct Board{pieces: [char;64]}
type PieceOption = Option<char>;
this index method for board is
impl Index<IVec2> for Board {
type Output = PieceOption;
fn index(&self, v : IVec2) -> &Self::Output{
if (v.abs() != v) || (v.max_element() > 8) {&None}
else {
let i : usize = (v.x 8* v.y).try_into().unwrap();
&Some(self.pieces[i])
}
}
}
Along with this PieceOption has methods is_empty
, is_ally
and is_rival
so my question is as follows: what should the value of this recursive function be, in order to achieve type consistency i need the function to return a vector but i dont want to return the vector in the case where the next piece is of the same colour (is_ally). Along with this i was wondering if there is a way of unwrapping the Some
values so that i do not need to type Some('char') for every single branch in the match statement, especially since i already filtered for the cases where the next move is out of bounds. this is the current function with the type inconsistency. This is the function currenty implimented for the bishops only my intention is to feed this function consts for each of the movement types eg
const DIAGONALS : [IVec2; 4] = [
ivec2(-1, -1), ivec2(-1, 1),
ivec2(-1, 1), ivec2(1, 1)
];
so here is the current state of the function
impl Board {
fn moves(&self, piece:&PieceOption, pos:IVec2, dir: Vec<IVec2>)->Vec<IVec2>{
dir.into_iter()
.map(|d| d pos)
.filter(|p| (p.abs() == *p) && p.max_element() < 8)
.flat_map(|p|
match piece{
Some('B')|Some('b')=>{
if self[p].is_empty() {self.moves(piece, p, vec![p-pos]).push(p)}
else if self[p].is_rival(*piece) {p}
else {()} /* here is where i do not wish to return a vector because
this is likely a case where the next piece is an opponent*/
},
_ => () /* here is where i do not wish to return a vector because
the piece is likely empty space*/
}
)
.collect()
}
}
UPDATE:
update i have realised if let
is what i need to unwrap the option of the piece but i am really confused about what the return value of the if let statement should be, my current code for the function is
impl Board {
fn moves(&self, piece:&PieceOption, pos:IVec2, dir: Vec<IVec2>)->Option<Vec<IVec2>>{
dir.into_iter()
.map(|d| d pos)
.filter(|p| (p.abs() == *p) && p.max_element() < 8)
.flat_map(|p|
if let Some(c) = piece{
match c{
'B'|'b'=>{
if self[p].is_empty() {self.moves(piece, p, vec![p-pos])?.push(p)}
else if self[p].is_rival(*piece) {Some(vec![p])}
else {None?}
},
_ => None
}
} else {None}
)
.collect()
}
}
Along with this any advice on the format is greatly appreciated I'd like to know what people think about this potential solution and my appologies if the question is confusingly worded? full code can be found at: https://github.com/LyndonAlcock/chess_test
CodePudding user response:
The return type of a closure passed to flat_map
should be a collection.
If you don't want to add anything you can just return an empty one. vec![]
in case of a Vec
Also Option<char>
is copy so you can just pass in the thing instead of a reference.
impl Board {
fn moves(&self, piece: PieceOption, pos: IVec2, dir: Vec<IVec2>) -> Vec<IVec2> {
dir.into_iter()
.map(|d| d pos)
.filter(|p| (p.abs() == *p) && p.max_element() < 8)
.flat_map(|p|
if let Some(c) = piece {
match c {
'B'|'b'=> {
if self[p].is_empty() {
let moves = self.moves(piece, p, vec![p-pos])
moves.push(p);
moves
} else if self[p].is_rival(*piece) {
vec![p]
} else {
vec![]
}
},
_ => vec![]
}
} else {
vec![]
}
)
.collect()
}
}