finish leg/game randomly (untested)
This commit is contained in:
parent
b3e7ae7900
commit
45deb93a4f
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -2,11 +2,18 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cup"
|
name = "cup"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -29,6 +36,29 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.139"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.49"
|
version = "1.0.49"
|
||||||
@ -47,6 +77,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.107"
|
||||||
@ -63,3 +123,9 @@ name = "unicode-ident"
|
|||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
"enum-map" = "2.4.2"
|
"enum-map" = "2.4.2"
|
||||||
|
"rand" = "0.8.5"
|
||||||
|
85
src/game.rs
85
src/game.rs
@ -1,4 +1,9 @@
|
|||||||
use enum_map::{Enum, EnumMap};
|
use enum_map::{Enum, EnumMap};
|
||||||
|
use rand::{
|
||||||
|
Rng,
|
||||||
|
seq::SliceRandom,
|
||||||
|
distributions::{Distribution, Uniform},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::stack::Stack;
|
use crate::stack::Stack;
|
||||||
|
|
||||||
@ -8,7 +13,7 @@ pub enum Color {
|
|||||||
#[default] Red, Green, Blue, Yellow, Purple,
|
#[default] Red, Green, Blue, Yellow, Purple,
|
||||||
}
|
}
|
||||||
|
|
||||||
// const COLORS: Stack<Color, 5> = Stack::from([
|
// const COLORS: Stack<Color, 5> = Stack::from_array([
|
||||||
// Color::Red,
|
// Color::Red,
|
||||||
// Color::Green,
|
// Color::Green,
|
||||||
// Color::Blue,
|
// Color::Blue,
|
||||||
@ -16,6 +21,14 @@ pub enum Color {
|
|||||||
// Color::Purple,
|
// Color::Purple,
|
||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
|
const COLORS: [Color; 5] = [
|
||||||
|
Color::Red,
|
||||||
|
Color::Green,
|
||||||
|
Color::Blue,
|
||||||
|
Color::Yellow,
|
||||||
|
Color::Purple,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
type ColorStack = Stack<Color, 5>;
|
type ColorStack = Stack<Color, 5>;
|
||||||
|
|
||||||
@ -68,6 +81,20 @@ impl Game {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new game with random starting positions
|
||||||
|
fn new_random() -> Self {
|
||||||
|
let mut game = Self::default();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut dice = *&COLORS;
|
||||||
|
dice.shuffle(&mut rng);
|
||||||
|
for color in dice {
|
||||||
|
let roll = rng.gen_range(1..=3);
|
||||||
|
game.squares[roll - 1].assume_stack_mut().push(color);
|
||||||
|
game.camels[color] = roll - 1;
|
||||||
|
}
|
||||||
|
game
|
||||||
|
}
|
||||||
|
|
||||||
fn set_state(&mut self, squares: [Square; 16], dice: EnumMap<Color, bool>) {
|
fn set_state(&mut self, squares: [Square; 16], dice: EnumMap<Color, bool>) {
|
||||||
self.squares = squares;
|
self.squares = squares;
|
||||||
self.dice = dice;
|
self.dice = dice;
|
||||||
@ -80,17 +107,6 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_positions(&mut self, target_sq: usize) {
|
|
||||||
match self.squares[target_sq] {
|
|
||||||
Square::Camels(stack) => {
|
|
||||||
for camel in stack.iter() {
|
|
||||||
self.camels[*camel] = target_sq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns winner if there is one
|
// returns winner if there is one
|
||||||
fn advance(&mut self, die: Color, roll: usize) -> Option<Color> {
|
fn advance(&mut self, die: Color, roll: usize) -> Option<Color> {
|
||||||
let src_sq = self.camels[die];
|
let src_sq = self.camels[die];
|
||||||
@ -144,6 +160,49 @@ impl Game {
|
|||||||
self.dice[die] = true;
|
self.dice[die] = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn finish_leg_random(&mut self) -> Option<Color> {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut leg_dice: Stack<Color, 5> = Stack::new();
|
||||||
|
for (color, rolled) in self.dice {
|
||||||
|
if !rolled {
|
||||||
|
leg_dice.push(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(&mut leg_dice[..]).shuffle(&mut rng);
|
||||||
|
|
||||||
|
for color in leg_dice.iter() {
|
||||||
|
let roll = rng.gen_range(1..=3);
|
||||||
|
if let Some(winner) = self.advance(*color, roll) {
|
||||||
|
return Some(winner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_game_random(&mut self) -> Color {
|
||||||
|
if let Some(winner) = self.finish_leg_random() {
|
||||||
|
return winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are now guaranteed to be at the start of a new leg,
|
||||||
|
// so we don't need to check the dice state
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let roll_dist = Uniform::from(0..=3);
|
||||||
|
let mut dice = *&COLORS; // makes a copy of the constant
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// easiest if we shuffle at the start of the leg
|
||||||
|
dice.shuffle(&mut rng);
|
||||||
|
for i in 0..5 {
|
||||||
|
let roll = roll_dist.sample(&mut rng);
|
||||||
|
if let Some(winner) = self.advance(dice[i], roll) {
|
||||||
|
return winner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -187,4 +246,6 @@ mod test {
|
|||||||
assert_eq!(game.squares[3].assume_stack(), &Stack::from([Red, Purple, Yellow]));
|
assert_eq!(game.squares[3].assume_stack(), &Stack::from([Red, Purple, Yellow]));
|
||||||
// B, _, G, RPY
|
// B, _, G, RPY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
39
src/stack.rs
39
src/stack.rs
@ -1,4 +1,4 @@
|
|||||||
use std::ops::Index;
|
use std::ops::{Index, IndexMut, RangeFull};
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
|
|
||||||
|
|
||||||
@ -35,6 +35,13 @@ impl<T, const S: usize> Stack<T, S> {
|
|||||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
self.data.iter().take(self.len)
|
self.data.iter().take(self.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn from_array(array: [T; S]) -> Self {
|
||||||
|
Stack {
|
||||||
|
data: array,
|
||||||
|
len: S,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,12 +101,24 @@ where T: Copy + Default
|
|||||||
|
|
||||||
impl<T, const S: usize> Index<usize> for Stack<T, S> {
|
impl<T, const S: usize> Index<usize> for Stack<T, S> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &T {
|
fn index(&self, index: usize) -> &T {
|
||||||
&self.data[index]
|
&self.data[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, const S: usize> Index<RangeFull> for Stack<T, S> {
|
||||||
|
type Output = [T];
|
||||||
|
fn index(&self, _index: RangeFull) -> &[T] {
|
||||||
|
&self.data[..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const S: usize> IndexMut<RangeFull> for Stack<T, S> {
|
||||||
|
fn index_mut(&mut self, _index: RangeFull) -> &mut [T] {
|
||||||
|
&mut self.data[..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<I, T, const S: usize> From<I> for Stack<T, S>
|
impl<I, T, const S: usize> From<I> for Stack<T, S>
|
||||||
where
|
where
|
||||||
@ -223,4 +242,20 @@ mod test {
|
|||||||
assert_eq!(it.next(), Some(&3));
|
assert_eq!(it.next(), Some(&3));
|
||||||
assert_eq!(it.next(), None);
|
assert_eq!(it.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_array() {
|
||||||
|
let s = Stack::from_array([1, 2, 3]);
|
||||||
|
assert_eq!(s[0], 1);
|
||||||
|
assert_eq!(s[1], 2);
|
||||||
|
assert_eq!(s[2], 3);
|
||||||
|
assert_eq!(s.len(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_index() {
|
||||||
|
let mut s = Stack::<_, 5>::from([3, 4, 5]);
|
||||||
|
assert_eq!(s[..], [3, 4, 5]);
|
||||||
|
assert_eq!(&mut s[..], &mut [3, 4, 5]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user