use std::fmt;
use std::fmt::Formatter;
use std::convert::TryFrom;
use rule::{AppliedMove};
use error::*;
use Find;
use MaxIndex;
use std::collections::HashMap;
#[derive(Clone, Copy, Eq, PartialOrd, Ord, PartialEq, Debug, Hash)]
pub enum KomaKind {
SFu = 0,
SKyou,
SKei,
SGin,
SKin,
SKaku,
SHisha,
SOu,
SFuN,
SKyouN,
SKeiN,
SGinN,
SKakuN,
SHishaN,
GFu,
GKyou,
GKei,
GGin,
GKin,
GKaku,
GHisha,
GOu,
GFuN,
GKyouN,
GKeiN,
GGinN,
GKakuN,
GHishaN,
Blank,
}
impl KomaKind {
pub fn to_nari(&self) -> KomaKind {
match *self {
KomaKind::SFu => {
KomaKind::SFuN
},
KomaKind::SKyou => {
KomaKind::SKyouN
},
KomaKind::SKei => {
KomaKind::SKeiN
},
KomaKind::SGin => {
KomaKind::SGinN
},
KomaKind::SHisha => {
KomaKind::SHishaN
},
KomaKind::SKaku => {
KomaKind::SKakuN
},
KomaKind::GFu => {
KomaKind::GFuN
},
KomaKind::GKyou => {
KomaKind::GKyouN
},
KomaKind::GKei => {
KomaKind::GKeiN
},
KomaKind::GGin => {
KomaKind::GGinN
},
KomaKind::GHisha => {
KomaKind::GHishaN
},
KomaKind::GKaku => {
KomaKind::GKakuN
},
kind => kind
}
}
pub fn is_nari(&self) -> bool {
match *self {
KomaKind::SFuN | KomaKind::SKyouN | KomaKind::SKeiN | KomaKind::SGinN | KomaKind::SHishaN | KomaKind::SKakuN |
KomaKind::GFuN | KomaKind::GKyouN | KomaKind::GKeiN | KomaKind::GGinN | KomaKind::GHishaN | KomaKind::GKakuN => {
true
},
_ => false
}
}
}
impl MaxIndex for KomaKind {
fn max_index() -> usize {
KomaKind::Blank as usize
}
}
#[derive(PartialEq, Eq)]
pub struct Banmen(pub [[KomaKind; 9]; 9]);
impl Clone for Banmen {
fn clone(&self) -> Banmen {
match self {
&Banmen(ref kinds) => Banmen(kinds.clone())
}
}
}
impl Banmen {
}
impl fmt::Debug for Banmen {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Banmen(ref v) => write!(f, "Banmen[\n{}\n]",
v.iter()
.map(|&row| {
format!(" [{}]", row.iter().map(|&k| format!("{:?}", k)).collect::<Vec<String>>().join(", "))
})
.collect::<Vec<String>>().join("\n"))
}
}
}
impl Find<KomaKind,Vec<KomaPosition>> for Banmen {
fn find(&self,query:&KomaKind) -> Option<Vec<KomaPosition>> {
let mut r:Vec<KomaPosition> = Vec::new();
match self {
&Banmen(ref kinds) => {
for y in 0..kinds.len() {
for x in 0..kinds[y].len() {
if *query == kinds[y][x] {
r.push(KomaPosition(9 - x as u32, y as u32 + 1));
}
}
}
}
}
if r.len() > 0 {
Some(r)
} else {
None
}
}
}
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub enum Teban {
Sente = 0,
Gote,
}
impl Teban {
pub fn opposite(&self) -> Teban {
match *self {
Teban::Sente => Teban::Gote,
Teban::Gote => Teban::Sente,
}
}
}
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub struct KomaPosition(pub u32,pub u32);
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub struct KomaSrcPosition(pub u32,pub u32);
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub struct KomaDstToPosition(pub u32,pub u32,pub bool);
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub struct KomaDstPutPosition(pub u32,pub u32);
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub enum Move {
To(KomaSrcPosition,KomaDstToPosition),
Put(MochigomaKind,KomaDstPutPosition),
}
impl Move {
pub fn to_applied_move(&self) -> AppliedMove {
AppliedMove::from(*self)
}
}
#[derive(Debug,Eq)]
pub enum MochigomaCollections {
Empty,
Pair(Mochigoma,Mochigoma),
}
impl Clone for MochigomaCollections {
fn clone(&self) -> MochigomaCollections {
match *self {
MochigomaCollections::Empty => MochigomaCollections::Empty,
MochigomaCollections::Pair(ref ms, ref mg) => {
MochigomaCollections::Pair(ms.clone(),mg.clone())
}
}
}
}
impl PartialEq for MochigomaCollections {
fn eq(&self, other: &Self) -> bool {
match self {
&MochigomaCollections::Empty => {
match other {
&MochigomaCollections::Empty => {
true
}
&MochigomaCollections::Pair(ref ms,ref mg) => {
ms.is_empty() && mg.is_empty()
}
}
},
&MochigomaCollections::Pair(ref ms, ref mg) => {
match other {
&MochigomaCollections::Empty => {
ms.is_empty() && mg.is_empty()
}
&MochigomaCollections::Pair(ref oms,ref omg) => {
ms == oms && mg == omg
}
}
}
}
}
}
impl MochigomaCollections {
pub fn new(ms:Mochigoma,mg:Mochigoma) -> MochigomaCollections {
if ms.is_empty() && mg.is_empty() {
MochigomaCollections::Empty
} else {
MochigomaCollections::Pair(ms,mg)
}
}
pub fn is_empty(&self) -> bool {
match self {
&MochigomaCollections::Empty => true,
&MochigomaCollections::Pair(ref ms, ref mg) => {
ms.is_empty() && mg.is_empty()
}
}
}
}
#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug, Hash)]
pub enum ObtainKind {
Fu = 0,
Kyou,
Kei,
Gin,
Kin,
Kaku,
Hisha,
Ou,
FuN,
KyouN,
KeiN,
GinN,
KakuN,
HishaN,
}
impl TryFrom<KomaKind> for ObtainKind {
type Error = TypeConvertError<String>;
fn try_from(kind:KomaKind) -> Result<ObtainKind,TypeConvertError<String>> {
Ok(match kind {
KomaKind::SFu => ObtainKind::Fu,
KomaKind::SKyou => ObtainKind::Kyou,
KomaKind::SKei => ObtainKind::Kei,
KomaKind::SGin => ObtainKind::Gin,
KomaKind::SKin => ObtainKind::Kin,
KomaKind::SKaku => ObtainKind::Kaku,
KomaKind::SHisha => ObtainKind::Hisha,
KomaKind::SOu => ObtainKind::Ou,
KomaKind::SFuN => ObtainKind::FuN,
KomaKind::SKyouN => ObtainKind::KyouN,
KomaKind::SKeiN => ObtainKind::KeiN,
KomaKind::SGinN => ObtainKind::GinN,
KomaKind::SKakuN => ObtainKind::KakuN,
KomaKind::SHishaN => ObtainKind::HishaN,
KomaKind::GFu => ObtainKind::Fu,
KomaKind::GKyou => ObtainKind::Kyou,
KomaKind::GKei => ObtainKind::Kei,
KomaKind::GGin => ObtainKind::Gin,
KomaKind::GKin => ObtainKind::Kin,
KomaKind::GKaku => ObtainKind::Kaku,
KomaKind::GHisha => ObtainKind::Hisha,
KomaKind::GOu => ObtainKind::Ou,
KomaKind::GFuN => ObtainKind::FuN,
KomaKind::GKyouN => ObtainKind::KyouN,
KomaKind::GKeiN => ObtainKind::KeiN,
KomaKind::GGinN => ObtainKind::GinN,
KomaKind::GKakuN => ObtainKind::KakuN,
KomaKind::GHishaN => ObtainKind::HishaN,
KomaKind::Blank => {
return Err(TypeConvertError::LogicError(String::from("Can not to convert Blank to ObtainKind.")));
}
})
}
}
impl TryFrom<KomaKind> for MochigomaKind {
type Error = TypeConvertError<String>;
fn try_from(kind:KomaKind) -> Result<MochigomaKind,TypeConvertError<String>> {
Ok(match kind {
KomaKind::SFu => MochigomaKind::Fu,
KomaKind::SKyou => MochigomaKind::Kyou,
KomaKind::SKei => MochigomaKind::Kei,
KomaKind::SGin => MochigomaKind::Gin,
KomaKind::SKin => MochigomaKind::Kin,
KomaKind::SKaku => MochigomaKind::Kaku,
KomaKind::SHisha => MochigomaKind::Hisha,
KomaKind::SFuN => MochigomaKind::Fu,
KomaKind::SKyouN => MochigomaKind::Kyou,
KomaKind::SKeiN => MochigomaKind::Kei,
KomaKind::SGinN => MochigomaKind::Gin,
KomaKind::SKakuN => MochigomaKind::Kaku,
KomaKind::SHishaN => MochigomaKind::Hisha,
KomaKind::GFu => MochigomaKind::Fu,
KomaKind::GKyou => MochigomaKind::Kyou,
KomaKind::GKei => MochigomaKind::Kei,
KomaKind::GGin => MochigomaKind::Gin,
KomaKind::GKin => MochigomaKind::Kin,
KomaKind::GKaku => MochigomaKind::Kaku,
KomaKind::GHisha => MochigomaKind::Hisha,
KomaKind::GFuN => MochigomaKind::Fu,
KomaKind::GKyouN => MochigomaKind::Kyou,
KomaKind::GKeiN => MochigomaKind::Kei,
KomaKind::GGinN => MochigomaKind::Gin,
KomaKind::GKakuN => MochigomaKind::Kaku,
KomaKind::GHishaN => MochigomaKind::Hisha,
KomaKind::SOu | KomaKind::GOu => {
return Err(TypeConvertError::LogicError(String::from("Can not to convert SOu or GOu to MochigomaKind.")));
},
KomaKind::Blank => {
return Err(TypeConvertError::LogicError(String::from("Can not to convert Blank to MochigomaKind.")));
}
})
}
}
#[derive(Clone, Copy, Eq, PartialOrd, Ord, PartialEq, Debug, Hash)]
#[repr(u8)]
pub enum MochigomaKind {
Fu = 0,
Kyou,
Kei,
Gin,
Kin,
Kaku,
Hisha,
}
impl TryFrom<ObtainKind> for MochigomaKind {
type Error = TypeConvertError<String>;
fn try_from(o:ObtainKind) -> Result<MochigomaKind,TypeConvertError<String>> {
Ok(match o {
ObtainKind::Fu | ObtainKind::FuN => MochigomaKind::Fu,
ObtainKind::Kyou | ObtainKind::KyouN=> MochigomaKind::Kyou,
ObtainKind::Kei | ObtainKind::KeiN => MochigomaKind::Kei,
ObtainKind::Gin | ObtainKind::GinN => MochigomaKind::Gin,
ObtainKind::Kin => MochigomaKind::Kin,
ObtainKind::Kaku | ObtainKind::KakuN => MochigomaKind::Kaku,
ObtainKind::Hisha | ObtainKind::HishaN => MochigomaKind::Hisha,
ObtainKind::Ou => {
return Err(TypeConvertError::LogicError(String::from("Can not to convert Ou to MochigomaKind.")));
}
})
}
}
impl MaxIndex for MochigomaKind {
fn max_index() -> usize {
MochigomaKind::Hisha as usize
}
}
pub const MOCHIGOMA_KINDS:[MochigomaKind; 7] = [
MochigomaKind::Fu,
MochigomaKind::Kyou,
MochigomaKind::Kei,
MochigomaKind::Gin,
MochigomaKind::Kin,
MochigomaKind::Kaku,
MochigomaKind::Hisha,
];
pub const MOCHIGOMA_KIND_MAX:usize = MochigomaKind::Hisha as usize;
impl From<(Teban,MochigomaKind)> for KomaKind {
fn from(tk:(Teban,MochigomaKind)) -> KomaKind {
match tk {
(Teban::Sente,k) => {
match k {
MochigomaKind::Fu => KomaKind::SFu,
MochigomaKind::Kyou => KomaKind::SKyou,
MochigomaKind::Kei => KomaKind::SKei,
MochigomaKind::Gin => KomaKind::SGin,
MochigomaKind::Kin => KomaKind::SKin,
MochigomaKind::Kaku => KomaKind::SKaku,
MochigomaKind::Hisha => KomaKind::SHisha,
}
},
(Teban::Gote,k) => {
match k {
MochigomaKind::Fu => KomaKind::GFu,
MochigomaKind::Kyou => KomaKind::GKyou,
MochigomaKind::Kei => KomaKind::GKei,
MochigomaKind::Gin => KomaKind::GGin,
MochigomaKind::Kin => KomaKind::GKin,
MochigomaKind::Kaku => KomaKind::GKaku,
MochigomaKind::Hisha => KomaKind::GHisha,
}
}
}
}
}
const MOCHIGOMA_START_INDEXES:[u8; MOCHIGOMA_KIND_MAX + 1] = [
0,
18,
22,
26,
30,
34,
36
];
const MOCHIGOMA_MAX_COUNT:[u8; MOCHIGOMA_KIND_MAX + 1] = [
18,
4,
4,
4,
4,
2,
2
];
const MOCHIGOMA_MASK:[u64; MOCHIGOMA_KIND_MAX + 1] = [
0b111111111111111111,
0b1111,
0b1111,
0b1111,
0b1111,
0b11,
0b11
];
const MOCHIGOMA_MASK_SOURCE:u64 = 0b10_10_1000_1000_1000_1000_100000000000000000;
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Mochigoma {
bitboard:u64
}
impl Mochigoma {
pub fn new() -> Mochigoma {
Mochigoma {
bitboard:0
}
}
#[inline]
pub fn insert(&mut self,kind:MochigomaKind,count:usize) {
let mut bits = 0;
let index = MOCHIGOMA_START_INDEXES[kind as usize];
for _ in 0..count.min(MOCHIGOMA_MAX_COUNT[kind as usize] as usize) {
bits = (bits << 1) | 1;
}
self.bitboard = (self.bitboard & !(MOCHIGOMA_MASK[kind as usize] << index)) | (bits << index)
}
#[inline]
pub fn get(&self,kind:MochigomaKind) -> usize {
((self.bitboard >> MOCHIGOMA_START_INDEXES[kind as usize]) & MOCHIGOMA_MASK[kind as usize]).trailing_ones() as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.bitboard == 0
}
#[inline]
pub fn iter<'a>(&'a self) -> impl Iterator<Item=(MochigomaKind,usize)> + 'a {
MochigomaIterator::new(self.bitboard)
}
#[inline]
pub fn put(&mut self,kind:MochigomaKind) {
let mut b = self.bitboard;
b = b >> MOCHIGOMA_START_INDEXES[kind as usize] & MOCHIGOMA_MASK[kind as usize];
b = (b << 1 | 1) & MOCHIGOMA_MASK[kind as usize];
self.bitboard = self.bitboard | (b << MOCHIGOMA_START_INDEXES[kind as usize]);
}
#[inline]
pub fn pull(&mut self,kind:MochigomaKind) -> Result<usize,InvalidStateError> {
let index = MOCHIGOMA_START_INDEXES[kind as usize];
let mut b = self.bitboard >> index & MOCHIGOMA_MASK[kind as usize];
if b == 0 {
Err(InvalidStateError(String::from("I don't have any pieces.")))
} else {
b = b >> 1;
self.bitboard = self.bitboard & !(MOCHIGOMA_MASK[kind as usize] << index) | (b << index);
Ok(128 - b.leading_zeros() as usize)
}
}
#[inline]
pub fn filled() -> Mochigoma {
let mut m:Mochigoma = Mochigoma::new();
m.insert(MochigomaKind::Fu, 9);
m.insert(MochigomaKind::Kyou, 2);
m.insert(MochigomaKind::Kei, 2);
m.insert(MochigomaKind::Gin, 2);
m.insert(MochigomaKind::Kin, 2);
m.insert(MochigomaKind::Kaku, 1);
m.insert(MochigomaKind::Hisha, 1);
m
}
}
pub struct MochigomaIterator {
bitboard:u64,
mask:u64,
current_index:usize
}
impl MochigomaIterator {
pub fn new(bitboard:u64) -> MochigomaIterator {
MochigomaIterator {
bitboard,
mask:MOCHIGOMA_MASK_SOURCE,
current_index:0
}
}
}
impl Iterator for MochigomaIterator {
type Item = (MochigomaKind,usize);
fn next(&mut self) -> Option<Self::Item> {
if self.mask == 0 {
None
} else {
let next_index = self.mask.trailing_zeros() + 1;
let mask = (self.mask - 1) ^ self.mask;
let c = (self.bitboard & mask).trailing_ones();
let current_index = self.current_index;
self.mask >>= next_index;
self.bitboard >>= next_index;
self.current_index += 1;
Some((unsafe { std::mem::transmute(current_index as u8) }, c as usize))
}
}
}
impl From<&Mochigoma> for HashMap<MochigomaKind,u32> {
fn from(source:&Mochigoma) -> HashMap<MochigomaKind,u32> {
source.iter().fold(HashMap::new(),|mut acc,(k,c)| {
acc.insert(k,c as u32);
acc
})
}
}
impl From<&HashMap<MochigomaKind,u32>> for Mochigoma {
fn from(source:&HashMap<MochigomaKind,u32>) -> Mochigoma {
MOCHIGOMA_KINDS.iter().fold(Mochigoma::new(),| mut acc,k | {
let count = source.get(k).map(|&c| c).unwrap_or(0);
acc.insert(*k,count as usize);
acc
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mochigoma_collections_clone_and_eq() {
let mc1 = MochigomaCollections::Empty;
let mc2 = mc1.clone();
assert_eq!(mc1,mc2);
for &kind in &MOCHIGOMA_KINDS {
let mut ms = Mochigoma::new();
ms.insert(kind,1);
let mc1 = MochigomaCollections::Pair(ms,Mochigoma::new());
let mc2 = mc1.clone();
assert_eq!(mc1, mc2);
}
let mut ms = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
ms.insert(kind, 1);
}
let mc1 = MochigomaCollections::Pair(ms,Mochigoma::new());
let mc2 = mc1.clone();
assert_eq!(mc1, mc2);
for &kind in &MOCHIGOMA_KINDS {
let mut mg = Mochigoma::new();
mg.insert(kind,1);
let mc1 = MochigomaCollections::Pair(Mochigoma::new(),mg);
let mc2 = mc1.clone();
assert_eq!(mc1, mc2);
}
let mut mg = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
mg.insert(kind, 1);
}
let mc1 = MochigomaCollections::Pair(Mochigoma::new(),mg);
let mc2 = mc1.clone();
assert_eq!(mc1, mc2);
}
#[test]
fn test_mochigoma_insert_and_get() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
}
for &kind in &MOCHIGOMA_KINDS {
assert_eq!(2,m.get(kind));
}
}
#[test]
fn test_mochigoma_insert_and_is_empty() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
}
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,0);
}
assert_eq!(true,m.is_empty())
}
#[test]
fn test_mochigoma_insert_and_is_empty_not() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
}
assert_eq!(false,m.is_empty());
}
#[test]
fn test_mochigoma_iter() {
let mut m = Mochigoma::new();
let mut c = 1;
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,c);
c += 1;
}
assert_eq!(vec![
(MochigomaKind::Fu,1),
(MochigomaKind::Kyou,2),
(MochigomaKind::Kei,3),
(MochigomaKind::Gin,4),
(MochigomaKind::Kin,4),
(MochigomaKind::Kaku,2),
(MochigomaKind::Hisha,2),
],m.iter().collect::<Vec<(MochigomaKind,usize)>>());
}
#[test]
fn test_mochigoma_put() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.put(kind);
}
for &kind in &MOCHIGOMA_KINDS {
assert_eq!(1,m.get(kind));
}
}
#[test]
fn test_mochigoma_put_and_is_empty_not() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.put(kind);
}
assert_eq!(false,m.is_empty());
}
#[test]
fn test_mochigoma_pull() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
m.pull(kind).unwrap();
}
for &kind in &MOCHIGOMA_KINDS {
assert_eq!(1,m.get(kind));
}
}
#[test]
fn test_mochigoma_pull_and_is_empty() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.put(kind);
m.pull(kind).unwrap();
}
for &kind in &MOCHIGOMA_KINDS {
assert_eq!(0,m.get(kind));
}
assert_eq!(true,m.is_empty());
}
#[test]
fn test_mochigoma_insert_and_pull_and_is_empty() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
m.pull(kind).unwrap();
m.pull(kind).unwrap();
}
for &kind in &MOCHIGOMA_KINDS {
assert_eq!(0,m.get(kind));
}
assert_eq!(true,m.is_empty());
}
#[test]
fn test_mochigoma_pull_error() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
assert!(m.pull(kind).is_err())
}
}
#[test]
fn test_mochigoma_pull_error_after_insert() {
let mut m = Mochigoma::new();
for &kind in &MOCHIGOMA_KINDS {
m.insert(kind,2);
}
for &kind in &MOCHIGOMA_KINDS {
m.pull(kind).unwrap();
m.pull(kind).unwrap();
assert!(m.pull(kind).is_err())
}
}
}