RIIR
This commit is contained in:
+380
@@ -0,0 +1,380 @@
|
||||
use enum_map::{Enum, EnumMap};
|
||||
use rand::{
|
||||
Rng,
|
||||
seq::SliceRandom,
|
||||
distributions::{Distribution, Uniform},
|
||||
};
|
||||
|
||||
use crate::stack::Stack;
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Enum)]
|
||||
pub enum Color {
|
||||
#[default] Red, Green, Blue, Yellow, Purple,
|
||||
}
|
||||
|
||||
// const COLORS: Stack<Color, 5> = Stack::from_array([
|
||||
// Color::Red,
|
||||
// Color::Green,
|
||||
// Color::Blue,
|
||||
// Color::Yellow,
|
||||
// Color::Purple,
|
||||
// ]);
|
||||
|
||||
const COLORS: [Color; 5] = [
|
||||
Color::Red,
|
||||
Color::Green,
|
||||
Color::Blue,
|
||||
Color::Yellow,
|
||||
Color::Purple,
|
||||
];
|
||||
|
||||
|
||||
type ColorStack = Stack<Color, 5>;
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Tile {
|
||||
Forward,
|
||||
Backward,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Square {
|
||||
Camels(ColorStack),
|
||||
Tile(Tile),
|
||||
}
|
||||
|
||||
impl Square {
|
||||
fn assume_stack(&self) -> &ColorStack {
|
||||
match self {
|
||||
Square::Camels(stack) => stack,
|
||||
_ => panic!("Attempted to use the stack from a non-stack square"),
|
||||
}
|
||||
}
|
||||
|
||||
fn assume_stack_mut(&mut self) -> &mut ColorStack {
|
||||
match self {
|
||||
Square::Camels(stack) => stack,
|
||||
_ => panic!("Attempted to use the stack from a non-stack square"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Square {
|
||||
fn default() -> Self {
|
||||
Square::Camels(ColorStack::new())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct Game {
|
||||
squares: [Square; 16],
|
||||
dice: EnumMap<Color, bool>,
|
||||
camels: EnumMap<Color, usize>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
// new game with random starting positions
|
||||
pub 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
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, camels: &[(Color, usize); 5], dice: &EnumMap<Color, bool>) {
|
||||
for i in 0..16 {
|
||||
self.squares[i] = match self.squares[i] {
|
||||
Square::Camels(mut stack) => {
|
||||
stack.clear();
|
||||
Square::Camels(stack)
|
||||
},
|
||||
_ => Square::Camels(Stack::new())
|
||||
};
|
||||
}
|
||||
|
||||
for square in self.squares {
|
||||
assert_eq!(square.assume_stack().len(), 0)
|
||||
}
|
||||
|
||||
self.dice = *dice;
|
||||
for &(color, sq) in camels {
|
||||
self.squares[sq].assume_stack_mut().push(color);
|
||||
self.camels[color] = sq;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> ([(Color, usize); 5], EnumMap<Color, bool>) {
|
||||
let mut state = [(Color::Red, 0); 5];
|
||||
|
||||
let mut j = 0;
|
||||
for (sq_idx, square) in self.squares.iter().enumerate() {
|
||||
if let Square::Camels(stack) = square {
|
||||
for camel in stack.iter() {
|
||||
state[j] = (*camel, sq_idx);
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(state, self.dice)
|
||||
}
|
||||
|
||||
// returns winner if there is one
|
||||
pub fn advance(&mut self, die: Color, roll: usize) -> Option<Color> {
|
||||
let src_sq = self.camels[die];
|
||||
let dst_sq = src_sq + roll;
|
||||
if dst_sq >= 16 {
|
||||
self.dice[die] = true;
|
||||
return self.squares[src_sq].assume_stack().last().copied();
|
||||
}
|
||||
|
||||
// special case when the destination square is the same as the source square
|
||||
if let Square::Tile(Tile::Backward) = self.squares[dst_sq] {
|
||||
if roll == 1 {
|
||||
let src_stack = self.squares[src_sq].assume_stack_mut();
|
||||
let slice_start = src_stack.iter().position(|&c| c == die).unwrap();
|
||||
src_stack.shift_slice_under(slice_start);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we have to split self.squares into two slices using split_at_mut, otherwise
|
||||
// rustc complains that we're trying to use two mutable references to the same value
|
||||
let (left, right) = self.squares.split_at_mut(src_sq + 1);
|
||||
let src_stack = left[src_sq].assume_stack_mut();
|
||||
let slice_start = src_stack.iter().position(|&c| c == die).unwrap();
|
||||
|
||||
// since `right` starts immediately after the source square, the index of the
|
||||
// destination square will be roll - 1 (e.g. if roll is 1, dst will be right[0])
|
||||
let (dst_rel_idx, prepend) = match right[roll - 1] {
|
||||
Square::Tile(Tile::Forward) => (roll, false), // roll - 1 + 1
|
||||
Square::Tile(Tile::Backward) => (roll - 2, true), // roll is guaranteed to be >= 2 since we already handled roll == 1
|
||||
_ => (roll - 1, false),
|
||||
};
|
||||
let dst_stack = right[dst_rel_idx].assume_stack_mut();
|
||||
let dst_true_idx = src_sq + 1 + dst_rel_idx; // src_sq + 1 was the original split boundary, so add the relative index to that to get the true index
|
||||
|
||||
if prepend {
|
||||
let slice_len = src_stack.len() - slice_start;
|
||||
src_stack.move_slice_under(dst_stack, slice_start);
|
||||
for i in 0..slice_len {
|
||||
self.camels[dst_stack[i]] = dst_true_idx;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let dst_prev_len = dst_stack.len();
|
||||
src_stack.move_slice(dst_stack, slice_start);
|
||||
for i in dst_prev_len..dst_stack.len() {
|
||||
self.camels[dst_stack[i]] = dst_true_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.dice[die] = true;
|
||||
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(1..=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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn project_outcomes(&self, count: usize) -> EnumMap<Color, usize> {
|
||||
let (orig_camels, orig_dice) = self.get_state();
|
||||
let mut projection = *self;
|
||||
|
||||
let mut scores: EnumMap<Color, usize> = EnumMap::default();
|
||||
for i in 0..count {
|
||||
let winner = projection.finish_game_random();
|
||||
scores[winner] += 1;
|
||||
projection.set_state(&orig_camels, &orig_dice);
|
||||
}
|
||||
|
||||
scores
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use Color::*;
|
||||
|
||||
#[test]
|
||||
fn test_advance() {
|
||||
let mut game = Game::new();
|
||||
// all dice are false (not rolled) to start with
|
||||
assert_eq!(game.dice.values().any(|&v| v), false);
|
||||
|
||||
let camel_state = [
|
||||
(Blue, 0),
|
||||
(Yellow, 0),
|
||||
(Red, 1),
|
||||
(Green, 2),
|
||||
(Purple, 2),
|
||||
];
|
||||
game.set_state(&camel_state, &Default::default());
|
||||
assert_eq!(game.squares[0].assume_stack(), &Stack::from([Blue, Yellow]));
|
||||
assert_eq!(game.camels[Blue], 0);
|
||||
assert_eq!(game.camels[Yellow], 0);
|
||||
assert_eq!(game.squares[1].assume_stack(), &Stack::from([Red]));
|
||||
assert_eq!(game.camels[Red], 1);
|
||||
assert_eq!(game.squares[2].assume_stack(), &Stack::from([Green, Purple]));
|
||||
assert_eq!(game.camels[Green], 2);
|
||||
assert_eq!(game.camels[Purple], 2);
|
||||
// BY, R, GP
|
||||
|
||||
game.advance(Yellow, 2);
|
||||
assert_eq!(game.dice[Yellow], true);
|
||||
assert_eq!(game.camels[Yellow], 2);
|
||||
assert_eq!(game.squares[2].assume_stack(), &Stack::from([Green, Purple, Yellow]));
|
||||
// B, R, GPY
|
||||
|
||||
game.advance(Red, 2);
|
||||
assert_eq!(game.dice[Red], true);
|
||||
assert_eq!(game.camels[Red], 3);
|
||||
// B, _, GPY, R
|
||||
|
||||
game.advance(Purple, 1);
|
||||
assert_eq!(game.dice[Purple], true);
|
||||
assert_eq!(game.squares[3].assume_stack(), &Stack::from([Red, Purple, Yellow]));
|
||||
// B, _, G, RPY
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_random() {
|
||||
for _ in 0..100 {
|
||||
let game = Game::new_random();
|
||||
for (camel, i) in game.camels {
|
||||
assert!(i < 3); // since we've only rolled the die once for each camel
|
||||
let stack = game.squares[i].assume_stack();
|
||||
assert!(stack[..].contains(&camel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finish_leg() {
|
||||
let mut game = Game::new();
|
||||
let camel_state = [
|
||||
(Purple, 0),
|
||||
(Blue, 0),
|
||||
(Green, 1),
|
||||
(Red, 1),
|
||||
(Yellow, 2),
|
||||
];
|
||||
game.set_state(&camel_state, &Default::default());
|
||||
// PB, G, RY
|
||||
game.advance(Green, 2);
|
||||
// PB, _, RY, G
|
||||
game.advance(Purple, 1);
|
||||
// _, PB, RY, G
|
||||
|
||||
// since this is randomized, we should do it a bunch of times to make sure
|
||||
for _ in 0..100 {
|
||||
let mut projection = game; // copy?
|
||||
assert_eq!(projection.squares[1].assume_stack(), &Stack::from([Purple, Blue]));
|
||||
projection.finish_leg_random();
|
||||
// since we already rolled Green, it can't have moved
|
||||
assert_eq!(projection.camels[Green], 3);
|
||||
// likewise purple
|
||||
assert_eq!(projection.camels[Purple], 1);
|
||||
// blue, red,and yellow, on the other hand, *must* have moved
|
||||
assert_ne!(projection.camels[Blue], 1);
|
||||
assert_ne!(projection.camels[Red], 2);
|
||||
assert_ne!(projection.camels[Yellow], 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finish_leg_winner() {
|
||||
let mut game = Game::new();
|
||||
let camel_state = [
|
||||
(Green, 13),
|
||||
(Red, 14),
|
||||
(Purple, 14),
|
||||
(Blue, 15),
|
||||
(Yellow, 15),
|
||||
];
|
||||
game.set_state(&camel_state, &Default::default());
|
||||
|
||||
// since there are no tiles involved, and multiple camels are on 15, there must be a winner
|
||||
assert!(matches!(game.finish_leg_random(), Some(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_project_outcomes() {
|
||||
let mut game = Game::new();
|
||||
let camel_state = [
|
||||
(Blue, 1),
|
||||
(Green, 2),
|
||||
(Yellow, 2),
|
||||
(Purple, 4),
|
||||
(Red, 10),
|
||||
];
|
||||
game.set_state(&camel_state, &Default::default());
|
||||
// _, B, GY, _, P, _, _, _, _, _, R
|
||||
|
||||
let scores = game.project_outcomes(10_000);
|
||||
let mut max = 0;
|
||||
let mut winner = Blue; // just "anything that's not red"
|
||||
for (color, score) in scores {
|
||||
if score > max {
|
||||
max = score;
|
||||
winner = color;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(winner, Red);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
use std::time::Instant;
|
||||
|
||||
mod stack;
|
||||
mod game;
|
||||
|
||||
use game::Game;
|
||||
|
||||
|
||||
fn main() {
|
||||
let n_games = 10_000_000;
|
||||
|
||||
let start = Instant::now();
|
||||
let game = Game::new_random();
|
||||
let _scores = game.project_outcomes(n_games);
|
||||
let end = Instant::now();
|
||||
|
||||
let elapsed = end.duration_since(start);
|
||||
let secs = elapsed.as_secs();
|
||||
let hundredths = elapsed.subsec_millis() / 10; // technically not accurate but good enough for now
|
||||
|
||||
let rate = (10_000_000 as f64) / elapsed.as_secs_f64();
|
||||
|
||||
println!("Test completed:");
|
||||
println!("{n_games} in {secs}.{hundredths:02} seconds", );
|
||||
println!("Games per second: {rate}");
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
use std::ops::{Index, IndexMut, RangeFull};
|
||||
use std::iter::IntoIterator;
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Stack<T, const S: usize> {
|
||||
data: [T; S],
|
||||
len: usize // we can experiment with using u8 some other time
|
||||
}
|
||||
|
||||
|
||||
impl<T, const S: usize> Stack<T, S> {
|
||||
pub fn push(&mut self, v: T) {
|
||||
self.data[self.len] = v;
|
||||
self.len += 1;
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
pub fn last(&self) -> Option<&T> {
|
||||
if self.len == 0 {
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(&self.data[self.len - 1])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
self.data.iter().take(self.len)
|
||||
}
|
||||
|
||||
pub const fn from_array(array: [T; S]) -> Self {
|
||||
Stack {
|
||||
data: array,
|
||||
len: S,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> [T; S] {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T, const S: usize> Stack<T, S>
|
||||
where T: Copy + Default
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
data: [Default::default(); S],
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_slice(&mut self, dst: &mut Self, start: usize) {
|
||||
let slice_len = self.len - start;
|
||||
let src_slice = &mut self.data[start..self.len];
|
||||
let dst_slice = &mut dst.data[dst.len..(dst.len + slice_len)];
|
||||
dst_slice.copy_from_slice(src_slice);
|
||||
|
||||
self.len -= slice_len;
|
||||
dst.len += slice_len;
|
||||
}
|
||||
|
||||
pub fn move_slice_under(&mut self, dst: &mut Self, start: usize) {
|
||||
let slice_len = self.len - start;
|
||||
let src_slice = &mut self.data[start..self.len];
|
||||
|
||||
dst.data.rotate_right(slice_len);
|
||||
let dst_slice = &mut dst.data[0..slice_len];
|
||||
|
||||
dst_slice.copy_from_slice(src_slice);
|
||||
|
||||
self.len -= slice_len;
|
||||
dst.len += slice_len;
|
||||
}
|
||||
|
||||
// like above, except source and destination are the same, i.e. reordering the stack
|
||||
pub fn shift_slice_under(&mut self, start: usize) {
|
||||
for mut i in start..self.len {
|
||||
while i > 0 {
|
||||
self.data.swap(i, i -1);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T, const S: usize> Default for Stack<T, S>
|
||||
where T: Copy + Default
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T, const S: usize> Index<usize> for Stack<T, S> {
|
||||
type Output = T;
|
||||
fn index(&self, index: usize) -> &T {
|
||||
&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>
|
||||
where
|
||||
T: Copy + Default,
|
||||
I: IntoIterator<Item = T>
|
||||
{
|
||||
fn from(src: I) -> Self {
|
||||
let mut res = Self::new();
|
||||
for (i, item) in src.into_iter().enumerate() {
|
||||
if i >= S {
|
||||
break;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let mut stack: Stack<usize, 5> = Stack::new();
|
||||
stack.push(1);
|
||||
stack.push(2);
|
||||
stack.push(3);
|
||||
|
||||
assert_eq!(stack.len(), 3);
|
||||
assert_eq!(stack[0], 1);
|
||||
assert_eq!(stack[1], 2);
|
||||
assert_eq!(stack[2], 3);
|
||||
|
||||
assert_eq!(stack.last(), Some(&3));
|
||||
|
||||
stack.clear();
|
||||
assert_eq!(stack.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_slice() {
|
||||
let mut a: Stack<usize, 5> = Stack::new();
|
||||
let mut b: Stack<usize, 5> = Stack::new();
|
||||
|
||||
a.push(1);
|
||||
a.push(2);
|
||||
a.push(3);
|
||||
b.push(9);
|
||||
b.push(8);
|
||||
|
||||
a.move_slice(&mut b, 1);
|
||||
assert_eq!(b[2], 2);
|
||||
assert_eq!(b[3], 3);
|
||||
|
||||
b.move_slice(&mut a, 1);
|
||||
assert_eq!(a[1], 8);
|
||||
assert_eq!(a[2], 2);
|
||||
assert_eq!(a[3], 3);
|
||||
|
||||
a.move_slice(&mut b, 0);
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(b[0], 9);
|
||||
assert_eq!(b.last(), Some(&3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_slice_under() {
|
||||
let mut a: Stack<usize, 5> = Stack::new();
|
||||
let mut b: Stack<usize, 5> = Stack::new();
|
||||
|
||||
a.push(1);
|
||||
a.push(2);
|
||||
a.push(3);
|
||||
b.push(9);
|
||||
b.push(8);
|
||||
|
||||
a.move_slice_under(&mut b, 1);
|
||||
assert_eq!(a.len(), 1);
|
||||
assert_eq!(a[0], 1);
|
||||
|
||||
assert_eq!(b.len(), 4);
|
||||
assert_eq!(b[0], 2);
|
||||
assert_eq!(b[3], 8);
|
||||
|
||||
b.move_slice_under(&mut a, 0);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert_eq!(a[0], 2);
|
||||
assert_eq!(a[4], 1);
|
||||
}
|
||||
|
||||
fn test_shift_slice_under() {
|
||||
let mut a: Stack<usize, 5> = Stack::from([1, 2, 3, 4, 5]);
|
||||
a.shift_slice_under(3);
|
||||
assert_eq!(a[0], 4);
|
||||
assert_eq!(a[1], 5);
|
||||
assert_eq!(a[2], 1);
|
||||
assert_eq!(a[3], 2);
|
||||
assert_eq!(a[4], 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let s = Stack::<_, 5>::from([1, 2, 3]);
|
||||
assert_eq!(s[0], 1);
|
||||
assert_eq!(s[2], 3);
|
||||
|
||||
let s = Stack::<_, 2>::from([1, 2, 3]);
|
||||
assert_eq!(s.len(), 2);
|
||||
assert_eq!(s[0], 1);
|
||||
assert_eq!(s[1], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter() {
|
||||
let s = Stack::<_, 5>::from([1, 2, 3]);
|
||||
let mut it = s.iter();
|
||||
assert_eq!(it.next(), Some(&1));
|
||||
assert_eq!(it.next(), Some(&2));
|
||||
assert_eq!(it.next(), Some(&3));
|
||||
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]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user