#![warn(clippy::pedantic, clippy::nursery)]
#![allow(
clippy::too_many_lines,
clippy::non_ascii_literal,
clippy::module_name_repetitions,
clippy::use_self
)]
#![cfg_attr(not(test), no_std)]
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
use cetkaik_fundamental::{AbsoluteSide, PureMove_};
use cetkaik_traits::CetkaikRepresentation;
#[must_use]
pub fn from_hop1zuo1_candidates_vec<T: CetkaikRepresentation>(
whose_turn: AbsoluteSide,
field: &T::AbsoluteField,
) -> Vec<PureMove_<T::AbsoluteCoord>> {
use cetkaik_traits::IsAbsoluteField;
field
.hop1zuo1_of(whose_turn)
.flat_map(|cetkaik_fundamental::ColorAndProf { color, prof }| {
T::as_board_absolute(field)
.empty_squares()
.map(move |dest| PureMove_::NonTamMoveFromHopZuo { color, prof, dest })
})
.collect()
}
mod calculate_movable;
pub use calculate_movable::calculate_movable_positions_for_either_side;
pub use calculate_movable::is_tam_hue_relative;
#[derive(Debug, Eq, Clone, PartialEq)]
pub struct MovablePositions<T> {
pub finite: Vec<T>,
pub infinite: Vec<T>,
}
fn empty_neighbors_of<T: CetkaikRepresentation>(
board: T::RelativeBoard,
c: T::RelativeCoord,
) -> impl Iterator<Item = T::RelativeCoord> {
calculate_movable::iter::eight_neighborhood::<T>(c)
.filter(move |coord| board.peek(*coord).is_none())
}
fn can_get_occupied_by_non_tam<T: CetkaikRepresentation>(
side: T::RelativeSide,
dest: T::RelativeCoord,
board: T::RelativeBoard,
tam_itself_is_tam_hue: bool,
) -> bool {
let is_protected_by_opponent_tam_hue_auai = |side: T::RelativeSide, coord: T::RelativeCoord| {
calculate_movable::vec::eight_neighborhood::<T>(coord)
.into_iter()
.filter(|ab| {
board.peek(*ab).map_or(false, |piece| {
piece.match_on_piece_and_apply(&|| false, &|_, piece_prof, piece_side| {
piece_prof == Profession::Uai1
&& piece_side != side
&& calculate_movable::is_tam_hue_relative::<T>(
*ab,
board,
tam_itself_is_tam_hue,
)
})
})
})
.count()
> 0
};
board.peek(dest).map_or(true, |piece| {
piece.match_on_piece_and_apply(
&|| false,
&|_, _, piece_side| {
piece_side != side &&
!is_protected_by_opponent_tam_hue_auai(
side,
dest
)
},
)
})
}
fn is_ciurl_required<T: CetkaikRepresentation>(
dest: T::RelativeCoord,
moving_piece_prof: Profession,
src: T::RelativeCoord,
) -> bool {
T::is_water_relative(dest)
&& !T::is_water_relative(src)
&& !matches!(moving_piece_prof, Profession::Nuak1)
}
#[must_use]
pub fn not_from_hop1zuo1_candidates_vec<T: CetkaikRepresentation>(
allow_kut2tam2: &AllowKut2Tam2,
tam_itself_is_tam_hue: bool,
whose_turn: AbsoluteSide,
f: &T::AbsoluteField,
) -> Vec<PureMove_<T::AbsoluteCoord>> {
let perspective = T::get_one_perspective();
not_from_hop1zuo1_candidates_::<T>(
T::to_relative_side(whose_turn, perspective),
*allow_kut2tam2,
perspective,
tam_itself_is_tam_hue,
&T::to_relative_field((*f).clone(), perspective),
)
}
fn candidates_tam2<T: CetkaikRepresentation>(
src: T::RelativeCoord,
f: &T::RelativeField,
perspective: T::Perspective,
ans: &mut Vec<PureMove_<T::AbsoluteCoord>>,
) {
let candidates: Vec<T::RelativeCoord> = calculate_movable::vec::eight_neighborhood::<T>(src);
for tentative_dest in candidates {
let dest_piece = T::as_board_relative(f).peek(tentative_dest);
let mut subtracted_board = *T::as_board_relative(f);
subtracted_board.put(src, None);
if dest_piece.is_none() {
let fst_dst: T::RelativeCoord = tentative_dest;
ans.append(&mut calculate_movable::iter::eight_neighborhood::<T>(fst_dst).flat_map(|neighbor| {
let snd_dst: T::RelativeCoord = neighbor;
if T::as_board_relative(f).peek(neighbor).is_none() ||
neighbor == src
{
vec![PureMove_::TamMoveNoStep {
second_dest: T::to_absolute_coord(snd_dst, perspective),
first_dest: T::to_absolute_coord(fst_dst, perspective),
src: T::to_absolute_coord(src, perspective),
}].into_iter()
} else {
let step: T::RelativeCoord = neighbor;
empty_neighbors_of::<T>(subtracted_board, step)
.flat_map(|snd_dst| {
vec![PureMove_::TamMoveStepsDuringLatter {
first_dest: T::to_absolute_coord(fst_dst, perspective),
second_dest: T::to_absolute_coord(snd_dst, perspective),
src: T::to_absolute_coord(src, perspective),
step: T::to_absolute_coord(step, perspective),
}].into_iter()
}).collect::<Vec<PureMove_<T::AbsoluteCoord>>>().into_iter()
}
}).collect::<Vec<PureMove_<T::AbsoluteCoord>>>());
} else {
let step = tentative_dest;
ans.append(
&mut empty_neighbors_of::<T>(subtracted_board, step)
.flat_map(|fst_dst| {
let v = empty_neighbors_of::<T>(subtracted_board, fst_dst);
v.flat_map(move |snd_dst| {
vec![PureMove_::TamMoveStepsDuringFormer {
first_dest: T::to_absolute_coord(fst_dst, perspective),
second_dest: T::to_absolute_coord(snd_dst, perspective),
src: T::to_absolute_coord(src, perspective),
step: T::to_absolute_coord(step, perspective),
}]
.into_iter()
})
.collect::<Vec<PureMove_<T::AbsoluteCoord>>>()
.into_iter()
})
.collect::<Vec<PureMove_<T::AbsoluteCoord>>>(),
);
}
}
}
fn append_possible_movement_of_a_piece<T: CetkaikRepresentation>(
side: T::RelativeSide,
config: Config2,
prof: Profession,
src: T::RelativeCoord,
field: &T::RelativeField,
perspective: T::Perspective,
ans: &mut Vec<PureMove_<T::AbsoluteCoord>>,
) {
let MovablePositions { finite, infinite } =
calculate_movable::calculate_movable_positions_for_nontam::<T>(
src,
prof,
*T::as_board_relative(field),
config.tam_itself_is_tam_hue,
side,
);
let candidates: Vec<T::RelativeCoord> = [&finite[..], &infinite[..]].concat();
for tentative_dest in candidates {
let dest_piece = T::as_board_relative(field).peek(tentative_dest);
let candidates_when_stepping = || {
let step = tentative_dest;
let perspective = perspective;
let tam_itself_is_tam_hue: bool = config.tam_itself_is_tam_hue;
let mut subtracted_board = *T::as_board_relative(field);
subtracted_board.put(src, None);
let MovablePositions { finite, infinite } =
calculate_movable::calculate_movable_positions_for_nontam::<T>(
step,
prof,
subtracted_board,
tam_itself_is_tam_hue,
side,
);
let candidates = finite.into_iter();
let candidates_inf = infinite.into_iter();
let candidates_abs = candidates
.flat_map(|final_dest| {
if can_get_occupied_by_non_tam::<T>(
side,
final_dest,
subtracted_board,
tam_itself_is_tam_hue,
) {
vec![PureMove_::NonTamMoveSrcStepDstFinite {
src: T::to_absolute_coord(src, perspective),
step: T::to_absolute_coord(step, perspective),
dest: T::to_absolute_coord(final_dest, perspective),
is_water_entry_ciurl: is_ciurl_required::<T>(final_dest, prof, src),
}]
.into_iter()
} else {
vec![].into_iter()
}
})
.collect::<Vec<PureMove_<T::AbsoluteCoord>>>();
let candidates_inf_abs = candidates_inf
.flat_map(|planned_dest| {
if !can_get_occupied_by_non_tam::<T>(
side,
planned_dest,
subtracted_board,
tam_itself_is_tam_hue,
) {
return vec![].into_iter();
}
let obj: PureMove_<T::AbsoluteCoord> = PureMove_::InfAfterStep {
src: T::to_absolute_coord(src, perspective),
step: T::to_absolute_coord(step, perspective),
planned_direction: T::to_absolute_coord(planned_dest, perspective),
};
vec![obj].into_iter()
})
.collect::<Vec<PureMove_<T::AbsoluteCoord>>>();
[&candidates_abs[..], &candidates_inf_abs[..]].concat()
};
if let Some(piece) = dest_piece {
let mut a = piece.match_on_piece_and_apply(
&|| {
if config.allow_kut2tam2 {
candidates_when_stepping()
} else {
vec![]
}
},
&|_color, prof, side_| {
if side_ == side {
candidates_when_stepping()
} else {
if can_get_occupied_by_non_tam::<T>(
side,
tentative_dest,
*T::as_board_relative(field),
config.tam_itself_is_tam_hue,
) {
[
&[PureMove_::NonTamMoveSrcDst {
src: T::to_absolute_coord(src, perspective),
dest: T::to_absolute_coord(tentative_dest, perspective),
is_water_entry_ciurl: is_ciurl_required::<T>(
tentative_dest,
prof,
src,
),
}][..],
&candidates_when_stepping()[..],
]
.concat()
} else {
candidates_when_stepping()
}
}
},
);
ans.append(&mut a);
} else {
ans.append(&mut vec![PureMove_::NonTamMoveSrcDst {
src: T::to_absolute_coord(src, perspective),
dest: T::to_absolute_coord(tentative_dest, perspective),
is_water_entry_ciurl: is_ciurl_required::<T>(tentative_dest, prof, src),
}]);
}
}
}
fn not_from_hop1zuo1_candidates_<T: CetkaikRepresentation>(
side: T::RelativeSide,
allow_kut2tam2: AllowKut2Tam2,
perspective: T::Perspective,
tam_itself_is_tam_hue: bool,
field: &T::RelativeField,
) -> Vec<PureMove_<T::AbsoluteCoord>> {
let mut ans = vec![];
T::loop_over_one_side_and_tam(T::as_board_relative(field), side, &mut |src, maybe_prof| {
match maybe_prof {
None => candidates_tam2::<T>(src, field, perspective, &mut ans),
Some(prof) => append_possible_movement_of_a_piece::<T>(
side,
Config2 {
tam_itself_is_tam_hue,
allow_kut2tam2: allow_kut2tam2.allow_kut2tam2,
},
prof,
src,
field,
perspective,
&mut ans,
),
}
});
ans
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct AllowKut2Tam2 {
pub allow_kut2tam2: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Config2 {
pub allow_kut2tam2: bool,
pub tam_itself_is_tam_hue: bool,
}
#[cfg(test)]
mod tests;
pub use cetkaik_fundamental::{Color, Profession};
use cetkaik_traits::IsBoard;
use cetkaik_traits::IsPieceWithSide;
#[allow(clippy::similar_names)]
pub mod get_blocker_deltas;