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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
use chrono::Local;
use env_logger::{Builder, Env, Target};
use std::io::Write;
use std::process::exit;
use std::sync::{Arc, Mutex};
use wwb::*;
/// Roll a d6 and return the result.
fn roll_d6() -> u8 {
fastrand::u8(1..=6)
}
fn current_space_pretty(current_space: u16) -> String {
if current_space == 0 {
"Start".to_string()
} else if current_space == BOARD_SIZE + 1 {
"Finish".to_string()
} else {
current_space.to_string()
}
}
fn main() {
let env = Env::new().filter_or("RUST_LOG", "info");
// Create logger
Builder::from_env(env)
.format(|buf, record| {
writeln!(
buf,
"{} - {}",
Local::now().format("%Y-%m-%dT%H:%M:%S"),
record.args()
)
})
.target(Target::Stdout)
.init();
let game = Arc::new(Mutex::new(Game::default()));
// Set up Ctrl-C handler to print the game state before exiting.
let game_clone = Arc::clone(&game);
ctrlc::set_handler(move || {
let game = game_clone.lock().unwrap();
log::error!("{:#?}", *game);
exit(0);
})
.expect("Error setting Ctrl-C handler");
loop {
let mut game = game.lock().unwrap();
game.turn_count += 1;
// Game loop:
// Player rolls d6
// If not 5, next player's turn
// If 5, roll d6 again
// If not 5, go back to space 0
// If 5 again, go ahead a space
// If players are on the same space that is NOT 0, move BOTH back to space 0
// Next player's turn
// Roll the dice
// This will probably not work properly when the turn count goes above 2^32 on a 32-bit machine and 3^64 on a 64-bit machine.
let current_player_number = game.turn_count as usize % PLAYER_COUNT;
let mut current_space = game.players[current_player_number].current_space;
let current_turn_pretty = game
.turn_count
.to_string()
.as_bytes()
.rchunks(3)
.rev()
.map(std::str::from_utf8)
.collect::<Result<Vec<&str>, _>>()
.unwrap()
.join(",");
let roll = roll_d6();
log::debug!(
"Player {} rolled a {} on turn {} from space {}",
current_player_number,
roll,
current_turn_pretty,
current_space_pretty(current_space)
);
if roll != 5 {
continue;
}
current_space += 1;
// Check if the player has won by reaching the space after the last space.
if current_space == BOARD_SIZE + 1 {
println!("Player {} has reached the Finish space and won on turn {}!", current_player_number, current_turn_pretty);
break;
}
if current_space > game.players[current_player_number].high_score {
log::info!(
"Player {} has a new high score of {} on turn {}",
current_player_number,
current_space_pretty(current_space),
current_turn_pretty
);
game.players[current_player_number].high_score = current_space;
}
let mut collision: bool = false;
for player in game.players.iter_mut() {
if player.current_space == current_space && player.current_space != 0 {
log::debug!(
"Two players collided on space {} on turn {}",
current_space_pretty(current_space),
current_turn_pretty
);
player.current_space = 0;
current_space = 0;
collision = true;
}
}
// No need to run this logic if there was a collision and the current player is already at 0.
if !collision {
if roll_d6() == 5 {
log::debug!(
"Player {} rolled a 5 again on turn {} gets to stay on space {}",
current_player_number,
current_turn_pretty,
current_space_pretty(current_space)
);
} else {
log::debug!(
"Player {} rolled a non-5 after rolling a 5 on turn {} and goes back to Start",
current_player_number,
current_turn_pretty
);
current_space = 0;
}
}
game.players[current_player_number].current_space = current_space;
log::debug!(
"Player {} ends turn {} on space {}",
current_player_number,
current_turn_pretty,
current_space_pretty(current_space)
);
}
}
|