Change implementation to use LUT
This commit is contained in:
parent
2244651aa1
commit
0767d5d8c1
91
lut.py
Normal file
91
lut.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
s = set()
|
||||||
|
|
||||||
|
for a in range(7):
|
||||||
|
for b in range(7):
|
||||||
|
for c in range(7):
|
||||||
|
s.add(tuple(sorted((a, b, c))))
|
||||||
|
|
||||||
|
mapping = sorted(s)
|
||||||
|
|
||||||
|
n = 128
|
||||||
|
filler = 0
|
||||||
|
|
||||||
|
print(f"const MAPPING: [(u8, u8, u8); {len(mapping)}] = {list(mapping)};")
|
||||||
|
print()
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def score(column):
|
||||||
|
values = {die: 0 for die in range(1, 7)}
|
||||||
|
for die in column:
|
||||||
|
if die == 0:
|
||||||
|
continue
|
||||||
|
values[die] += 1
|
||||||
|
|
||||||
|
multiplier = {0: 1, 1: 1, 2: 2, 3: 9}
|
||||||
|
|
||||||
|
return sum(value * count * multiplier[count] for (value, count) in values.items())
|
||||||
|
|
||||||
|
|
||||||
|
score_lut = [filler for _ in range(n)]
|
||||||
|
for i, column in enumerate(mapping):
|
||||||
|
score_lut[i] = score(column)
|
||||||
|
|
||||||
|
print(f"const SCORE_LUT: [u8; {n}] = {score_lut};")
|
||||||
|
print()
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def add(die, column):
|
||||||
|
if 0 not in column:
|
||||||
|
raise ValueError("Invalid Move")
|
||||||
|
|
||||||
|
new_column = list(column)
|
||||||
|
new_column[0] = die # sorted and a zero is present -> first index is 0
|
||||||
|
|
||||||
|
return tuple(sorted(new_column))
|
||||||
|
|
||||||
|
|
||||||
|
add_lut = {die: [filler for _ in range(32)] for die in range(1, 7)}
|
||||||
|
for die in range(1, 7):
|
||||||
|
for i, column in enumerate(mapping):
|
||||||
|
try:
|
||||||
|
new_column = add(die, column)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
add_lut[die][i] = mapping.index(new_column)
|
||||||
|
|
||||||
|
print(f"const ADD_LUT: [[u8; 32]; 8] = [")
|
||||||
|
print(f" [{filler}; 32],")
|
||||||
|
for die in range(1, 7):
|
||||||
|
print(f" {add_lut[die]},")
|
||||||
|
print(f" [{filler}; 32],")
|
||||||
|
print("];");
|
||||||
|
print()
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def remove(die, opposite):
|
||||||
|
new_opposite = list(opposite)
|
||||||
|
for i in range(3):
|
||||||
|
if new_opposite[i] == die:
|
||||||
|
new_opposite[i] = 0
|
||||||
|
return tuple(sorted(new_opposite))
|
||||||
|
|
||||||
|
|
||||||
|
remove_lut = {die: [filler for _ in range(n)] for die in range(1, 7)}
|
||||||
|
for die in range(1, 7):
|
||||||
|
for i, column in enumerate(mapping):
|
||||||
|
new_column = remove(die, column)
|
||||||
|
remove_lut[die][i] = mapping.index(new_column)
|
||||||
|
|
||||||
|
print(f"const REMOVE_LUT: [[u8; {n}]; 8] = [")
|
||||||
|
print(f" [{filler}; {n}],")
|
||||||
|
for die in range(1, 7):
|
||||||
|
print(f" {remove_lut[die]},")
|
||||||
|
print(f" [{filler}; {n}],")
|
||||||
|
print("];");
|
||||||
|
print()
|
374
src/game.rs
374
src/game.rs
@ -1,152 +1,166 @@
|
|||||||
|
const MAPPING: [(u8, u8, u8); 84] = [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 0, 5), (0, 0, 6), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 1, 5), (0, 1, 6), (0, 2, 2), (0, 2, 3), (0, 2, 4), (0, 2, 5), (0, 2, 6), (0, 3, 3), (0, 3, 4), (0, 3, 5), (0, 3, 6), (0, 4, 4), (0, 4, 5), (0, 4, 6), (0, 5, 5), (0, 5, 6), (0, 6, 6), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 1, 5), (1, 1, 6), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 2, 6), (1, 3, 3), (1, 3, 4), (1, 3, 5), (1, 3, 6), (1, 4, 4), (1, 4, 5), (1, 4, 6), (1, 5, 5), (1, 5, 6), (1, 6, 6), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 2, 5), (2, 2, 6), (2, 3, 3), (2, 3, 4), (2, 3, 5), (2, 3, 6), (2, 4, 4), (2, 4, 5), (2, 4, 6), (2, 5, 5), (2, 5, 6), (2, 6, 6), (3, 3, 3), (3, 3, 4), (3, 3, 5), (3, 3, 6), (3, 4, 4), (3, 4, 5), (3, 4, 6), (3, 5, 5), (3, 5, 6), (3, 6, 6), (4, 4, 4), (4, 4, 5), (4, 4, 6), (4, 5, 5), (4, 5, 6), (4, 6, 6), (5, 5, 5), (5, 5, 6), (5, 6, 6), (6, 6, 6)];
|
||||||
|
|
||||||
|
const SCORE_LUT: [u8; 128] = [
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 4, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 12, 7, 8, 9, 16, 9, 10, 20, 11, 24, 27,
|
||||||
|
6, 7, 8, 9, 10, 9, 6, 7, 8, 9, 13, 8, 9, 10, 17, 10, 11, 21, 12, 25, 54, 11, 12, 13, 14, 14, 9,
|
||||||
|
10, 11, 18, 11, 12, 22, 13, 26, 81, 16, 17, 18, 19, 12, 13, 23, 14, 27, 108, 21, 22, 24, 15,
|
||||||
|
28, 135, 26, 29, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
const ADD_LUT: [[u8; 32]; 8] = [
|
||||||
|
[0; 32],
|
||||||
|
[
|
||||||
|
1, 7, 8, 9, 10, 11, 12, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
||||||
|
45, 46, 47, 48, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2, 8, 13, 14, 15, 16, 17, 29, 34, 35, 36, 37, 38, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
||||||
|
59, 60, 61, 62, 63, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3, 9, 14, 18, 19, 20, 21, 30, 35, 39, 40, 41, 42, 50, 54, 55, 56, 57, 64, 65, 66, 67, 68,
|
||||||
|
69, 70, 71, 72, 73, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
4, 10, 15, 19, 22, 23, 24, 31, 36, 40, 43, 44, 45, 51, 55, 58, 59, 60, 65, 68, 69, 70, 74,
|
||||||
|
75, 76, 77, 78, 79, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
5, 11, 16, 20, 23, 25, 26, 32, 37, 41, 44, 46, 47, 52, 56, 59, 61, 62, 66, 69, 71, 72, 75,
|
||||||
|
77, 78, 80, 81, 82, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
6, 12, 17, 21, 24, 26, 27, 33, 38, 42, 45, 47, 48, 53, 57, 60, 62, 63, 67, 70, 72, 73, 76,
|
||||||
|
78, 79, 81, 82, 83, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[0; 32],
|
||||||
|
];
|
||||||
|
|
||||||
|
const REMOVE_LUT: [[u8; 128]; 8] = [
|
||||||
|
[0; 128],
|
||||||
|
[
|
||||||
|
0, 0, 2, 3, 4, 5, 6, 0, 2, 3, 4, 5, 6, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||||
|
26, 27, 0, 2, 3, 4, 5, 6, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0, 1, 0, 3, 4, 5, 6, 7, 1, 9, 10, 11, 12, 0, 3, 4, 5, 6, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||||
|
26, 27, 28, 7, 30, 31, 32, 33, 1, 9, 10, 11, 12, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 0,
|
||||||
|
3, 4, 5, 6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||||
|
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0, 1, 2, 0, 4, 5, 6, 7, 8, 1, 10, 11, 12, 13, 2, 15, 16, 17, 0, 4, 5, 6, 22, 23, 24, 25,
|
||||||
|
26, 27, 28, 29, 7, 31, 32, 33, 34, 8, 36, 37, 38, 1, 10, 11, 12, 43, 44, 45, 46, 47, 48,
|
||||||
|
49, 13, 51, 52, 53, 2, 15, 16, 17, 58, 59, 60, 61, 62, 63, 0, 4, 5, 6, 22, 23, 24, 25, 26,
|
||||||
|
27, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0, 1, 2, 3, 0, 5, 6, 7, 8, 9, 1, 11, 12, 13, 14, 2, 16, 17, 18, 3, 20, 21, 0, 5, 6, 25, 26,
|
||||||
|
27, 28, 29, 30, 7, 32, 33, 34, 35, 8, 37, 38, 39, 9, 41, 42, 1, 11, 12, 46, 47, 48, 49, 50,
|
||||||
|
13, 52, 53, 54, 14, 56, 57, 2, 16, 17, 61, 62, 63, 64, 18, 66, 67, 3, 20, 21, 71, 72, 73,
|
||||||
|
0, 5, 6, 25, 26, 27, 80, 81, 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0, 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 1, 12, 13, 14, 15, 2, 17, 18, 19, 3, 21, 22, 4, 24, 0, 6,
|
||||||
|
27, 28, 29, 30, 31, 7, 33, 34, 35, 36, 8, 38, 39, 40, 9, 42, 43, 10, 45, 1, 12, 48, 49, 50,
|
||||||
|
51, 13, 53, 54, 55, 14, 57, 58, 15, 60, 2, 17, 63, 64, 65, 18, 67, 68, 19, 70, 3, 21, 73,
|
||||||
|
74, 22, 76, 4, 24, 79, 0, 6, 27, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0, 1, 2, 3, 4, 5, 0, 7, 8, 9, 10, 11, 1, 13, 14, 15, 16, 2, 18, 19, 20, 3, 22, 23, 4, 25,
|
||||||
|
5, 0, 28, 29, 30, 31, 32, 7, 34, 35, 36, 37, 8, 39, 40, 41, 9, 43, 44, 10, 46, 11, 1, 49,
|
||||||
|
50, 51, 52, 13, 54, 55, 56, 14, 58, 59, 15, 61, 16, 2, 64, 65, 66, 18, 68, 69, 19, 71, 20,
|
||||||
|
3, 74, 75, 22, 77, 23, 4, 80, 25, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
[0; 128],
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn add_is_valid(column: u8) -> bool {
|
||||||
|
column < 28
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(die: u8, column: u8) -> u8 {
|
||||||
|
ADD_LUT[(die & 0b111) as usize][(column & 0b11111) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(die: u8, column: u8) -> u8 {
|
||||||
|
REMOVE_LUT[(die & 0b111) as usize][(column & 0b1111111) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Column {
|
||||||
|
L = 0,
|
||||||
|
C = 2,
|
||||||
|
R = 4,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Player {
|
pub enum Player {
|
||||||
Bottom,
|
Bottom,
|
||||||
Top,
|
Top,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum Column {
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encodes the state of the game
|
|
||||||
///
|
|
||||||
/// Each cell can take 7 values (empty or 1-6) -> 3 * 18 = 54 bits required.
|
|
||||||
/// We need one additional bit to store which player's turn it is.
|
|
||||||
///
|
|
||||||
/// Cell Layout:
|
|
||||||
/// ```
|
|
||||||
/// 11 14 17
|
|
||||||
/// 10 13 16
|
|
||||||
/// 9 12 15
|
|
||||||
///
|
|
||||||
/// 0 3 6
|
|
||||||
/// 1 4 7
|
|
||||||
/// 2 5 8
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Offsets:
|
|
||||||
/// ```
|
|
||||||
/// 33 42 51
|
|
||||||
/// 30 39 48
|
|
||||||
/// 27 36 45
|
|
||||||
///
|
|
||||||
/// 0 9 18
|
|
||||||
/// 3 12 21
|
|
||||||
/// 6 15 24
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// current_player: `54`
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Board(u64);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IllegalMove(());
|
pub struct IllegalMove(());
|
||||||
|
|
||||||
|
pub struct Board {
|
||||||
|
columns: [u8; 6],
|
||||||
|
pub current_player: Player,
|
||||||
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::from_values([&[], &[], &[]], [&[], &[], &[]], Player::Bottom)
|
Self {
|
||||||
}
|
columns: [0, 0, 0, 0, 0, 0],
|
||||||
|
current_player: Player::Bottom,
|
||||||
pub fn from_values(bottom: [&[u8]; 3], top: [&[u8]; 3], current_player: Player) -> Self {
|
|
||||||
let mut bits = 0;
|
|
||||||
for (start, half) in [(0, bottom), (27, top)] {
|
|
||||||
for (index, &col) in half.iter().enumerate() {
|
|
||||||
for (offset, &val) in col.iter().enumerate() {
|
|
||||||
let shift = start + index * 9 + offset * 3;
|
|
||||||
bits |= (val as u64) << shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_player == Player::Top {
|
|
||||||
bits |= 1 << 54
|
|
||||||
}
|
|
||||||
|
|
||||||
Self(bits)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visualize(&self) {
|
pub fn visualize(&self) {
|
||||||
let &Self(bits) = self;
|
let [a, b, c, d, e, f] = self.columns;
|
||||||
|
|
||||||
let print_half = |rows| {
|
|
||||||
for row in rows {
|
|
||||||
for offset in row {
|
|
||||||
let value = (bits >> offset & 0b111u64) as u8;
|
|
||||||
if value > 0 {
|
|
||||||
print!("{value} ");
|
|
||||||
} else {
|
|
||||||
print!("_ ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
print_half([[33, 42, 51], [30, 39, 48], [27, 36, 45]]);
|
|
||||||
println!();
|
|
||||||
print_half([[0, 9, 18], [3, 12, 21], [6, 15, 24]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_player(&self) -> Player {
|
|
||||||
let &Self(bits) = self;
|
|
||||||
if bits >> 54 & 1 == 0 {
|
|
||||||
Player::Bottom
|
|
||||||
} else {
|
|
||||||
Player::Top
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_game_over(&self) -> bool {
|
|
||||||
let &Self(bits) = self;
|
|
||||||
let has_empty_slots = |offset| -> bool {
|
|
||||||
for i in [0, 3, 6] {
|
|
||||||
if (bits >> offset + i) & 0b111u64 == 0u64 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
!((has_empty_slots(0) || has_empty_slots(9) || has_empty_slots(18))
|
println!("{b:02X} {d:02X} {f:02X}");
|
||||||
&& (has_empty_slots(27) || has_empty_slots(36) || has_empty_slots(45)))
|
println!("{a:02X} {c:02X} {e:02X}");
|
||||||
|
|
||||||
|
let (l1, l2, l3) = MAPPING[b as usize];
|
||||||
|
let (l4, l5, l6) = MAPPING[a as usize];
|
||||||
|
let (c1, c2, c3) = MAPPING[d as usize];
|
||||||
|
let (c4, c5, c6) = MAPPING[c as usize];
|
||||||
|
let (r1, r2, r3) = MAPPING[f as usize];
|
||||||
|
let (r4, r5, r6) = MAPPING[e as usize];
|
||||||
|
|
||||||
|
println!("{l1} {c1} {r1}");
|
||||||
|
println!("{l2} {c2} {r2}");
|
||||||
|
println!("{l3} {c3} {r3}");
|
||||||
|
println!();
|
||||||
|
println!("{l6} {c6} {r6}");
|
||||||
|
println!("{l5} {c5} {r5}");
|
||||||
|
println!("{l4} {c4} {r4}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (bottom, top)
|
|
||||||
pub fn column_scores(&self) -> ((u8, u8, u8), (u8, u8, u8)) {
|
pub fn column_scores(&self) -> ((u8, u8, u8), (u8, u8, u8)) {
|
||||||
let &Self(bits) = self;
|
let [a, b, c, d, e, f] = self.columns;
|
||||||
|
|
||||||
let score_col = |offset| {
|
|
||||||
let mut counts = [0; 6];
|
|
||||||
for i in [0, 3, 6] {
|
|
||||||
let value = ((bits >> offset + i) & 0b111u64) as usize;
|
|
||||||
if value == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
counts[value - 1] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
counts
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(value, &count)| {
|
|
||||||
let value = (value + 1) as u8;
|
|
||||||
value
|
|
||||||
* count
|
|
||||||
* match count {
|
|
||||||
2 => 2,
|
|
||||||
3 => 9,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sum()
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
(
|
||||||
(score_col(0), score_col(9), score_col(18)),
|
(
|
||||||
(score_col(27), score_col(36), score_col(45)),
|
SCORE_LUT[(a & 0x7F) as usize],
|
||||||
|
SCORE_LUT[(b & 0x7F) as usize],
|
||||||
|
SCORE_LUT[(c & 0x7F) as usize],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
SCORE_LUT[(d & 0x7F) as usize],
|
||||||
|
SCORE_LUT[(e & 0x7F) as usize],
|
||||||
|
SCORE_LUT[(f & 0x7F) as usize],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,83 +169,37 @@ impl Board {
|
|||||||
a as i16 + b as i16 + c as i16 - d as i16 - e as i16 - f as i16
|
a as i16 + b as i16 + c as i16 - d as i16 - e as i16 - f as i16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn play(&self, column: Column, value: u8) -> Result<Self, IllegalMove> {
|
pub fn play(&self, column: Column, die: u8) -> Result<Self, IllegalMove> {
|
||||||
let Self(mut bits) = *self;
|
let a = &self.columns;
|
||||||
|
if !add_is_valid(a[column as usize]) {
|
||||||
let mut apply_move = |offset, opposite| -> Result<(), IllegalMove> {
|
return Err(IllegalMove(()));
|
||||||
// push value to the first zero after offset
|
|
||||||
let mut found = false;
|
|
||||||
for index in [0, 3, 6] {
|
|
||||||
if ((bits >> offset + index) & 0b111u64) != 0u64 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
bits &= !((0b111u64 << offset + index) as u64);
|
|
||||||
bits |= (value as u64) << offset + index;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// raise if all three are non-zero
|
|
||||||
if !found {
|
|
||||||
return Err(IllegalMove(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// eliminate all occurences from value after opposite
|
|
||||||
let mut tmp = [0, 0, 0];
|
|
||||||
let mut i = 0;
|
|
||||||
for index in [0, 3, 6] {
|
|
||||||
let other = ((bits >> opposite + index) & 0b111u64) as u8;
|
|
||||||
if other == value {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tmp[i] = other;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if i != 3 {
|
|
||||||
for (index, &value) in tmp.iter().enumerate() {
|
|
||||||
bits &= !((0b111u64 << opposite + index) as u64);
|
|
||||||
bits |= (value as u64) << opposite + index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
match (column, self.current_player()) {
|
|
||||||
(Column::Left, Player::Bottom) => apply_move(0, 27)?,
|
|
||||||
(Column::Left, Player::Top) => apply_move(27, 0)?,
|
|
||||||
(Column::Center, Player::Bottom) => apply_move(9, 36)?,
|
|
||||||
(Column::Center, Player::Top) => apply_move(36, 9)?,
|
|
||||||
(Column::Right, Player::Bottom) => apply_move(18, 45)?,
|
|
||||||
(Column::Right, Player::Top) => apply_move(45, 18)?,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch current player
|
let mut a = a.clone();
|
||||||
bits ^= 1 << 54;
|
|
||||||
|
|
||||||
Ok(Self(bits))
|
let (current, opposite) = match self.current_player {
|
||||||
}
|
Player::Bottom => (column as usize, column as usize + 1),
|
||||||
}
|
Player::Top => (column as usize + 1, column as usize)
|
||||||
|
};
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
a[current] = add(die, a[current]);
|
||||||
use super::*;
|
a[opposite] = remove(die, a[opposite]);
|
||||||
|
|
||||||
#[test]
|
let player = match self.current_player {
|
||||||
fn test_example() {
|
Player::Top => Player::Bottom,
|
||||||
let board = Board::from_values(
|
Player::Bottom => Player::Top,
|
||||||
[&[6, 5, 5], &[5, 5], &[1, 5]],
|
};
|
||||||
[&[2, 2, 1], &[4, 3, 3], &[4, 2, 3]],
|
|
||||||
Player::Bottom,
|
Ok(Self {
|
||||||
);
|
columns: a,
|
||||||
|
current_player: player,
|
||||||
board.visualize();
|
})
|
||||||
|
}
|
||||||
assert_eq!(board.column_scores(), ((26, 20, 6), (9, 16, 9)));
|
|
||||||
assert!(board.score() > 0);
|
pub fn is_game_over(&self) -> bool {
|
||||||
assert!(board.is_game_over());
|
let [a, b, c, d, e, f] = self.columns;
|
||||||
|
|
||||||
|
!((add_is_valid(a) | add_is_valid(b) | add_is_valid(c))
|
||||||
|
& (add_is_valid(d) | add_is_valid(e) | add_is_valid(f)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ fn main() {
|
|||||||
|
|
||||||
while !b.is_game_over() {
|
while !b.is_game_over() {
|
||||||
b.visualize();
|
b.visualize();
|
||||||
println!("Current player: {:?}", b.current_player());
|
println!("Current player: {:?}", b.current_player);
|
||||||
|
|
||||||
let d6 = (Select::new().items(&[1, 2, 3, 4, 5, 6]).interact().unwrap() + 1) as u8;
|
let d6 = (Select::new().items(&[1, 2, 3, 4, 5, 6]).interact().unwrap() + 1) as u8;
|
||||||
|
|
||||||
let column = [Column::Left, Column::Center, Column::Right][Select::new()
|
let column = [Column::L, Column::C, Column::R][Select::new()
|
||||||
.items(&["Left", "Center", "Right"])
|
.items(&["Left", "Center", "Right"])
|
||||||
.interact()
|
.interact()
|
||||||
.unwrap()];
|
.unwrap()];
|
||||||
|
Loading…
Reference in New Issue
Block a user