diff --git a/docs/js/class_p.js b/docs/js/class_p.js index 56cdc3b3..31c02017 100644 --- a/docs/js/class_p.js +++ b/docs/js/class_p.js @@ -1,7 +1,7 @@ const MAX_EXPORT_LENGTH = 7360; class Point { - constructor(x, y, type, adjacent, surround, use, neighbor = [], adjacent_dia = [], type2 = 0) { + constructor(x, y, type, adjacent, surround, use, neighbor = [], adjacent_dia = [], type2 = 0, index = null) { this.x = x; this.y = y; this.type = type; @@ -11,6 +11,7 @@ class Point { this.surround = surround; this.neighbor = neighbor; this.use = use; + this.index = index; } } @@ -72,6 +73,7 @@ class Puzzle { this.drawing_mode = -1; this.cursol = 0; this.cursolS = 0; + this.select_remove = false; this.panelflag = false; // Drawing mode this.mmode = ""; // Problem mode @@ -185,61 +187,37 @@ class Puzzle { this.isReplay = false; } + reset_puzzle(p) { + this[p] = {}; + this[p].command_redo = new Stack(); + this[p].command_undo = new Stack(); + this[p].command_replay = new Stack(); + this[p].surface = {}; + this[p].number = {}; + this[p].numberS = {}; + this[p].symbol = {}; + this[p].freeline = {}; + this[p].freelineE = {}; + this[p].thermo = []; + this[p].arrows = []; + this[p].direction = []; + this[p].squareframe = []; + this[p].polygon = []; + this[p].line = {}; + this[p].lineE = {}; + this[p].wall = {}; + this[p].cage = {}; + this[p].deletelineE = {}; + this[p].killercages = []; + this[p].nobulbthermo = []; + } + reset() { - let pu_qa = ["pu_q", "pu_a"], - pu_qa_col = ["pu_q_col", "pu_a_col"]; - - // Object and Array initialization - for (var i of pu_qa) { - this[i] = {}; - this[i].command_redo = new Stack(); - this[i].command_undo = new Stack(); - this[i].command_replay = new Stack(); - this[i].surface = {}; - this[i].number = {}; - this[i].numberS = {}; - this[i].symbol = {}; - this[i].freeline = {}; - this[i].freelineE = {}; - this[i].thermo = []; - this[i].arrows = []; - this[i].direction = []; - this[i].squareframe = []; - this[i].polygon = []; - this[i].line = {}; - this[i].lineE = {}; - this[i].wall = {}; - this[i].cage = {}; - this[i].deletelineE = {}; - this[i].killercages = []; - this[i].nobulbthermo = []; - } - - // Object and Array initialization for custom colors - for (var i of pu_qa_col) { - this[i] = {}; - this[i].command_redo = new Stack(); - this[i].command_undo = new Stack(); - this[i].command_replay = new Stack(); - this[i].surface = {}; - this[i].number = {}; - this[i].numberS = {}; - this[i].symbol = {}; - this[i].freeline = {}; - this[i].freelineE = {}; - this[i].thermo = []; - this[i].arrows = []; - this[i].direction = []; - this[i].squareframe = []; - this[i].polygon = []; - this[i].line = {}; - this[i].lineE = {}; - this[i].wall = {}; - this[i].cage = {}; - this[i].deletelineE = {}; - this[i].killercages = []; - this[i].nobulbthermo = []; - } + // Object and Array initialization for problem/solution mode plus their custom colors + this.reset_puzzle("pu_q"); + this.reset_puzzle("pu_q_col"); + this.reset_puzzle("pu_a"); + this.reset_puzzle("pu_a_col"); this.frame = {}; this.freelinecircle_g = [-1, -1]; @@ -247,52 +225,8 @@ class Puzzle { } reset_board() { - this[this.mode.qa] = {}; - this[this.mode.qa].command_redo = new Stack(); - this[this.mode.qa].command_undo = new Stack(); - this[this.mode.qa].command_replay = new Stack(); - this[this.mode.qa].surface = {}; - this[this.mode.qa].number = {}; - this[this.mode.qa].numberS = {}; - this[this.mode.qa].symbol = {}; - this[this.mode.qa].freeline = {}; - this[this.mode.qa].freelineE = {}; - this[this.mode.qa].thermo = []; - this[this.mode.qa].arrows = []; - this[this.mode.qa].direction = []; - this[this.mode.qa].squareframe = []; - this[this.mode.qa].polygon = []; - this[this.mode.qa].line = {}; - this[this.mode.qa].lineE = {}; - this[this.mode.qa].wall = {}; - this[this.mode.qa].cage = {}; - this[this.mode.qa].deletelineE = {}; - this[this.mode.qa].killercages = []; - this[this.mode.qa].nobulbthermo = []; - - // Object and Array initialization for custom colors - this[this.mode.qa + "_col"] = {}; - this[this.mode.qa + "_col"].command_redo = new Stack(); - this[this.mode.qa + "_col"].command_undo = new Stack(); - this[this.mode.qa + "_col"].command_replay = new Stack(); - this[this.mode.qa + "_col"].surface = {}; - this[this.mode.qa + "_col"].number = {}; - this[this.mode.qa + "_col"].numberS = {}; - this[this.mode.qa + "_col"].symbol = {}; - this[this.mode.qa + "_col"].freeline = {}; - this[this.mode.qa + "_col"].freelineE = {}; - this[this.mode.qa + "_col"].thermo = []; - this[this.mode.qa + "_col"].arrows = []; - this[this.mode.qa + "_col"].direction = []; - this[this.mode.qa + "_col"].squareframe = []; - this[this.mode.qa + "_col"].polygon = []; - this[this.mode.qa + "_col"].line = {}; - this[this.mode.qa + "_col"].lineE = {}; - this[this.mode.qa + "_col"].wall = {}; - this[this.mode.qa + "_col"].cage = {}; - this[this.mode.qa + "_col"].deletelineE = {}; - this[this.mode.qa + "_col"].killercages = []; - this[this.mode.qa + "_col"].nobulbthermo = []; + this.reset_puzzle(this.mode.qa); + this.reset_puzzle(this.mode.qa + "_col"); } reset_arr() { @@ -460,9 +394,7 @@ class Puzzle { } } this.cellsoutsideFrame = []; - if (this.gridtype === "square" || - this.gridtype === "sudoku" || - this.gridtype === "kakuro") { + if (this.grid_is_square()) { for (var i = 1; i < this.nx0 - 1; i++) { // Cell Center let cell_firstrow = i + 1 * this.nx0; @@ -1313,6 +1245,10 @@ class Puzzle { return obj; } + grid_is_square() { + return (this.gridtype == "square" || this.gridtype == "kakuro" || this.gridtype == "sudoku"); + } + mode_set(mode, loadtype = 'new') { this.mode[this.mode.qa].edit_mode = mode; this.submode_reset(); @@ -1367,6 +1303,12 @@ class Puzzle { this.redraw(); } + number_multi_enabled() { + let edit_mode = this.mode[this.mode.qa].edit_mode; + let submode = this.mode[this.mode.qa][edit_mode][0]; + return (edit_mode === "number" && !["2"].includes(submode)); + } + submode_check(name) { if (document.getElementById(name)) { document.getElementById(name).checked = true; @@ -7118,6 +7060,18 @@ class Puzzle { } } + set_value(prop, key, value) { + this.record(prop, key, this.undoredo_counter); + this[this.mode.qa][prop][key] = value; + this.record_replay(prop, key, this.undoredo_counter); + } + + remove_value(prop, key) { + this.record(prop, key, this.undoredo_counter); + delete this[this.mode.qa][prop][key]; + this.record_replay(prop, key, this.undoredo_counter); + } + ///////////////////////////// // Key Event // @@ -7139,185 +7093,150 @@ class Puzzle { // var str_replace = ["+-=*", "+-=*"]; // if (str_replace[0].indexOf(key) != -1) { key = str_replace[1][str_replace[0].indexOf(key)]; } if (this.mode[this.mode.qa].edit_mode === "number") { - switch (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]) { - case "1": - // If the there are corner or sides present then get rid of them - // Only in Answer mode - if (this.mode.qa === "pu_a") { - var corner_cursor = 4 * (this.cursol + this.nx0 * this.ny0); - var side_cursor = 4 * (this.cursol + 2 * this.nx0 * this.ny0); + let submode = this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode]; + if (this.selection.length === 1) { + let clean_flag = this.check_neighbors(this.selection[0]); + if (!clean_flag) { + this.undoredo_counter = 0; + } else { + this.undoredo_counter = this.undoredo_counter + 1; + } + } else { + this.undoredo_counter = this.undoredo_counter + 1; + } + let cells = null; + if (this.number_multi_enabled()) + cells = this.selection; + else + cells = [this.cursol]; + for (var k of cells) { + switch (submode[0]) { + case "1": + // If the there are corner or sides present then get rid of them + // Only in Answer mode + if (this.mode.qa === "pu_a") { + var corner_cursor = 4 * (k + this.nx0 * this.ny0); + var side_cursor = 4 * (k + 2 * this.nx0 * this.ny0); - for (var j = 0; j < 4; j++) { - if (this[this.mode.qa].numberS[corner_cursor + j]) { - this.record("numberS", corner_cursor + j); - delete this[this.mode.qa].numberS[corner_cursor + j]; - this.record_replay("numberS", corner_cursor + j); - } + for (var j = 0; j < 4; j++) + if (this[this.mode.qa].numberS[corner_cursor + j]) + this.remove_value("numberS", corner_cursor + j); + + for (var j = 0; j < 4; j++) + if (this[this.mode.qa].numberS[side_cursor + j]) + this.remove_value("numberS", side_cursor + j); } - for (var j = 0; j < 4; j++) { - if (this[this.mode.qa].numberS[side_cursor + j]) { - this.record("numberS", side_cursor + j); - delete this[this.mode.qa].numberS[side_cursor + j]; - this.record_replay("numberS", side_cursor + j); + if (str_num.indexOf(key) != -1 && this[this.mode.qa].number[k]) { + con = parseInt(this[this.mode.qa].number[k][0], 10); // Convert to number + if (con >= 1 && con <= 9 && this[this.mode.qa].number[k][2] != "7") { // If already 1-9 exist, go to 2nd digit + number = con.toString() + key; + } else { + // It enters here when the cell already contains 2 digits. + number = key; } + } else { + // It enters for first entry in a cell and then for alphabets or special characters i.e. non numbers + number = key; } - } - this.record("number", this.cursol); - if (str_num.indexOf(key) != -1 && this[this.mode.qa].number[this.cursol]) { - con = parseInt(this[this.mode.qa].number[this.cursol][0], 10); // Convert to number - if (con >= 1 && con <= 9 && this[this.mode.qa].number[this.cursol][2] != "7") { // If already 1-9 exist, go to 2nd digit - number = con.toString() + key; + this.set_value("number", k, [number, submode[1], submode[0]]); + break; + case "2": // Arrow + if (this[this.mode.qa].number[k] && this[this.mode.qa].number[k][2] != "7") { + con = this[this.mode.qa].number[k][0]; } else { - // It enters here when the cell already contains 2 digits. - number = key; + con = ""; } - } else { - // It enters for first entry in a cell and then for alphabets or special characters i.e. non numbers - number = key; - } - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - break; - case "2": // Arrow - this.record("number", this.cursol); - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != "7") { - con = this[this.mode.qa].number[this.cursol][0]; - } else { - con = ""; - } - if (con.slice(-2, -1) === "_") { - conA = parseInt(con.slice(0, -2), 10); - arrow = con.slice(-2); - } else { - conA = parseInt(con, 10); - arrow = ""; - } - if (str_num.indexOf(key) != -1) { - if (conA >= 1 && conA <= 9) { // If 1 to 9 got to the second digit - number = conA.toString() + key; + if (con.slice(-2, -1) === "_") { + conA = parseInt(con.slice(0, -2), 10); + arrow = con.slice(-2); + } else { + conA = parseInt(con, 10); + arrow = ""; + } + if (str_num.indexOf(key) != -1) { + if (conA >= 1 && conA <= 9) { // If 1 to 9 got to the second digit + number = conA.toString() + key; + } else { + number = key; + } } else { number = key; } - } else { - number = key; - } - this[this.mode.qa].number[this.cursol] = [number + arrow, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - break; - case "3": // 1/4, corner - case "9": // Sides - this.record("numberS", this.cursolS); - if (this[this.mode.qa].numberS[this.cursolS]) { - con = this[this.mode.qa].numberS[this.cursolS][0]; - } else { - con = ""; - } - number = con + key; - this[this.mode.qa].numberS[this.cursolS] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1]]; - this.record_replay("numberS", this.cursolS); - break; - case "4": //tapa - if (key === ".") { key = " "; } - this.record("number", this.cursol); - if (this[this.mode.qa].number[this.cursol]) { - con = this[this.mode.qa].number[this.cursol][0]; - mode = this[this.mode.qa].number[this.cursol][2]; - } else { - con = ""; - mode = ""; - } - let con_expand = [...con]; - if (mode != 2 && mode != 7) { // If not arrow mode - if (con_expand.length >= 0 && con_expand.length <= 3) { // Max 4 values - number = con + key; + this.set_value("number", k, [number + arrow, submode[1], submode[0]]); + break; + case "3": // 1/4, corner + case "9": // Sides + if (this[this.mode.qa].numberS[k]) { + con = this[this.mode.qa].numberS[k][0]; } else { - number = con; // Don't update if more than 4 values + con = ""; } - } else { // Overwrite if arrow - number = key; - } - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - break; - case "5": // Small - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != "2" && this[this.mode.qa].number[this.cursol][2] != "7") { - con = this[this.mode.qa].number[this.cursol][0]; - } else { - con = ""; - } - if (con.length < 10) { - this.record("number", this.cursol); - number = con + key; - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - } - break; - case "6": // Medium - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != "2" && this[this.mode.qa].number[this.cursol][2] != "7") { - con = this[this.mode.qa].number[this.cursol][0]; - } else { - con = ""; - } - if (con.length < 10) { - this.record("number", this.cursol); number = con + key; - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - } - break; - case "10": //big - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != "2" && this[this.mode.qa].number[this.cursol][2] != "7") { - con = this[this.mode.qa].number[this.cursol][0]; - } else { - con = ""; - } - if (con.length < 10) { - this.record("number", this.cursol); - number = con + key; - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - } - break; - case "7": // Candidates - if (str_num_no0.indexOf(key) != -1) { - this.record("number", this.cursol); - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] === "7") { - con = this[this.mode.qa].number[this.cursol][0]; + this.set_value("numberS", k, [number, submode[1]]); + break; + case "4": //tapa + if (key === ".") { key = " "; } + if (this[this.mode.qa].number[k]) { + con = this[this.mode.qa].number[k][0]; + mode = this[this.mode.qa].number[k][2]; + } else { + con = ""; + mode = ""; + } + let con_expand = [...con]; + if (mode != 2 && mode != 7) { // If not arrow mode + if (con_expand.length >= 0 && con_expand.length <= 3) { // Max 4 values + number = con + key; + } else { + number = con; // Don't update if more than 4 values + } + } else { // Overwrite if arrow + number = key; + } + this.set_value("number", k, [number, submode[1], submode[0]]); + break; + case "5": // Small + case "6": // Medium + case "10": //big + case "8": // Long + if (this[this.mode.qa].number[k] && this[this.mode.qa].number[k][2] != "2" && this[this.mode.qa].number[k][2] != "7") { + con = this[this.mode.qa].number[k][0]; + } else { + con = ""; + } + // Length limit of 10 except for Long submode which has 50 + const limit = (submode[0] === "8") ? 50 : 10; + if (con.length < limit) { + number = con + key; + this.set_value("number", k, [number, submode[1], submode[0]]); + } + break; + + case "7": // Candidates + if (str_num_no0.indexOf(key) != -1) { + if (this[this.mode.qa].number[k] && this[this.mode.qa].number[k][2] === "7") { + con = this[this.mode.qa].number[k][0]; + } else { + con = ""; + } + number = this.onofftext(9, key, con); + this.set_value("number", k, [number, submode[1], submode[0]]); + } + break; + + case "11": // Killer Sum + var corner_cursor = 4 * (k + this.nx0 * this.ny0); + if (this[this.mode.qa].numberS[corner_cursor]) { + con = " " + this[this.mode.qa].numberS[corner_cursor][0]; } else { con = ""; } - number = this.onofftext(9, key, con); - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - } - break; - case "8": // Long - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != "2" && this[this.mode.qa].number[this.cursol][2] != "7") { - con = this[this.mode.qa].number[this.cursol][0]; - } else { - con = ""; - } - if (con.length < 50) { - this.record("number", this.cursol); number = con + key; - this[this.mode.qa].number[this.cursol] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1], this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]]; - this.record_replay("number", this.cursol); - } - break; - case "11": // Killer Sum - var corner_cursor = 4 * (this.cursol + this.nx0 * this.ny0); - this.record("numberS", corner_cursor); - if (this[this.mode.qa].numberS[corner_cursor]) { - con = " " + this[this.mode.qa].numberS[corner_cursor][0]; - } else { - con = ""; - } - number = con + key; - this[this.mode.qa].numberS[corner_cursor] = [number, this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][1]]; - this.record_replay("numberS", corner_cursor); - break; + this.set_value("numberS", corner_cursor, [number, submode[1]]); + break; + } } } else if (this.mode[this.mode.qa].edit_mode === "symbol") { if (str_num.indexOf(key) != -1) { @@ -7410,7 +7329,7 @@ class Puzzle { } } - if (this.gridtype === "square" || this.gridtype === "sudoku" || this.gridtype === "kakuro") { + if (this.grid_is_square()) { // not reliable, every access, the order is changing and hence sorting var adjacent_cursor = this.get_neighbors(k, 'adjacent').sort(); @@ -7459,7 +7378,7 @@ class Puzzle { } break; case "2": // Corner mode - if (this.gridtype === "square" || this.gridtype === "sudoku" || this.gridtype === "kakuro") { + if (this.grid_is_square()) { if (this.selection.length > 0 && str_all.indexOf(key) != -1) { if (this.selection.length === 1) { @@ -7910,53 +7829,74 @@ class Puzzle { key_backspace() { var number; if (this.mode[this.mode.qa].edit_mode === "number") { - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3" || this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "9") { // 1/4 and side - if (this[this.mode.qa].numberS[this.cursolS]) { - this.record("numberS", this.cursolS); - number = this[this.mode.qa].numberS[this.cursolS][0].slice(0, -1); - if (number) { - this[this.mode.qa].numberS[this.cursolS][0] = number; + let submode = this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]; + if (this.selection.length > 0) { + if (this.selection.length === 1) { + let clean_flag = this.check_neighbors(this.selection[0]); + if (!clean_flag) { + this.undoredo_counter = 0; } else { - delete this[this.mode.qa].numberS[this.cursolS]; - } - this.record_replay("numberS", this.cursolS); - } - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "11") { - var corner_cursor = 4 * (this.cursol + this.nx0 * this.ny0); - if (this[this.mode.qa].numberS[corner_cursor]) { - this.record("numberS", corner_cursor); - number = this[this.mode.qa].numberS[corner_cursor][0].slice(1, -1); - if (number) { - this[this.mode.qa].numberS[corner_cursor][0] = number; - } else { - delete this[this.mode.qa].numberS[corner_cursor]; + this.undoredo_counter = this.undoredo_counter + 1; } - this.record_replay("numberS", corner_cursor); + } else { + this.undoredo_counter = this.undoredo_counter + 1; } - } else { - if (this[this.mode.qa].number[this.cursol] && this[this.mode.qa].number[this.cursol][2] != 7) { - this.record("number", this.cursol); - number = this[this.mode.qa].number[this.cursol][0]; - if (number) { - if (this[this.mode.qa].number[this.cursol][2] === "2") { - if (number.slice(-2, -1) === "_") { - number = number.slice(0, -2).slice(0, -1) + number.slice(-2); + let cells = null; + if (this.number_multi_enabled()) + cells = this.selection; + else + cells = [this.cursol]; + + for (var k of cells) { + if (submode === "3" || submode === "9") { // 1/4 and side + if (this[this.mode.qa].numberS[k]) { + this.record("numberS", k, this.undoredo_counter); + number = this[this.mode.qa].numberS[k][0].slice(0, -1); + if (number) { + this[this.mode.qa].numberS[k][0] = number; } else { - number = number.slice(0, -1); + delete this[this.mode.qa].numberS[k]; } - } else { - number = number.slice(0, -1); + this.record_replay("numberS", k, this.undoredo_counter); } - if (number || - this[this.mode.qa].number[this.cursol][1] === 6 || - this[this.mode.qa].number[this.cursol][1] === 7 || - this[this.mode.qa].number[this.cursol][1] === 11) { - this[this.mode.qa].number[this.cursol][0] = number; - } else { - delete this[this.mode.qa].number[this.cursol]; + } else if (submode === "11") { + var corner_cursor = 4 * (k + this.nx0 * this.ny0); + if (this[this.mode.qa].numberS[corner_cursor]) { + this.record("numberS", corner_cursor, this.undoredo_counter); + number = this[this.mode.qa].numberS[corner_cursor][0].slice(1, -1); + if (number) { + this[this.mode.qa].numberS[corner_cursor][0] = number; + } else { + delete this[this.mode.qa].numberS[corner_cursor]; + } + this.record_replay("numberS", corner_cursor, this.undoredo_counter); + } + } else { + if (this[this.mode.qa].number[k] && this[this.mode.qa].number[k][2] != 7) { + this.record("number", k, this.undoredo_counter); + number = this[this.mode.qa].number[k][0]; + if (number) { + if (this[this.mode.qa].number[k][2] === "2") { + if (number.slice(-2, -1) === "_") { + number = number.slice(0, -2).slice(0, -1) + number.slice(-2); + } else { + number = number.slice(0, -1); + } + } else { + number = number.slice(0, -1); + } + if (number || + this[this.mode.qa].number[k][1] === 6 || + this[this.mode.qa].number[k][1] === 7 || + this[this.mode.qa].number[k][1] === 11) { + this[this.mode.qa].number[k][0] = number; + } else { + delete this[this.mode.qa].number[k]; + } + } + this.record_replay("number", k, this.undoredo_counter); } } - this.record_replay("number", this.cursol); } } } @@ -7974,23 +7914,34 @@ class Puzzle { mouseevent(x, y, num, ctrl_key = false) { if (!pu.replay) { num = this.recalculate_num(x, y, num); //for uniform tiling - switch (this.mode[this.mode.qa].edit_mode) { + let edit_mode = this.mode[this.mode.qa].edit_mode; + let submode = this.mode[this.mode.qa][edit_mode][0]; + + // Map shift/ctrl-click to right click in certain modes for convenience + if (ctrl_key && this.mouse_mode === "down_left" && + (edit_mode === "surface" || edit_mode === "combi")) { + this.mouse_mode = "down_right"; + this.mouse_click = 2; + this.mouse_click_last = 2; + } + + switch (edit_mode) { case "surface": this.mouse_surface(x, y, num); break; case "line": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3") { + if (submode === "3") { this.mouse_linefree(x, y, num); - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "4") { + } else if (submode === "4") { this.mouse_lineX(x, y, num); } else { this.mouse_line(x, y, num); } break; case "lineE": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3") { + if (submode === "3") { this.mouse_lineEfree(x, y, num); - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "4") { + } else if (submode === "4") { this.mouse_lineEX(x, y, num); } else { this.mouse_lineE(x, y, num); @@ -8000,14 +7951,14 @@ class Puzzle { this.mouse_wall(x, y, num); break; case "number": - let submode = this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]; - if (submode === "3" || submode === "9") { - this.mouse_numberS(x, y, num, submode); - } else { - this.mouse_number(x, y, num); - } + // Multi-selection mode: treat this just like sudoku mode if we're in + // a submode that can work with multiple cells + if (this.number_multi_enabled()) + this.mouse_sudoku(x, y, num, ctrl_key); + else + this.mouse_number(x, y, num, ctrl_key); if (pu.mouse_mode === "down_left") { - let isNumberS = ["3", "9", "11"].includes(pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0]) + let isNumberS = ["3", "9", "11"].includes(submode) let enableLoadButton = (!isNumberS && pu[pu.mode.qa].number[pu.cursol]) || (isNumberS && pu[pu.mode.qa].numberS[pu.cursolS]); document.getElementById("closeBtn_input3").disabled = !enableLoadButton; } @@ -8037,6 +7988,40 @@ class Puzzle { } } + // Double click: select all cells with the same value as the clicked cell + // XXX: support other cell types + dblmouseevent(x, y, num, ctrl_key = false) { + let edit_mode = this.mode[this.mode.qa].edit_mode; + if (edit_mode === "number" || edit_mode === "sudoku") { + if (!ctrl_key) + this.selection = []; + + let value = this.pu_q.number[num] || this.pu_a.number[num]; + let remove = this.selection.indexOf(num) !== -1; + + // Normal sudoku values + if (value) { + let n = value[0]; + + for (let qa of ["pu_q", "pu_a"]) { + let puzzle = this[qa]; + + for (let c of this.centerlist) { + if (puzzle.number[c] && puzzle.number[c][0] == n) { + if (remove) { + var index = this.selection.indexOf(c); + if (index !== -1) + this.selection.splice(index, 1); + } else if (this.selection.indexOf(c) === -1) + this.selection.push(c); + } + } + } + } + this.redraw(); + } + } + ////////////////////////// // surface ////////////////////////// @@ -8648,7 +8633,7 @@ class Puzzle { this.cursol = num; // Remember cursolS - if (this.gridtype == "square" || this.gridtype == "kakuro" || this.gridtype == "sudoku") { + if (this.grid_is_square()) { if (!this.cellsoutsideFrame.includes(this.cursol)) { this.cursolS = 4 * (this.cursol + this.nx0 * this.ny0); } @@ -8658,7 +8643,7 @@ class Puzzle { this.cursol = num; // Remember cursolS - if (this.gridtype == "square" || this.gridtype == "kakuro" || this.gridtype == "sudoku") { + if (this.grid_is_square()) { if (!this.cellsoutsideFrame.includes(this.cursol)) { this.cursolS = 4 * (this.cursol + this.nx0 * this.ny0); } @@ -8677,26 +8662,6 @@ class Puzzle { } } - mouse_numberS(x, y, num, submode) { - if (this.mouse_mode === "down_left") { - this.cursolS = num; - - // Remember cursol - if (this.gridtype == "square" || this.gridtype == "kakuro" || this.gridtype == "sudoku") { - if (submode === "3") { - this.cursol = parseInt(this.cursolS / 4) - this.nx0 * this.ny0; - } else if (submode === "9") { - this.cursol = parseInt(this.cursolS / 4) - 2 * this.nx0 * this.ny0; - } - } - this.redraw(); - } else if (this.mouse_mode === "down_right") { - this.cursolS = num; - this.redraw(); - } - } - - mouse_sudoku(x, y, num, ctrl_key = false) { // if (this.point[num].type === 0) {} // Add this line, to ignore corners and allow diagonal selection, and set type = [0, 1] if (this.mouse_mode === "down_left") { @@ -8715,7 +8680,7 @@ class Puzzle { this.cursol = num; // Remember cursolS - if (this.gridtype == "square" || this.gridtype == "kakuro" || this.gridtype == "sudoku") { + if (this.grid_is_square()) { if (!this.cellsoutsideFrame.includes(this.cursol)) { this.cursolS = 4 * (this.cursol + this.nx0 * this.ny0); } @@ -8723,12 +8688,16 @@ class Puzzle { this.redraw(); } else if (this.mouse_mode === "move") { // if the first selected position is edge then do not consider move - if (this.selection.length === 1 && parseInt(this.selection[0] / (this.nx0 * this.ny0)) > 0 && + if (this.cursol && this.cursol >= this.nx0 * this.ny0 && this.gridtype !== "iso" && this.gridtype !== "tetrakis_square" && this.gridtype !== "truncated_square" && this.gridtype !== "snub_square" && this.gridtype !== "cairo_pentagonal" && this.gridtype !== "rhombitrihexagonal" && this.gridtype !== "deltoidal_trihexagonal") { // do nothing - } else if (!this.selection.includes(num) & this.drawing) { + } else if (this.select_remove && this.drawing) { + let i = this.selection.indexOf(num); + if (i !== -1) + this.selection.splice(i, 1); + } else if (!this.selection.includes(num) && this.drawing) { this.selection.push(num); } this.redraw(); @@ -9613,7 +9582,7 @@ class Puzzle { break; case "edgexoi": case "tents": - if (this.mouse_mode === "down_right" || this.ondown_key === "touchstart") { + if (this.mouse_click === 2 || this.ondown_key === "touchstart") { num = this.coord_p_edgex(x, y, 0.3); } else { num = this.coord_p_edgex(x, y, 0.01); @@ -10423,7 +10392,7 @@ class Puzzle { } else { // Ignore if edge already exist // Do this only for square grids for now - if (this.gridtype === "square") { + if (this.grid_is_square()) { let neighbor1 = this.point[num].neighbor[0]; let neighbor2 = this.point[num].neighbor[1]; @@ -12024,20 +11993,16 @@ class Puzzle { } draw_cursol() { + let edit_mode = this.mode[this.mode.qa].edit_mode; /*cursol*/ - if (this.mode[this.mode.qa].edit_mode === "number" || this.mode[this.mode.qa].edit_mode === "symbol") { + if ((edit_mode === "number" && !this.number_multi_enabled()) || edit_mode === "symbol") { set_line_style(this.ctx, 99); - if (this.mode[this.mode.qa].edit_mode === "symbol" && UserSettings.panel_shown && !pu.onoff_symbolmode_list[pu.mode[this.mode.qa].symbol[0]]) { + if (edit_mode === "symbol" && UserSettings.panel_shown && !pu.onoff_symbolmode_list[pu.mode[this.mode.qa].symbol[0]]) { this.ctx.strokeStyle = Color.BLUE_DARK_VERY; } this.ctx.fillStyle = Color.TRANSPARENTBLACK; - if (this.mode[this.mode.qa].edit_mode === "number" && (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3" || this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "9")) { - if (this.cursolS) { - this.draw_polygon(this.ctx, this.point[this.cursolS].x, this.point[this.cursolS].y, 0.2, 4, 45); - } else { - this.default_cursol(); - } - } else if (UserSettings.draw_edges) { + let submode = this.mode[this.mode.qa][edit_mode][0]; + if (UserSettings.draw_edges) { this.draw_polygon(this.ctx, this.point[this.cursol].x, this.point[this.cursol].y, 0.2, 4, 45); } else { this.default_cursol(); @@ -12073,16 +12038,18 @@ class Puzzle { } draw_selection() { - if (this.mode[this.mode.qa].edit_mode === "sudoku" || - (this.mode[this.mode.qa].edit_mode === "cage" && document.getElementById("sub_cage1").checked)) { + let edit_mode = this.mode[this.mode.qa].edit_mode; + if (edit_mode === "sudoku" || this.number_multi_enabled() || + (edit_mode === "cage" && document.getElementById("sub_cage1").checked)) { + // [ZW] removing this for now, preventing escape to clear selection, not sure what the purpose is // since we dont want single cell highlighed while in killer submode - if (this.selection.length === 0 && this.mode[this.mode.qa].edit_mode === "sudoku") { - // check if cursor is in centerlist, to avoid border/edge case - let cursorexist = this.centerlist.indexOf(this.cursol); - if (cursorexist !== -1) { - this.selection.push(this.cursol); - } - } + //if (this.selection.length === 0 && this.mode[this.mode.qa].edit_mode === "sudoku") { + // // check if cursor is in centerlist, to avoid border/edge case + // let cursorexist = this.centerlist.indexOf(this.cursol); + // if (cursorexist !== -1) { + // this.selection.push(this.cursol); + // } + //} // Handling rotation and reflection of the grid var a = [0, 1, 2, 3], @@ -12106,7 +12073,7 @@ class Puzzle { } for (var k of this.selection) { let factor, offset; - if (this.gridtype === "square" || this.gridtype === "sudoku" || this.gridtype === "kakuro") { + if (this.grid_is_square()) { factor = parseInt(k / (this.nx0 * this.ny0)); offset = 3; } else if (this.gridtype === "iso") { @@ -12154,7 +12121,7 @@ class Puzzle { } else { let r, n, th; let tol = 0.01; // error tolerance - if (this.gridtype === "square" || this.gridtype === "sudoku" || this.gridtype === "kakuro") { + if (this.grid_is_square()) { r = 0.2; n = 4; th = 45; @@ -12631,4 +12598,4 @@ class Puzzle { return !this.version_gt(major, minor, revision); } -} \ No newline at end of file +} diff --git a/docs/js/class_square.js b/docs/js/class_square.js index 48a24a76..7f3fb77c 100644 --- a/docs/js/class_square.js +++ b/docs/js/class_square.js @@ -50,6 +50,7 @@ class Puzzle_square extends Puzzle { var ny = this.ny0; var adjacent, surround, type, use, neighbor, adjacent_dia; var point = []; + const index = (x, y) => [x, y, this.nx0 * y + x]; //center type = 0; for (var j = 0; j < ny; j++) { @@ -59,7 +60,7 @@ class Puzzle_square extends Puzzle { adjacent_dia = [k - nx - 1, k - nx + 1, k + nx - 1, k + nx + 1]; surround = [k + nx * ny - nx - 1, k + nx * ny - nx, k + nx * ny, k + nx * ny - 1]; neighbor = [k + 2 * nx * ny - nx, k + 2 * nx * ny, k + 3 * nx * ny - 1, k + 3 * nx * ny]; - point[k] = new Point((i + 0.5) * this.size, (j + 0.5) * this.size, type, adjacent, surround, use, neighbor, adjacent_dia); + point[k] = new Point((i + 0.5) * this.size, (j + 0.5) * this.size, type, adjacent, surround, use, neighbor, adjacent_dia, 0, index(i, j)); k++; } } @@ -71,7 +72,7 @@ class Puzzle_square extends Puzzle { adjacent = [k - nx, k - 1, k + 1, k + nx]; adjacent_dia = [k - nx - 1, k - nx + 1, k + nx - 1, k + nx + 1]; surround = []; - point[k] = new Point(point[i + j * nx].x + 0.5 * this.size, point[i + j * nx].y + 0.5 * this.size, type, adjacent, surround, use, [], adjacent_dia); + point[k] = new Point(point[i + j * nx].x + 0.5 * this.size, point[i + j * nx].y + 0.5 * this.size, type, adjacent, surround, use, [], adjacent_dia, 0, index(i, j)); k++; } } @@ -85,7 +86,7 @@ class Puzzle_square extends Puzzle { adjacent = [k + nx, k - nx]; surround = []; neighbor = [k - 2 * nx * ny, k - 2 * nx * ny + nx]; - point[k] = new Point(point[i + j * nx].x, point[i + j * nx].y + 0.5 * this.size, type, adjacent, surround, use, neighbor); + point[k] = new Point(point[i + j * nx].x, point[i + j * nx].y + 0.5 * this.size, type, adjacent, surround, use, neighbor, [], 0, index(i, j)); k++; } } @@ -96,7 +97,7 @@ class Puzzle_square extends Puzzle { adjacent = [k + 1, k - 1]; surround = []; neighbor = [k - 3 * nx * ny, k - 3 * nx * ny + 1]; - point[k] = new Point(point[i + j * nx].x + 0.5 * this.size, point[i + j * nx].y, type, adjacent, surround, use, neighbor); + point[k] = new Point(point[i + j * nx].x + 0.5 * this.size, point[i + j * nx].y, type, adjacent, surround, use, neighbor, [], 0, index(i, j)); k++; } } @@ -109,16 +110,16 @@ class Puzzle_square extends Puzzle { if (i === 0 || i === nx - 1 || j === 0 || j === ny - 1) { use = -1; } else { use = 1; } surround = []; adjacent = [k - 4 * nx + 2, k - 3, k + 1, k + 2]; - point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; adjacent = [k - 4 * nx + 2, k - 1, k + 3, k + 2]; - point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; adjacent = [k - 2, k - 3, k + 1, k + 4 * nx - 2]; - point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; adjacent = [k - 2, k - 1, k + 3, k + 4 * nx - 2]; - point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; } } @@ -131,13 +132,13 @@ class Puzzle_square extends Puzzle { if (i === 0 || i === nx - 1 || j === 0 || j === ny - 1) { use = -1; } else { use = 1; } adjacent = []; surround = []; - point[k] = new Point(point[i + j * nx].x - 0 * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x - 0 * this.size, point[i + j * nx].y - r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; - point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y - 0 * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x + r * this.size, point[i + j * nx].y - 0 * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; - point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y + 0 * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x - r * this.size, point[i + j * nx].y + 0 * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; - point[k] = new Point(point[i + j * nx].x + 0 * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use); + point[k] = new Point(point[i + j * nx].x + 0 * this.size, point[i + j * nx].y + r * this.size, type, adjacent, surround, use, [], [], 0, index(i, j)); k++; } } @@ -180,7 +181,9 @@ class Puzzle_square extends Puzzle { type_set() { var type - switch (this.mode[this.mode.qa].edit_mode) { + let edit_mode = this.mode[this.mode.qa].edit_mode; + let submode = this.mode[this.mode.qa][edit_mode][0]; + switch (edit_mode) { case "surface": case "board": type = [0]; @@ -194,11 +197,11 @@ class Puzzle_square extends Puzzle { } break; case "number": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "2") { + if (submode === "2") { type = [0]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3") { + } else if (submode === "3") { type = [4]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "9") { + } else if (submode === "9") { type = [5]; } else { if (!UserSettings.draw_edges) { @@ -209,20 +212,20 @@ class Puzzle_square extends Puzzle { } break; case "line": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "4") { + if (submode === "4") { type = [2, 3]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "2") { + } else if (submode === "2") { type = [0, 1]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "5") { + } else if (submode === "5") { type = [0, 2, 3]; } else { type = [0]; } break; case "lineE": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "4") { + if (submode === "4") { type = [2, 3]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "2") { + } else if (submode === "2") { type = [0, 1]; } else { type = [1]; @@ -236,21 +239,21 @@ class Puzzle_square extends Puzzle { } break; case "cage": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "1") { + if (submode === "1") { type = [0]; - } else if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "2") { + } else if (submode === "2") { type = [4]; } break; case "special": - if (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "polygon") { + if (submode === "polygon") { type = [1]; } else { type = [0, 1]; } break; case "combi": - switch (this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0]) { + switch (submode) { case "tents": case "linex": case "linedir": @@ -347,11 +350,13 @@ class Puzzle_square extends Puzzle { } cursolcheck() { - if (this.mode[this.mode.qa].edit_mode === "number" && this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3") { + let edit_mode = this.mode[this.mode.qa].edit_mode; + let submode = this.mode[this.mode.qa][edit_mode][0]; + if (edit_mode === "number" && submode === "3") { if (this.cursolS > 8 * (this.nx0) * (this.ny0)) { this.cursolS -= 4 * (this.nx0) * (this.ny0); } - } else if (this.mode[this.mode.qa].edit_mode === "number" && this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "9") { + } else if (edit_mode === "number" && submode === "9") { if (this.cursolS < 8 * (this.nx0) * (this.ny0)) { this.cursolS += 4 * (this.nx0) * (this.ny0); } @@ -386,8 +391,10 @@ class Puzzle_square extends Puzzle { c = b[3]; break; } - if (this.mode[this.mode.qa].edit_mode === "number" || this.mode[this.mode.qa].edit_mode === "symbol" || this.mode[this.mode.qa].edit_mode === "sudoku") { - if (this.mode[this.mode.qa].edit_mode === "number" && this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "3") { + let edit_mode = this.mode[this.mode.qa].edit_mode; + let submode = this.mode[this.mode.qa][edit_mode][0]; + if (edit_mode === "number" || edit_mode === "symbol" || edit_mode === "sudoku") { + if (edit_mode === "number" && submode === "3") { switch (c) { case 0: a = this.cursolS % 2 === 0 ? this.cursolS - 3 : this.cursolS - 1; @@ -412,7 +419,7 @@ class Puzzle_square extends Puzzle { if (!this.selection.includes(this.cursol)) { this.selection.push(this.cursol); } - } else if (this.mode[this.mode.qa].edit_mode === "number" && this.mode[this.mode.qa][this.mode[this.mode.qa].edit_mode][0] === "9") { + } else if (edit_mode === "number" && submode === "9") { switch (c) { case 0: a = this.cursolS % 4 === 2 ? this.cursolS - 4 : this.cursolS - this.cursolS % 4 + 2; @@ -437,7 +444,7 @@ class Puzzle_square extends Puzzle { if (!this.selection.includes(this.cursol)) { this.selection.push(this.cursol); } - } else if (this.mode[this.mode.qa].edit_mode === "sudoku") { + } else if (edit_mode === "sudoku" || (edit_mode === "number" && this.number_multi_enabled())) { if (this.selection.length >= 1) { var current_cursor = this.cursol; switch (c) { @@ -4175,4 +4182,4 @@ class Puzzle_kakuro extends Puzzle_square { this[this.mode.qa].symbol[(i + 2) + ((j + 2) * this.nx0)] = [1, "kakuro", 2]; } } -} \ No newline at end of file +} diff --git a/docs/js/class_tri.js b/docs/js/class_tri.js index 8f9ad4a0..4f2f5837 100644 --- a/docs/js/class_tri.js +++ b/docs/js/class_tri.js @@ -373,7 +373,8 @@ class Puzzle_tri extends Puzzle { c = b[3]; break; } - if (this.mode[this.mode.qa].edit_mode === "number" || this.mode[this.mode.qa].edit_mode === "symbol") { + let edit_mode = this.mode[this.mode.qa].edit_mode; + if (edit_mode === "number" || edit_mode === "sudoku" || edit_mode === "symbol") { if (parseInt(this.cursol / (this.n0) ** 2) === 1) { switch (c) { case 0: @@ -410,6 +411,14 @@ class Puzzle_tri extends Puzzle { } } } + + if (!ctrl_key) { + this.selection = []; + } + if (!this.selection.includes(this.cursol)) { + this.selection.push(this.cursol); + } + this.redraw(); } @@ -2729,4 +2738,4 @@ class Puzzle_tri extends Puzzle { th = th / 180 * Math.PI; return th; } -} \ No newline at end of file +} diff --git a/docs/js/main.js b/docs/js/main.js index 7f12a612..54cf215c 100644 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -111,13 +111,15 @@ onload = function() { function onDown(e) { if ((ondown_key === "mousedown" && e.button !== 1) || (ondown_key === "touchstart")) { // Ignore Middle button - if (e.type === "mousedown") { + if (e.type === "mousedown" || e.type === "dblclick") { var event = e; } else { var event = e.changedTouches[0]; e.preventDefault(); // When both mouse and touch start, only touch } - if (ondown_key === "mousedown" && event.button !== 2 && pu.mode[pu.mode.qa].edit_mode !== "sudoku") { // not right click and so improve the coordinate system for certain modes + if (ondown_key === "mousedown" && event.button !== 2 && + pu.mode[pu.mode.qa].edit_mode !== "number" && + pu.mode[pu.mode.qa].edit_mode !== "sudoku") { // not right click and so improve the coordinate system for certain modes var obj = coord_point(event, 'flex'); } else { var obj = coord_point(event); @@ -125,24 +127,36 @@ onload = function() { var x = obj.x, y = obj.y, num = obj.num; + + let ctrl = isCtrlKeyHeld(e) || isShiftKeyHeld(e); + + // Remember whether this cell was already in the selection so we can + // remove instead of add cells + pu.select_remove = ctrl && pu.selection.indexOf(num) !== -1; + let skip_mouseevent = restrict_mouse(num); if (pu.point[num].use === 1 && !skip_mouseevent) { - if (event.button === 2) { // right click + if (e.type === "dblclick") { + pu.mouse_mode = "down_left"; + pu.mouse_click = 0; + pu.dblmouseevent(x, y, num, ctrl); + } else if (event.button === 2) { // right click pu.mouse_mode = "down_right"; pu.mouse_click = 2; pu.mouse_click_last = 2; - pu.mouseevent(x, y, num, isCtrlKeyHeld(e)); + pu.mouseevent(x, y, num, ctrl); } else { // Left click or tap pu.mouse_mode = "down_left"; pu.mouse_click = 0; pu.mouse_click_last = 1; - pu.mouseevent(x, y, num, isCtrlKeyHeld(e)); + pu.mouseevent(x, y, num, ctrl); } } } } function onUp(e) { + let edit_mode = pu.mode[pu.mode.qa].edit_mode; if ((ondown_key === "mousedown" && e.button !== 1) || (ondown_key === "touchstart")) { // Ignore Middle button if (e.type === "mouseup") { var event = e; @@ -150,9 +164,10 @@ onload = function() { var event = e.changedTouches[0]; e.preventDefault(); // When both mouse and touch start, only touch } - if (ondown_key === "mousedown" && (pu.mode[pu.mode.qa].edit_mode === "combi") && // to handle mobile/ipad users for up events for certain modes - (pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0] === "yajilin" || - pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0] === "akari")) { + // to handle mobile/ipad users for up events for certain modes + if (ondown_key === "mousedown" && (edit_mode === "sudoku" || edit_mode === "number" || + (edit_mode === "combi" && (pu.mode[pu.mode.qa][edit_mode][0] === "yajilin" || + pu.mode[pu.mode.qa][edit_mode][0] === "akari")))) { var obj = coord_point(event, 'flex'); } else { var obj = coord_point(event); @@ -173,6 +188,7 @@ onload = function() { } function onMove(e) { + let edit_mode = pu.mode[pu.mode.qa].edit_mode; if ((ondown_key === "mousedown" && e.buttons !== 4) || (ondown_key === "touchstart")) { // Ignore Middle button if (e.type === "mousemove") { var event = e; @@ -183,12 +199,13 @@ onload = function() { if (event.buttons === 2) { // Right click and moving pu.mouse_click = 2; var obj = coord_point(event, 'flex'); - } else if ((ondown_key === "touchstart" || event.buttons === 1) && pu.mode[pu.mode.qa].edit_mode === "sudoku") { // Left click/Ipad and moving in Sudoku Mode + } else if ((ondown_key === "touchstart" || event.buttons === 1) && + (edit_mode === "sudoku" || edit_mode === "number")) { // Left click/Ipad and moving in Sudoku Mode pu.mouse_click = 0; var obj = coord_point(event, 'flex'); } else { - if (((pu.mode[pu.mode.qa].edit_mode === "combi") && (pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0] === "yajilin" || - pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0] === "akari"))) { + if (((edit_mode === "combi") && (pu.mode[pu.mode.qa][edit_mode][0] === "yajilin" || + pu.mode[pu.mode.qa][edit_mode][0] === "akari"))) { var obj = coord_point(event, 'flex'); } else { var obj = coord_point(event); @@ -339,7 +356,7 @@ onload = function() { if (pu.mode[pu.mode.qa].edit_mode === "sudoku" && keylocation === 3) { // Skip arrow behavior deliberately for sudoku numpad usage. } else { - pu.key_arrow(key, isCtrlKeyHeld(e)); + pu.key_arrow(key, isCtrlKeyHeld(e) || isShiftKeyHeld(e)); e.returnValue = false; } } @@ -348,6 +365,28 @@ onload = function() { return false; } + if (key === 'Escape') { + // Escape out of any modal dialogs if they're open + + // Weird hack to make sure any sub-dialogs are exited first + const sub_modals = ["modal-save-tag", "modal-save2"]; + let modals = [...document.getElementsByClassName('modal')]; + modals.sort((a, b) => !sub_modals.includes(a.id) && sub_modals.includes(b.id)); + + for (var m of modals) { + if (m.style.display && m.style.display !== 'none') { + e.preventDefault(); + m.style.display = 'none'; + return false; + } + } + + pu.selection = []; + pu.redraw(); + e.returnValue = false; + return false; + } + // All of this is specific to sudoku if (pu.mode[pu.mode.qa].edit_mode === "sudoku") { @@ -802,6 +841,7 @@ onload = function() { } var key = e.key; + const keylocation = e.location; if (isShiftKeyPressed(key) && keylocation !== 3 && pu.mode[pu.mode.qa].edit_mode === "sudoku") { if (present_submode === "1") { @@ -843,21 +883,20 @@ onload = function() { var y = e.pageY - canvas.offsetTop; var min0, min = 10e6; var num = 0; - let type; var improve_modes = ["star", "yajilin", "mines", "doublemines", "akari"]; + let edit_mode = pu.mode[pu.mode.qa].edit_mode; + + let type = pu.type; // Improving starbattle composite mode, left click if (fittype === 'flex') { - if (((pu.mode[pu.mode.qa].edit_mode === "combi") && - (improve_modes.includes(pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0]))) || - (pu.mode[pu.mode.qa].edit_mode === "sudoku")) { - type = pu.type; - pu.type = [0]; - } + if ((edit_mode === "combi" && improve_modes.includes(pu.mode[pu.mode.qa][edit_mode][0])) || + edit_mode === "sudoku" || edit_mode === "number") + type = [0]; } for (var i = 0; i < pu.point.length; i++) { - if (pu.point[i] && pu.type.indexOf(pu.point[i].type) != -1) { + if (pu.point[i] && type.indexOf(pu.point[i].type) != -1) { min0 = (x - pu.point[i].x) ** 2 + (y - pu.point[i].y) ** 2; if (min0 < min) { min = min0; @@ -866,15 +905,6 @@ onload = function() { } } - // resetting the type for starbattle composite mode - if (fittype === 'flex') { - if (((pu.mode[pu.mode.qa].edit_mode === "combi") && - (improve_modes.includes(pu.mode[pu.mode.qa][pu.mode[pu.mode.qa].edit_mode][0]))) || - (pu.mode[pu.mode.qa].edit_mode === "sudoku")) { - pu.type = type; - } - } - //const endTime = performance.now(); //console.log(endTime - startTime); num = parseInt(num); @@ -991,14 +1021,6 @@ onload = function() { if (!pu.ondown_key) { pu.ondown_key = ondown_key; } - // This segment of code I added for a purpose but don't recollect the reason. - // After the new improvements maybe this is not needed but for now retaining it as it doesn't impact anything. - if (pu.selection.length > 0 && e.target.id.indexOf("sub_sudoku") == -1 && e.target.id.indexOf("st_sudoku") == -1 && - e.target.id != "float-canvas" && !isCtrlKeyHeld(e)) { - // clear selection - pu.selection = []; - pu.redraw(); - } // Middle click for switching problem and solution // Applicable only in setter mode if (document.getElementById("title").textContent.toLowerCase().includes("setter")) { @@ -1898,6 +1920,18 @@ onload = function() { return lines; } + // Double click to select all of a certain element + document.addEventListener("dblclick", window_dblclick, { passive: false }); + function window_dblclick(e) { + if (e.target.id === "canvas") { + document.getElementById("inputtext").blur(); // Remove focus from text box + onDown(e); + if (checkms === 0) { + e.preventDefault(); + } + } + } + //panel(drag_window) var x_window; var y_window; @@ -2334,4 +2368,4 @@ function clear_storage_all() { html: '