diff --git a/10_globals.js b/10_globals.js index 6b350dbd..9da7f2a9 100644 --- a/10_globals.js +++ b/10_globals.js @@ -8,6 +8,7 @@ const boardfriends = document.getElementById("boardfriends"); const boardsquares = document.getElementById("boardsquares"); const canvas = document.getElementById("canvas"); +const fantasy = document.getElementById("fantasy"); const fenbox = document.getElementById("fenbox"); const infobox = document.getElementById("infobox"); const movelist = document.getElementById("movelist"); diff --git a/80_info.js b/80_info.js index d4950f2f..02879793 100644 --- a/80_info.js +++ b/80_info.js @@ -209,23 +209,24 @@ function NewInfoHandler() { ih.draw_infobox = function(mouse_point, active_square, leela_should_go, active_colour, searchmoves) { - // We can afford to draw the status bar each time... + // Various possible status things in order of priority... - let status_string = ""; - if (leela_should_go === false) { - status_string += `${config.versus === "" ? "HALTED " : "YOUR MOVE "}`; - } - status_string += `Nodes: ${NString(this.nodes)}, N/s: ${NString(this.nps)}`; + if (fantasy.style.display === "block") { + statusbox.innerHTML = `HYPOTHETICAL POSITION. Press escape to clear.`; + } else if (config.search_nodes !== "infinite" && (searchmoves.length === 1)) { + statusbox.innerHTML = `Node limit with exactly ONE searchmove might not return data.`; + } else { - if (typeof config.search_nodes === "number" && this.nodes > config.search_nodes) { - status_string += ` (limit exceeded)`; - } + let status_string = ""; + if (leela_should_go === false) { + status_string += `${config.versus === "" ? "HALTED " : "YOUR MOVE "}`; + } + status_string += `Nodes: ${NString(this.nodes)}, N/s: ${NString(this.nps)}`; - // Hackish warning for Lc0 issue... + if (typeof config.search_nodes === "number" && this.nodes > config.search_nodes) { + status_string += ` (limit exceeded)`; + } - if (config.search_nodes !== "infinite" && (searchmoves.length === 1)) { - statusbox.innerHTML = `Node limit with exactly ONE searchmove might not return data.`; - } else { statusbox.innerHTML = status_string; } @@ -365,7 +366,7 @@ function NewInfoHandler() { }); } - if (info.move === one_click_move) { + if (info.move === one_click_move && fantasy.style.display !== "block") { for (let e of new_elements) { e.class += " redback"; } diff --git a/95_renderer.js b/95_renderer.js index a266973b..c52d1b55 100644 --- a/95_renderer.js +++ b/95_renderer.js @@ -581,6 +581,7 @@ function NewRenderer() { this.hide_pgn_chooser(); this.hide_promotiontable(); this.set_active_square(null); + this.hide_fantasy(); }; renderer.toggle_debug_css = function() { @@ -657,6 +658,10 @@ function NewRenderer() { return; } + if (fantasy.style.display === "block") { // Do nothing if we're showing a fantasy position. + return; + } + this.hide_promotiontable(); // Just in case it's up. let p = Point(null); @@ -675,6 +680,13 @@ function NewRenderer() { let ocm = this.info_handler.one_click_moves[p.x][p.y]; let board = this.node.get_board(); + if (event.button !== 0) { + if (ocm) { + this.show_from_moves([ocm]); + } + return; + } + if (!this.active_square && ocm) { this.set_active_square(null); this.move(ocm); @@ -705,7 +717,10 @@ function NewRenderer() { return; } - // Legality checks... best to assume nothing. + if (event.button !== 0) { + renderer.show_from_moves(moves); + return; + } let reason = this.node.get_board().sequence_illegal(moves); if (reason !== "") { @@ -745,6 +760,53 @@ function NewRenderer() { this.movelist_handler.redraw_node(stats_node); // Redraw the stats node, which might not have been drawn (if draw was lazy). }; + renderer.show = function(board) { + + let ctx = fantasy.getContext("2d"); + + for (let x = 0; x < 8; x++) { + for (let y = 0; y < 8; y++) { + + ctx.fillStyle = (x + y) % 2 === 0 ? config.light_square : config.dark_square; + + let cc = CanvasCoords(x, y); + ctx.fillRect(cc.x1, cc.y1, config.square_size, config.square_size); + + if (board.state[x][y] === "") { + continue; + } + + let piece = board.state[x][y]; + ctx.drawImage(images[piece], cc.x1, cc.y1, config.square_size, config.square_size); + } + } + + fantasy.style.display = "block"; + }; + + renderer.show_from_moves = function(moves) { + + if (Array.isArray(moves) === false || moves.length === 0) { + return; + } + + let board = this.node.get_board(); + + for (let move of moves) { + if (board.illegal(move) !== "") { + console.log("show_from_moves(): " + reason); + return; + } + board = board.move(move); + } + + this.show(board); + }; + + renderer.hide_fantasy = function() { + fantasy.style.display = "none"; + }; + renderer.maybe_searchmove_click = function(event) { let sm = this.info_handler.searchmove_from_click(event); @@ -767,12 +829,19 @@ function NewRenderer() { let node = this.movelist_handler.node_from_click(event); - if (!node || node.get_root() !== this.node.get_root() || node === this.node) { + if (!node || node.get_root() !== this.node.get_root()) { return; } - this.node = node; - this.position_changed(); + if (event.button !== 0) { + renderer.show(node.get_board()); + return; + } + + if (node !== this.node) { + this.node = node; + this.position_changed(); + } }; renderer.show_promotiontable = function(partial_move) { diff --git a/99_start.js b/99_start.js index 38543685..ac3c9487 100644 --- a/99_start.js +++ b/99_start.js @@ -16,11 +16,11 @@ let hub = NewRenderer(); // boardsquares has its natural position, while the other two get // fixed position that is set to be on top of it. -boardfriends.width = canvas.width = boardsquares.width = config.board_size; -boardfriends.height = canvas.height = boardsquares.height = config.board_size; +boardfriends.width = canvas.width = fantasy.width = boardsquares.width = config.board_size; +boardfriends.height = canvas.height = fantasy.height = boardsquares.height = config.board_size; -boardfriends.style.left = canvas.style.left = boardsquares.offsetLeft.toString() + "px"; -boardfriends.style.top = canvas.style.top = boardsquares.offsetTop.toString() + "px"; +boardfriends.style.left = canvas.style.left = fantasy.style.left = boardsquares.offsetLeft.toString() + "px"; +boardfriends.style.top = canvas.style.top = fantasy.style.top = boardsquares.offsetTop.toString() + "px"; // Set up the squares in both tables. Note that, upon flips, the elements // themselves are moved to their new position, so everything works, e.g. diff --git a/nibbler.css b/nibbler.css index 75d1d6ae..04011d4d 100644 --- a/nibbler.css +++ b/nibbler.css @@ -59,6 +59,14 @@ body { user-select: none; } +#fantasy { + display: none; + outline: 2px dashed #6cccee; + outline-offset: 6px; + position: fixed; + user-select: none; +} + td { border: 0; margin: 0; diff --git a/nibbler.html b/nibbler.html index e67d47cc..0313b9fc 100644 --- a/nibbler.html +++ b/nibbler.html @@ -20,6 +20,7 @@
+
diff --git a/package-lock.json b/package-lock.json index d525f4ea..8dbdca08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { "name": "Nibbler", - "version": "0.6.8", + "version": "0.6.8-rc1", "lockfileVersion": 1 } diff --git a/package.json b/package.json index f64a38e5..9d260cc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Nibbler", - "version": "0.6.8", + "version": "0.6.8-rc1", "author": "Fohristiwhirl", "description": "Leela Chess Zero (Lc0) interface", "main": "main.js",