1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
sync::{Arc, RwLock},
};
#[derive(Deserialize, Serialize, Clone, Debug)]
pub enum Winning {
C1(Vec<u32>),
C2(Vec<u32>),
T(Vec<u32>),
TULUM(Vec<u32>),
}
#[derive(Default, Debug, Clone)]
pub struct Game {
pub id: u64,
pub c1: Vec<u32>,
pub c2: Vec<u32>,
pub t: Vec<u32>,
pub balls: Vec<u8>,
pub card_state: HashMap<u32, CardState>,
pub card_index_by_number: CardIndex,
}
impl Game {
pub fn new(game_id: u64, index: CardIndex) -> Arc<RwLock<Game>> {
Arc::new(RwLock::new(Game {
id: game_id,
card_index_by_number: index,
..Default::default()
}))
}
pub fn is_tulum(&self) -> bool {
let (c1, c2, c3) = (&self.c1, &self.c2, &self.t);
c1.len() == 1 && c2.len() == 1 && c3.len() == 1 && c1[0] == c2[0] && c2[0] == c3[0]
}
pub fn new_game(&mut self) -> u64 {
self.id += 1;
self.balls = Vec::new();
self.c1 = Vec::new();
self.c2 = Vec::new();
self.t = Vec::new();
self.card_state = HashMap::new();
self.id
}
pub fn add_ball(&mut self, num: u8) -> Result<Option<Winning>, String> {
if self.t.len() > 0 {
return Err("game finished".to_string());
} else if self.balls.contains(&num) {
return Err("ball exists".to_string());
}
self.balls.push(num);
let val = match self.card_index_by_number.get(&num) {
Some(val) => val,
None => return Ok(None),
};
let mut winner_cards: HashSet<u32> = HashSet::new();
let num_row_required_to_win = if self.c1.len() == 0 {
0
} else if self.c2.len() == 0 {
1
} else if self.t.len() == 0 {
2
} else {
return Ok(Some(Winning::T(self.t.clone())));
};
for card_info in val.iter() {
let card_state = self.card_state.entry(card_info.card_id).or_default();
let mut num_rows_completed = 0;
match card_info.row {
Row::R1 => card_state.r1 += 1,
Row::R2 => card_state.r2 += 1,
Row::R3 => card_state.r3 += 1,
};
if card_state.r1 > 4 {
num_rows_completed += 1;
}
if card_state.r2 > 4 {
num_rows_completed += 1;
}
if card_state.r3 > 4 {
num_rows_completed += 1;
}
if num_rows_completed > num_row_required_to_win {
winner_cards.insert(card_info.card_id);
}
}
if !winner_cards.is_empty() {
Ok(Some(match num_row_required_to_win {
0 => {
self.c1 = winner_cards.into_iter().collect();
Winning::C1(self.c1.clone())
}
1 => {
self.c2 = winner_cards.into_iter().collect();
Winning::C2(self.c2.clone())
}
_ => {
self.t = winner_cards.into_iter().collect();
Winning::T(self.t.clone())
}
}))
} else {
Ok(None)
}
}
}
pub type CardIndex = HashMap<u8, Vec<Cardinfo>>;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Row {
R1,
R2,
R3,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Cardinfo {
pub card_id: u32,
pub row: Row,
}
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
pub struct CardState {
pub r1: u8,
pub r2: u8,
pub r3: u8,
}
pub type Card = (u32, [u8; 9], [u8; 9], [u8; 9]);