1use crate::card::{Card, Face, Suit};
2use crate::err::SolError;
3
4#[derive(Clone, Copy, PartialEq)]
5pub enum FaceOrder {
6 Asc,
7 Desc,
8 Any,
9}
10
11pub fn str_to_face_order(s: &str) -> Result<FaceOrder, SolError> {
12 match s {
13 "asc" | "ascending" | "inc" | "increasing" => Ok(FaceOrder::Asc),
14 "desc" | "descending" | "dec" | "decreasing" => Ok(FaceOrder::Desc),
15 "any" | "alternate" => Ok(FaceOrder::Any),
16 _ => Err(SolError::InvalidFaceOrder(s.to_string())),
17 }
18}
19
20#[derive(Clone, Copy, PartialEq)]
21pub enum SuitOrder {
22 SameSuit,
23 SameColor,
24 AlternateColor,
25 ExceptSame,
26 Any,
27 Forbid,
28}
29
30pub fn str_to_suit_order(s: &str) -> Result<SuitOrder, SolError> {
31 match s {
32 "same" | "same suit" | "samesuit" => Ok(SuitOrder::SameSuit),
33 "exceptsame" | "except same" | "except" => Ok(SuitOrder::ExceptSame),
34 "same color" | "samecolor" => Ok(SuitOrder::SameColor),
35 "alternate" | "alternate color" | "alternatecolor" => Ok(SuitOrder::AlternateColor),
36 "none" | "forbid" | "disable" => Ok(SuitOrder::Forbid),
37 "any" => Ok(SuitOrder::Any),
38 _ => Err(SolError::InvalidSuitOrder(s.to_string())),
39 }
40}
41
42#[derive(Clone, Copy)]
44pub struct PileConf {
45 pub deal_by: u8, pub redeals: i8, pub pile_to_cols: bool, }
49
50impl PileConf {
51 pub fn validate(&self) -> Result<(), SolError> {
52 if self.deal_by == 0 || self.deal_by > 16 {
53 return Err(SolError::InvalidDealBy(self.deal_by));
54 }
55 Ok(())
56 }
57}
58
59#[derive(Clone, Copy)]
61pub struct FndSlot {
62 pub first: Face, pub suit: Suit, pub forder: FaceOrder, pub sorder: SuitOrder, pub filler: Option<Card>, }
68
69#[derive(Clone, Copy)]
71pub struct TempConf {
72 pub count: u8, }
74
75impl TempConf {
76 pub fn validate(&self) -> Result<(), SolError> {
77 if self.count > 4 {
78 return Err(SolError::InvalidTempNumber(self.count));
79 }
80 Ok(())
81 }
82}
83
84#[derive(Clone, Copy)]
86pub struct ColConf {
87 pub count: u8, pub up: u8, pub take_only: bool, }
91
92#[derive(Clone, Copy, PartialEq)]
94pub enum Playable {
95 Top, Any, Ordered, }
99
100#[derive(Clone)]
101pub struct Conf {
102 pub chance: Option<u16>, pub name: String, pub deck_count: u8, pub playable: Playable, pub pile: Option<PileConf>, pub fnd: Vec<FndSlot>, pub temp: Option<TempConf>, pub cols: Vec<ColConf>, pub col_forder: FaceOrder, pub col_sorder: SuitOrder, pub col_refill: Face,
117}
118
119impl Default for Conf {
120 fn default() -> Conf {
121 Conf {
122 name: String::new(),
123 chance: None,
124 deck_count: 1,
125 playable: Playable::Top,
126 pile: None,
127 fnd: Vec::new(),
128 temp: None,
129 cols: Vec::new(),
130 col_forder: FaceOrder::Desc,
131 col_sorder: SuitOrder::SameSuit,
132 col_refill: Face::Unavail,
133 }
134 }
135}
136
137impl Conf {
138 pub fn new() -> Self {
139 Default::default()
140 }
141 pub fn validate(&self) -> Result<(), SolError> {
142 if self.deck_count == 0 || self.deck_count > 2 {
143 return Err(SolError::InvalidDeckNumber(self.deck_count));
144 }
145 if let Some(ref cfg) = self.temp {
146 cfg.validate()?;
147 }
148 if let Some(ref dc) = self.pile {
149 dc.validate()?;
150 }
151 if self.fnd.is_empty() {
152 return Err(SolError::NoFoundation);
153 }
154 for w in &self.fnd {
155 if w.first == Face::Empty {
156 return Err(SolError::NoFoundationStart);
157 }
158 }
159 if self.cols.is_empty() {
160 return Err(SolError::NoCols);
161 }
162 if self.cols.len() > 10 {
163 return Err(SolError::InvalidColNumber(self.cols.len() as u8));
164 }
165 Ok(())
166 }
167
168 pub fn deal_by(&self) -> u8 {
169 if let Some(ref pconf) = self.pile {
170 pconf.deal_by
171 } else {
172 0
173 }
174 }
175
176 pub fn redeals(&self) -> i8 {
177 if let Some(ref pconf) = self.pile {
178 pconf.redeals
179 } else {
180 0
181 }
182 }
183}