Skip to content

Commit

Permalink
Merge pull request #272 from TruncateGame/main
Browse files Browse the repository at this point in the history
Prod release
  • Loading branch information
bglw authored Jul 15, 2024
2 parents 0a33a01 + e0f8c1e commit bc99ff8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 9 deletions.
2 changes: 2 additions & 0 deletions truncate_client/src/app_outer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub enum BackchannelMsg {
},
/// Tells the outer host to add a given word to the NPC's known dictionaries
Remember { word: String },
/// Tells the outer host to forget all words learned via BackchannelMsg::Remember
Forget,
/// Tells the outer host to copy the given text, and optionally
/// open a system share dialog.
/// More reliable than copying within egui, as the browser JS
Expand Down
4 changes: 4 additions & 0 deletions truncate_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ pub fn backchannel(msg: String) -> String {
utils::game_evals::remember(&word);
return String::new();
}
BackchannelMsg::Forget => {
utils::game_evals::forget();
return String::new();
}
BackchannelMsg::QueryFor { .. } => {
unreachable!("Backchannel should not be passing through QueryFor")
}
Expand Down
35 changes: 26 additions & 9 deletions truncate_client/src/regions/single_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
ResultModalUI,
},
utils::{
game_evals::{client_best_move, get_main_dict, remember},
game_evals::{client_best_move, forget, get_main_dict, remember},
text::TextHelper,
Theme,
},
Expand Down Expand Up @@ -133,7 +133,12 @@ impl SinglePlayerState {
.event(format!("single_player_{}_{}", self.name, event));
}

pub fn reset(&mut self, current_time: Duration, ctx: &egui::Context) {
pub fn reset(
&mut self,
current_time: Duration,
ctx: &egui::Context,
backchannel: &Backchannel,
) {
if let Some(seed) = &self.active_game.depot.board_info.board_seed {
if seed.day.is_some() {
match &mut self.header {
Expand All @@ -145,17 +150,23 @@ impl SinglePlayerState {
}
_ => {}
};
return self.reset_to(seed.clone(), self.human_starts, ctx);
return self.reset_to(seed.clone(), self.human_starts, ctx, backchannel);
}
}

let next_seed = (current_time.as_micros() % 243985691) as u32;
let next_board_seed = BoardSeed::new(next_seed);

self.reset_to(next_board_seed, !self.human_starts, ctx);
self.reset_to(next_board_seed, !self.human_starts, ctx, backchannel);
}

pub fn reset_to(&mut self, seed: BoardSeed, human_starts: bool, ctx: &egui::Context) {
pub fn reset_to(
&mut self,
seed: BoardSeed,
human_starts: bool,
ctx: &egui::Context,
backchannel: &Backchannel,
) {
let mut game = Game::new(9, 9, Some(seed.seed as u64), self.rules_generation);
self.human_starts = human_starts;
if self.human_starts {
Expand Down Expand Up @@ -207,6 +218,12 @@ impl SinglePlayerState {
self.winner = None;
self.move_sequence = vec![];
self.event_dispatcher = self.event_dispatcher.clone();

if backchannel.is_open() {
backchannel.send_msg(crate::app_outer::BackchannelMsg::Forget);
} else {
forget();
}
}

/// If the server sent through some new word definitions,
Expand Down Expand Up @@ -389,7 +406,7 @@ impl SinglePlayerState {
.map(|msg| (human_player, msg));

if matches!(next_msg, Some((_, PlayerMessage::Rematch))) {
self.reset(current_time, ui.ctx());
self.reset(current_time, ui.ctx(), backchannel);
return msgs_to_server;
} else if matches!(next_msg, Some((_, PlayerMessage::Resign))) {
if self.hide_splash {
Expand Down Expand Up @@ -427,15 +444,15 @@ impl SinglePlayerState {
match splash_msg {
Some(ResultModalAction::NewPuzzle) => {
self.splash = None;
self.reset(current_time, ui.ctx());
self.reset(current_time, ui.ctx(), backchannel);
}
Some(ResultModalAction::TryAgain) => {
self.splash = None;

if let Some(seed) = &self.active_game.depot.board_info.board_seed {
self.reset_to(seed.clone(), self.human_starts, ui.ctx());
self.reset_to(seed.clone(), self.human_starts, ui.ctx(), backchannel);
} else {
self.reset(current_time, ui.ctx());
self.reset(current_time, ui.ctx(), backchannel);
}
}
Some(ResultModalAction::Dismiss) => {
Expand Down
9 changes: 9 additions & 0 deletions truncate_client/src/utils/game_evals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,12 @@ pub fn remember(word: &String) {
}
}
}

/// Forgets all words learned via remember()
/// (For now, this just wipes all dicts and relies on them being recreated)
pub fn forget() {
*TOTAL_DICT.lock().unwrap() = None;
*SMALL_VOCAB_DICT_SAFE.lock().unwrap() = None;
*MEDIUM_VOCAB_DICT_SAFE.lock().unwrap() = None;
*LARGE_VOCAB_DICT_UNSAFE.lock().unwrap() = None;
}
39 changes: 39 additions & 0 deletions truncate_core/src/npc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,45 @@ mod tests {
}
}

#[test]
fn test_npc_determinism() {
let dict = dict();

let eval = || {
let game = test_game(
r###"
~~ ~~ |0 ~~
~~ S0 O0 ~~
~~ T0 A0 Y0
~~ A0 ~~ ~~
~~ R0 __ ~~
~~ __ A1 |1
~~ ~~ |1 ~~
~~ ~~ ~~ ~~
"###,
"XZF",
);
let mut pruned_arbor = Arborist::pruning();
let (pruned_best_move, _) = Game::best_move(
&game,
Some(&dict),
Some(&dict),
2,
Some(&mut pruned_arbor),
false,
&NPCParams::default(),
);

pruned_best_move
};

let base = eval();
println!("{:#?}", base);
for _ in 0..200 {
assert_eq!(eval(), base);
}
}

#[test]
fn generic_npc_tests() {
let dict = dict();
Expand Down

0 comments on commit bc99ff8

Please sign in to comment.