elo: add live leaderboard
This commit is contained in:
parent
222afb29c1
commit
875c1737e5
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -172,6 +172,15 @@ dependencies = [
|
|||||||
"itertools",
|
"itertools",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
@ -415,6 +424,7 @@ dependencies = [
|
|||||||
"arrayvec",
|
"arrayvec",
|
||||||
"const_fn",
|
"const_fn",
|
||||||
"criterion",
|
"criterion",
|
||||||
|
"crossbeam-channel",
|
||||||
"either",
|
"either",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
|
|||||||
@ -24,6 +24,7 @@ debug = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
arrayvec = "0.7"
|
arrayvec = "0.7"
|
||||||
const_fn = "0.4"
|
const_fn = "0.4"
|
||||||
|
crossbeam-channel = "0.5.14"
|
||||||
either = "1.13"
|
either = "1.13"
|
||||||
indicatif = { version = "0.17", features = [ "rayon" ] }
|
indicatif = { version = "0.17", features = [ "rayon" ] }
|
||||||
nohash-hasher = "0.2"
|
nohash-hasher = "0.2"
|
||||||
|
|||||||
65
src/elo.rs
65
src/elo.rs
@ -118,6 +118,7 @@ impl PlayerArena {
|
|||||||
players: players
|
players: players
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip([EloRating::new()].into_iter().cycle())
|
.zip([EloRating::new()].into_iter().cycle())
|
||||||
|
// flatten tuple
|
||||||
.map(|((a, b), c)| (a, b, c))
|
.map(|((a, b), c)| (a, b, c))
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
@ -137,21 +138,53 @@ impl PlayerArena {
|
|||||||
// shuffle for consistency
|
// shuffle for consistency
|
||||||
created_pairs.shuffle(&mut rand::rng());
|
created_pairs.shuffle(&mut rand::rng());
|
||||||
|
|
||||||
// after the agents are created, we can multithread the games being played
|
let num = created_pairs.len();
|
||||||
created_pairs
|
|
||||||
.into_par_iter()
|
let (sender, receiver) = crossbeam_channel::unbounded();
|
||||||
.progress_with_style(
|
|
||||||
ProgressStyle::with_template("[{elapsed_precise}] {pos:>7}/{len:7} ETA: {eta}")
|
// Spawn parallel processing in a dedicated thread
|
||||||
.expect("invalid ProgressStyle"),
|
let processing_thread = {
|
||||||
)
|
let sender = sender.clone();
|
||||||
.map(|((i, j), (p1, p2))| (i, j, Self::play_two_inner(p1, p2)))
|
std::thread::spawn(move || {
|
||||||
// TODO! is there some way in rayon to allow `self.process_outcome` to be run on the main thread
|
created_pairs
|
||||||
// as soon as Self::play_two_inner completes? This would allow maybe a live leaderboard to be displayed
|
.into_par_iter()
|
||||||
// while players are playing
|
.progress_with_style(
|
||||||
.collect::<Vec<_>>()
|
ProgressStyle::with_template(
|
||||||
// collect and process the outcomes of all the games
|
"[{elapsed_precise}] {pos:>7}/{len:7} ETA: {eta}",
|
||||||
.into_iter()
|
)
|
||||||
.for_each(|(i, j, o)| self.process_outcome(i, j, &o));
|
.expect("invalid ProgressStyle"),
|
||||||
|
)
|
||||||
|
.map(|((i, j), (p1, p2))| (i, j, Self::play_two_inner(p1, p2)))
|
||||||
|
.for_each(|(i, j, o)| {
|
||||||
|
sender.send((i, j, o)).expect("Failed to send result");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Immediately drop our copy of the sender so the channel closes properly
|
||||||
|
drop(sender);
|
||||||
|
|
||||||
|
// Process results on main thread as they arrive
|
||||||
|
let mut received_num = 0;
|
||||||
|
while let Ok((i, j, o)) = receiver.recv() {
|
||||||
|
self.process_outcome(i, j, &o);
|
||||||
|
received_num += 1;
|
||||||
|
|
||||||
|
// print the leaderboard every 5 steps
|
||||||
|
if received_num % 5 == 0 {
|
||||||
|
println!("{}", self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// break if all pairs were recieved
|
||||||
|
if received_num == num {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure parallel thread completes
|
||||||
|
processing_thread
|
||||||
|
.join()
|
||||||
|
.expect("Processing thread panicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prop_arena(&mut self, n: usize) {
|
fn prop_arena(&mut self, n: usize) {
|
||||||
@ -191,7 +224,7 @@ impl PlayerArena {
|
|||||||
player_1,
|
player_1,
|
||||||
player_2,
|
player_2,
|
||||||
false,
|
false,
|
||||||
Board::random(rand::random_range(3..8)),
|
Board::random(rand::random_range(3..=7)),
|
||||||
)
|
)
|
||||||
.loop_until_result();
|
.loop_until_result();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user