Skip to content

Commit

Permalink
fix: prevent browser make-move spam after undo (#491)
Browse files Browse the repository at this point in the history
  • Loading branch information
Terkwood authored May 12, 2021
1 parent b9d7201 commit 12fac85
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 44 deletions.
2 changes: 1 addition & 1 deletion botlink/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion botlink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
authors = ["terkwood <[email protected]>"]
edition = "2018"
name = "botlink"
version = "1.1.0"
version = "1.1.1"

[dependencies]
base64 = "0.13.0"
Expand Down
7 changes: 7 additions & 0 deletions botlink/src/stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ fn process_game_state(game_state: &GameState, opts: &mut StreamOpts) {
let game_id = &game_state.game_id;
match opts.attachment_repo.get(&game_id, player_up) {
Ok(Some(attachment)) => {
info!(
"🐌 game turn: {:?}, playerup: {:?}, moves: {}",
game_state.turn,
game_state.player_up,
game_state.moves.len()
);

if let Err(e) = opts.compute_move_in.send(ComputeMove {
game_id: game_id.clone(),
game_state: game_state.clone(),
Expand Down
4 changes: 1 addition & 3 deletions botlink/src/stream/write_moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::repo::BoardSizeRepo;
use bot_model::{api::MoveComputed, AlphaNumCoord};
use core_model::ReqId;
use crossbeam_channel::{select, Receiver};
use log::{error, info};
use log::error;
use move_model::{Coord, MakeMove};
use std::sync::Arc;
use uuid::Uuid;
Expand All @@ -24,8 +24,6 @@ pub fn xadd_loop(

if let Err(e) = xadder.xadd_make_move_command(&command) {
error!("could not xadd move command : {:?}",e)
} else {
info!("🆗 {:?}", command)
}
} else {
error!("Could not fetch board size for {}", game_id.0)
Expand Down
2 changes: 1 addition & 1 deletion browser/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bugout-browser",
"productName": "BUGOUT",
"version": "1.4.0",
"version": "1.4.1",
"description": "Graphical user interface for BUGOUT Go/Baduk/Weiqi",
"author": "Terkwood <[email protected]>",
"homepage": "https://github.com/Terkwood/BUGOUT",
Expand Down
7 changes: 4 additions & 3 deletions browser/src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const EDITION = "Revisited";
const EDITION = "Earl";

const EventEmitter = require("events");
const { ipcRenderer, remote } = require("electron");
Expand Down Expand Up @@ -787,14 +787,15 @@ class App extends Component {
onMoveUndone() {
let { gameTrees, gameIndex, treePosition } = this.state;
let tree = gameTrees[gameIndex];

// Try going back two moves
let thisMove = tree.get(treePosition);
let oneMoveAgo = tree.get(thisMove.parentId);

// Update data
let nextTreePosition = oneMoveAgo.parentId;
let newTree = tree.mutate((draft) => {
draft.removeNode(treePosition); // this move
draft.removeNode(thisMove.parentId); // one move ago
});

Expand Down Expand Up @@ -836,7 +837,7 @@ class App extends Component {

this.recordHistory({ prevGameIndex, prevTreePosition });

this.events.emit("navigate");
this.events.emit("navigate"); // trim this, nothing uses it
}

// 😇 BUGOUT trimmed 😇
Expand Down
42 changes: 15 additions & 27 deletions browser/src/modules/enginesyncer.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class EngineSyncer extends EventEmitter {
let promises = [];
let synced = true;
let nodes = [...tree.listNodesVertically(id, -1, {})].reverse();

for (let node of nodes) {
let nodeBoard = gametree.getBoard(tree, node.id);
let placedHandicapStones = false;
Expand All @@ -247,15 +247,15 @@ class EngineSyncer extends EventEmitter {

if (coords.length > 0) {
moves.push({ sign: 1, vertices });

promises.push(() =>
controller
.sendCommand({ name: "set_free_handicap", args: coords })
.then((r) => !r.error)
);

for (let vertex of vertices) {
if (engineBoard.get(vertex) !== 0) continue;

if (engineBoard.get(vertex) !== 0) continue;
engineBoard = engineBoard.makeMove(1, vertex);
}

Expand All @@ -272,6 +272,7 @@ class EngineSyncer extends EventEmitter {
...node.data[prop].map(sgf.parseCompressedVertices)
);


for (let vertex of vertices) {
if (engineBoard.hasVertex(vertex) && engineBoard.get(vertex) !== 0)
continue;
Expand All @@ -281,14 +282,15 @@ class EngineSyncer extends EventEmitter {
promises.push(() => enginePlay(sign, vertex));
engineBoard = engineBoard.makeMove(sign, vertex);
}

}

if (engineBoard.getPositionHash() !== nodeBoard.getPositionHash()) {
synced = false;
break;
}

if (node.id === id) break;
if (node.id === id) break;
}

if (synced) {
Expand All @@ -299,26 +301,13 @@ class EngineSyncer extends EventEmitter {
sharedHistoryLength = Math.min(this.state.moves.length, moves.length);
let undoLength = this.state.moves.length - sharedHistoryLength;

if (
!this.state.dirty &&
sharedHistoryLength > 0 &&
undoLength < sharedHistoryLength &&
(this.commands.includes("undo") || undoLength === 0)
) {
// Undo until shared history is reached, then play out rest

promises = [
...[...Array(undoLength)].map(() => () =>
controller.sendCommand({ name: "undo" }).then((r) => !r.error)
),
...promises.slice(sharedHistoryLength),
];
} else {
// Replay from beginning

promises.unshift(() => controller.sendCommand({ name: "clear_board" }));
}

promises = [
...[...Array(undoLength)].map(() => () =>
controller.sendCommand({ name: "undo" }).then((r) => !r.error)
),
...promises.slice(sharedHistoryLength),
];

let result = await Promise.all(promises.map((x) => x()));
let success = result.every((x) => x);
if (success) return;
Expand All @@ -338,7 +327,7 @@ class EngineSyncer extends EventEmitter {

for (let vertex of diff) {
let sign = board.get(vertex);

promises.push(() => enginePlay(sign, vertex));
engineBoard = engineBoard.makeMove(board.get(vertex), vertex);
}
Expand All @@ -351,7 +340,6 @@ class EngineSyncer extends EventEmitter {
}

// Complete rearrangement

promises = [() => controller.sendCommand({ name: "clear_board" })];
engineBoard = new Board(board.width, board.height);

Expand All @@ -360,7 +348,7 @@ class EngineSyncer extends EventEmitter {
let vertex = [x, y];
let sign = board.get(vertex);
if (sign === 0) continue;

promises.push(() => enginePlay(sign, vertex));
engineBoard = engineBoard.makeMove(sign, vertex);
}
Expand Down
19 changes: 18 additions & 1 deletion browser/src/modules/shims/gtp.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ class WebSocketController extends EventEmitter {
// - In case we need to show that the opponent passed
// - Also used by BugoutSync to delay sync requests after move
sabaki.events.emit("bugout-move-made", msg);

this.removeMessageListener();
}

handleOpponentQuit(resolve) {
Expand Down Expand Up @@ -937,23 +939,38 @@ class GatewayConn {
});
}

removeUndoListener() {
this.undoListener &&
this.webSocket.removeEventListener("message", this.undoListener);
}

updateUndoListener(listener) {
if (listener) {
this.removeUndoListener();
this.undoListener = listener;
this.webSocket.addEventListener("message", listener);
}
}

async undoMove(player) {
return new Promise((resolve, reject) => {
let requestPayload = {
type: "UndoMove",
player,
};

this.webSocket.addEventListener("message", (event) => {
this.updateUndoListener((event) => {
try {
let msg = JSON.parse(event.data);

if (msg.type === "MoveUndone") {
this.removeUndoListener();
resolve(msg);
sabaki.events.emit("bugout-move-undone");
sabaki.events.emit("bugout-wait-for-undo", { showWait: false, showReject: false });
} else if (msg.type === "UndoRejected") {
sabaki.events.emit("bugout-wait-for-undo", { showWait: false, showReject: true });
this.removeUndoListener();
resolve(msg);
}
// discard any other messages
Expand Down
2 changes: 1 addition & 1 deletion undo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion undo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
authors = ["terkwood <[email protected]>"]
edition = "2018"
name = "undo"
version = "0.1.0"
version = "0.1.1"

[dependencies]
bincode = "1.3.3"
Expand Down
6 changes: 6 additions & 0 deletions undo/src/repo/game_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ impl GameStateRepo for Rc<Client> {
}

fn put(&self, game_state: &GameState) -> Result<(), RepoErr> {
log::info!(
"🐌 game turn: {}, player up: {:?}, moves: {}",
game_state.turn,
game_state.player_up,
game_state.moves.len()
);
let mut conn = self.get_connection()?;
let bytes = bincode::serialize(&game_state)?;
conn.set(key(&game_state.game_id), bytes)?;
Expand Down
3 changes: 1 addition & 2 deletions undo/src/stream/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::undo::consume_undo;
use super::*;
use crate::repo::Botness;
use crate::Components;
use log::{error, info};
use log::error;
use redis_streams::XReadEntryId;

pub fn process(reg: &Components) {
Expand All @@ -11,7 +11,6 @@ pub fn process(reg: &Components) {
match reg.xread.xread_sorted() {
Ok(xrr) => {
for (xid, data) in xrr {
info!("🧮 Processing {:?}", &data);
consume(xid, &data, &reg);
unacked.push(xid, data);
}
Expand Down
17 changes: 14 additions & 3 deletions undo/src/stream/undo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,22 @@ fn reject(undo_move: &UndoMove, reg: &Components) -> Result<(), StreamAddErr> {
}

fn rollback(game_state: &GameState) -> GameState {
let moves = game_state.moves[0..(&game_state.moves.len() - 2)].to_vec();
let moves = {
let mut ms = game_state.moves.clone();
ms.pop();
ms.pop();
ms
};
let board = compute_board(&moves, game_state.board.size);
let captures = compute_captures(&moves);

GameState {
game_id: game_state.game_id.clone(),
turn: game_state.turn - 2,
player_up: game_state.player_up,
moves,
board: compute_board(&game_state.moves, game_state.board.size),
captures: compute_captures(&game_state.moves),
board,
captures,
}
}

Expand All @@ -64,6 +71,10 @@ fn compute_board(moves: &[MoveMade], size: u16) -> Board {
..Default::default()
};
for m in moves.iter() {
for c in &m.captured {
out.pieces.remove(c);
}

if let Some(coord) = m.coord {
out.pieces.insert(coord, m.player);
}
Expand Down

0 comments on commit 12fac85

Please sign in to comment.