pub mod node;
use std::cell::Cell;
#[derive(Clone, Debug)]
pub struct Slush {
preference: Cell<i64>,
}
impl Slush {
pub fn new(choice: i64) -> Self {
Self {
preference: Cell::new(choice),
}
}
pub fn preference(&self) -> i64 {
self.preference.get()
}
pub fn record_successful_poll(&self, choice: i64) {
self.preference.set(choice);
}
}
impl std::fmt::Display for Slush {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SL(Preference = {})", self.preference())
}
}
#[test]
fn test_slush() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let sl = Slush::new(0);
assert_eq!(sl.preference(), 0);
sl.record_successful_poll(1);
assert_eq!(sl.preference(), 1);
}
#[derive(Clone, Debug)]
pub struct Snowflake {
slush: Slush,
beta: Cell<i64>,
confidence: Cell<i64>,
finalized: Cell<bool>,
}
impl Snowflake {
pub fn new(beta: i64, choice: i64, confidence: i64, finalized: bool) -> Self {
Self {
slush: Slush::new(choice),
beta: Cell::new(beta),
confidence: Cell::new(confidence),
finalized: Cell::new(finalized),
}
}
pub fn preference(&self) -> i64 {
self.slush.preference()
}
pub fn beta(&self) -> i64 {
self.beta.get()
}
pub fn confidence(&self) -> i64 {
self.confidence.get()
}
pub fn finalized(&self) -> bool {
self.finalized.get()
}
pub fn record_successful_poll(&self, choice: i64) {
if self.finalized() {
return;
}
if self.preference() == choice {
self.confidence.set(self.confidence.get() + 1);
} else {
self.confidence.set(1);
}
self.finalized.set(self.confidence.get() >= self.beta());
self.slush.record_successful_poll(choice);
}
pub fn record_unsuccessful_poll(&self) {
self.confidence.set(0);
}
}
impl std::fmt::Display for Snowflake {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"SF(Confidence = {}, Finalized = {}, {})",
self.confidence(),
self.finalized(),
self.slush
)
}
}
#[test]
fn test_snowflake() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let beta = 2_i64;
let (blue, red) = (0_i64, 1_i64);
let snf = Snowflake::new(beta, red, 0, false);
assert_eq!(snf.beta(), beta);
assert_eq!(snf.preference(), red);
assert_eq!(snf.finalized(), false, "finalized too early");
snf.record_successful_poll(blue);
assert_eq!(snf.preference(), blue);
assert_eq!(snf.finalized(), false, "finalized too early");
snf.record_successful_poll(red);
assert_eq!(snf.preference(), red);
assert_eq!(snf.finalized(), false, "finalized too early");
snf.record_successful_poll(blue);
assert_eq!(snf.preference(), blue);
assert_eq!(snf.finalized(), false, "finalized too early");
snf.record_successful_poll(blue);
assert_eq!(snf.preference(), blue);
assert_eq!(snf.finalized(), true, "didn't finalize correctly");
log::info!("{snf}");
}
#[derive(Clone, Debug)]
pub struct Snowball {
snowflake: Snowflake,
preference: Cell<i64>,
num_successful_polls: Cell<[i64; 2]>,
}
impl Snowball {
pub fn new(snowflake: Snowflake, choice: i64, polls: [i64; 2]) -> Self {
Self {
snowflake,
preference: Cell::new(choice),
num_successful_polls: Cell::new(polls),
}
}
pub fn preference(&self) -> i64 {
if self.snowflake.finalized() {
return self.snowflake.preference();
}
self.preference.get()
}
pub fn beta(&self) -> i64 {
self.snowflake.beta()
}
pub fn confidence(&self) -> i64 {
self.snowflake.confidence()
}
pub fn finalized(&self) -> bool {
self.snowflake.finalized()
}
pub fn num_successful_polls(&self, idx: usize) -> i64 {
let polls = self.num_successful_polls.take();
let n = polls[idx];
self.num_successful_polls.set(polls);
n
}
pub fn record_successful_poll(&self, choice: i64) {
let mut polls = self.num_successful_polls.take();
polls[choice as usize] += 1;
let (count, count_other) = (polls[choice as usize], polls[1 - choice as usize]);
self.num_successful_polls.set(polls);
if count > count_other {
self.preference.set(choice);
}
self.snowflake.record_successful_poll(choice);
}
pub fn record_unsuccessful_poll(&self) {
self.snowflake.record_unsuccessful_poll()
}
}
impl std::fmt::Display for Snowball {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"SB(Preference = {}, NumSuccessfulPolls[0] = {}, NumSuccessfulPolls[1] = {}, {})",
self.preference.get(),
self.num_successful_polls(0),
self.num_successful_polls(1),
self.snowflake
)
}
}
#[test]
fn test_snowball() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let beta = 2_i64;
let (red, blue) = (0_i64, 1_i64);
let snb = Snowball::new(Snowflake::new(beta, red, 0, false), red, [0, 0]);
assert_eq!(snb.beta(), beta);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(red);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), true, "didn't finalize correctly");
log::info!("{snb}");
}
#[test]
fn test_snowball_record_unsuccessful_poll() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let beta = 2_i64;
let (red, blue) = (0_i64, 1_i64);
let snb = Snowball::new(Snowflake::new(beta, red, 0, false), red, [0, 0]);
assert_eq!(snb.beta(), beta);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false);
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_unsuccessful_poll();
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), true, "finalized too late");
assert_eq!(snb.num_successful_polls(red as usize), 0);
assert_eq!(snb.num_successful_polls(blue as usize), 3);
log::info!("{snb}");
assert_eq!(snb.to_string(), "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))");
}
#[test]
fn test_snowball_accept_weird_color() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let beta = 2_i64;
let (blue, red) = (0_i64, 1_i64);
let snb = Snowball::new(Snowflake::new(beta, red, 0, false), red, [0, 0]);
assert_eq!(snb.beta(), beta);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false);
snb.record_successful_poll(red);
snb.record_unsuccessful_poll();
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(red);
snb.record_unsuccessful_poll();
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), blue);
assert_eq!(snb.finalized(), true, "finalized too late");
log::info!("{snb}");
assert_eq!(snb.to_string(), "SB(Preference = 1, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 0)))");
}
#[test]
fn test_snowball_lock_color() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let beta = 1_i64;
let (red, blue) = (0_i64, 1_i64);
let snb = Snowball::new(Snowflake::new(beta, red, 0, false), red, [0, 0]);
assert_eq!(snb.beta(), beta);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), false, "finalized too early");
snb.record_successful_poll(red);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), true, "finalized too late");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), true, "finalized too late");
snb.record_successful_poll(blue);
assert_eq!(snb.preference(), red);
assert_eq!(snb.finalized(), true, "finalized too late");
log::info!("{snb}");
assert_eq!(snb.to_string(), "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF(Confidence = 1, Finalized = true, SL(Preference = 0)))");
}