Last active
November 23, 2023 11:49
-
-
Save killroy42/853ad633da50a61d8dcd23d27c3113c2 to your computer and use it in GitHub Desktop.
Prototype Hinting User Plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const generateHintFunc = (() => { | |
/*let board = Array.from({ length: 9 }, () => Array(9).fill(0)); | |
board[0][0] = 1; | |
board[2][2] = 2; | |
board[0][1] = 3; | |
board[1][0] = 4; | |
*/ | |
let board = [ | |
[0, 9, 0, 0, 0, 7, 0, 5, 0], | |
[0, 5, 0, 8, 0, 0, 0, 0, 0], | |
[1, 4, 0, 0, 5, 0, 2, 0, 0], | |
[7, 0, 4, 0, 9, 0, 0, 0, 0], | |
[3, 8, 1, 7, 0, 0, 5, 9, 6], | |
[5, 0, 9, 0, 8, 0, 7, 0, 4], | |
[0, 7, 5, 0, 3, 8, 0, 4, 1], | |
[0, 1, 0, 0, 0, 6, 0, 7, 0], | |
[0, 3, 0, 1, 7, 0, 0, 8, 0] ]; | |
/* | |
let board = [ | |
[0, 0, 0, 0, 1, 0, 8, 0, 6], | |
[8, 1, 0, 0, 0, 9, 4, 0, 0], | |
[9, 0, 6, 8, 3, 0, 5, 1, 0], | |
[0, 9, 8, 0, 0, 7, 1, 0, 3], | |
[0, 7, 1, 0, 0, 0, 6, 9, 0], | |
[6, 0, 0, 0, 9, 1, 0, 7, 8], | |
[0, 0, 3, 1, 5, 0, 0, 8, 0], | |
[0, 8, 9, 4, 0, 3, 0, 0, 0], | |
[0, 0, 0, 9, 0, 8, 0, 0, 0] | |
]; | |
*/ | |
// prints board to console, not used | |
function print_board(board){ | |
for(let i=0;i<9;i++){ | |
console.log(board[i].toString()); | |
} | |
} | |
// not used | |
function check_board(board){ | |
/* possible return values and meaning | |
1 = coluding numbers(same row, col, box) | |
2 = invalid inpit(outside range) | |
*/ | |
// check cols and rows | |
for(let i=0;i<9;i++){ | |
let row = new Set(); | |
let col = new Set(); | |
for(let j=0;j<9;j++){ | |
if(row.has(board[i][j]) || col.has(board[j][i])){ | |
return false; | |
} | |
if(board[i][j]>9 || board[i][j]<0){ | |
return false; | |
} | |
if(board[i][j]){ | |
row.add(board[i][j]); | |
} | |
if(board[j][i]){ | |
col.add(board[j][i]); | |
} | |
} | |
} | |
// box check | |
for (let i = 0; i < 3; i++) { | |
for (let j = 0; j < 3; j++) { | |
const box = new Set(); | |
for (let bRow = 3 * i; bRow < (3 * i + 3); bRow++) { | |
for (let bCol = 3 * j; bCol < (3 * j + 3); bCol++) { | |
const boxVal = board[bRow][bCol]; | |
if (boxVal && box.has(boxVal)) { | |
return false; | |
} | |
box.add(boxVal); | |
} | |
} | |
} | |
} | |
return true; | |
} | |
// this function checks whether a move is valid by checking if the board is still valid after a move | |
function check_after(board, i,j,num){ | |
for(let k=0;k<9;k++){ | |
if(board[i][k]===num || board[k][j]===num){ | |
return false; | |
} | |
} | |
for(let x=3*Math.floor(i/3);x<(3*Math.floor(i/3))+3;x++){ | |
for(let y=3*Math.floor(j/3);y<(3*Math.floor(j/3))+3;y++){ | |
if(board[x][y]==num){ | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
// solves the puzzle using backtacking, not really used | |
function solver1(board){ | |
// find open cell | |
let i=-1; | |
let j=-1; | |
for(let x=0;x<9;x++){ | |
for(let y=0;y<9;y++){ | |
if(!board[x][y]){ | |
i = x; | |
j = y; | |
break; | |
} | |
} | |
if(i>-1){ | |
break; | |
} | |
} | |
// finsihed game | |
if(i<0){ | |
//print_board(board); | |
return board; | |
} | |
// try all numbers | |
for(let num=1;num<10;num++){ | |
if(check_after(board,i,j,num)){ | |
board[i][j] = num; | |
if(solver1(board)){ | |
return board;// or return true | |
} | |
board[i][j]=0; | |
} | |
} | |
return false; | |
} | |
// fills random cell with correct value from solved board (could be used as a type of hint?) | |
function hint1(board, clarity){ | |
let empty_cells = Array(); | |
for(let i=0;i<9;i++){ | |
for(let j=0;j<9;j++){ | |
if(board[i][j]==0){ | |
empty_cells.push((9*i)+j); | |
} | |
} | |
} | |
// cell to be selected | |
let cell = empty_cells[Math.random()%empty_cells.length] | |
let x = Math.floor(cell/9); | |
let y = cell%9; | |
board[x][y] = solver1[board][x][y]; | |
console.log("row",x,"column ",y,"is ", board[x][y]); | |
} | |
// returns possible valid moves for every cell in a map | |
function possible_values4cell(board){ | |
let possible_vals = new Map(); // maps i(cell unit number) to set of possible values | |
for(let i=0;i<9;i++){ | |
for(let j=0;j<9;j++){ | |
if(board[i][j]==0){ | |
for(let k=1;k<10;k++){ | |
if(check_after(board,i,j,k)){ | |
if(!(possible_vals.has(9*i+j))){ | |
possible_vals.set(9*i+j, new Set()); | |
} | |
// add k to list of possibilities | |
const present = possible_vals.get(9*i+j); | |
present.add(k); | |
possible_vals.set(9*i+j, present); | |
} | |
} | |
}/*else{ | |
possible_vals.set(9*i+j, [board[i][j]]) | |
}*/ | |
} | |
} | |
return possible_vals; | |
} | |
// finds hidden singles | |
function h_singles(board){ | |
/* | |
cell i,j can only be one value | |
*/ | |
let hidden_singles = new Map(); // ij number representing single location : single value in cell location | |
for(let i=0;i<9;i++){ | |
for(let j=0;j<9;j++){ | |
if(possible_values4cell(board).get(9*i+j) && possible_values4cell(board).get(9*i+j).size==1){ | |
let single_value = Array.from(possible_values4cell(board).get(9*i+j))[0]; | |
hidden_singles.set(9*i+j, single_value); | |
} | |
} | |
} | |
return hidden_singles; | |
} | |
// this function is used in finding naked pairs/triples and quad | |
// it finds the frequency of each possibitity in a given row, column or box(rcb) | |
// example if row 3: has two cells with freq {2,3} occuring twice then there is a chance we have a naked pair in this row | |
function possibilities_freq4rcb(board, rcb, rcb_num){// rcb=row(0)/col(1)/box(2), rcb_num is 0 indexed | |
let temp, x, y, i, j; | |
let rcb_freq = new Map(); | |
let each_number_freq = new Map();// stores the occurence of each number in every possiblity inthat rcb/rowcolorbox | |
let possible_vals = possible_values4cell(board); | |
// row freq | |
if(rcb==0){ | |
for(let j=0;j<9;j++){ | |
if(possible_vals.get(9*rcb_num+j)){ | |
let arr0 = Array.from(possible_vals.get(9*rcb_num+j)); | |
arr0.sort(); | |
let pNum = 0; // convert possibilities to unique number | |
if(arr0.length==2){ | |
for(let k=0;k<2;k++){ | |
pNum += arr0[k]*Math.pow(10, 1-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(arr0.length==3){ | |
for(let k=0;k<3;k++){ | |
pNum += arr0[k]*Math.pow(10, 2-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(!rcb_freq || !rcb_freq.has(pNum)){ | |
rcb_freq.set(pNum, 0); | |
} | |
temp = rcb_freq.get(pNum); | |
temp+=1 | |
rcb_freq.set(pNum, temp); | |
} | |
} | |
if(rcb_freq.has(0)){ | |
rcb_freq.delete(0); | |
} | |
} | |
// column frequency | |
if(rcb==1){ | |
for(let i=0;i<9;i++){ | |
if(possible_vals.get(9*i+rcb_num)){ | |
let arr0 = Array.from(possible_vals.get(9*i+rcb_num)); | |
arr0.sort(); | |
let pNum = 0; // convert possibilities to unique number | |
if(arr0.length==2){ | |
for(let k=0;k<2;k++){ | |
pNum += arr0[k]*Math.pow(10, 1-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(arr0.length==3){ | |
for(let k=0;k<3;k++){ | |
pNum += arr0[k]*Math.pow(10, 2-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(!rcb_freq || !rcb_freq.has(pNum)){ | |
rcb_freq.set(pNum, 0); | |
} | |
temp = rcb_freq.get(pNum); | |
temp+=1 | |
rcb_freq.set(pNum, temp); | |
} | |
} | |
if(rcb_freq.has(0)){ | |
rcb_freq.delete(0); | |
} | |
} | |
// box freq | |
if(rcb==2){ | |
i = x = 3*Math.floor(rcb_num/3); | |
j = y = 3*(rcb_num%3); | |
for(;i<x+3;i++){ | |
for(;j<y+3;j++){ | |
if(possible_vals.get(9*i+j)){ | |
let arr0 = Array.from(possible_vals.get(9*i+j)); | |
arr0.sort(); | |
let pNum = 0; // convert possibilities to unique number | |
if(arr0.length==2){ | |
for(let k=0;k<2;k++){ | |
pNum += arr0[k]*Math.pow(10, 1-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(arr0.length==3){ | |
for(let k=0;k<3;k++){ | |
pNum += arr0[k]*Math.pow(10, 2-k); | |
if(!each_number_freq || !each_number_freq.has(arr0[k])){ | |
each_number_freq.set(arr0[k], 0); | |
} | |
temp = each_number_freq.get(arr0[k]); | |
temp+=1 | |
each_number_freq.set(arr0[k], temp); | |
} | |
} | |
if(!rcb_freq || !rcb_freq.has(pNum)){ | |
rcb_freq.set(pNum, 0); | |
} | |
temp = rcb_freq.get(pNum); | |
temp+=1 | |
rcb_freq.set(pNum, temp); | |
} | |
} | |
j = y; | |
} | |
if(rcb_freq.has(0)){ | |
rcb_freq.delete(0); | |
} | |
} | |
let ret = { | |
rcb_frequency :rcb_freq, | |
each_number_frequency : each_number_freq | |
} | |
return ret; | |
} | |
// using function possibilities_freq4rcb we now find naked pairs or triples | |
function naked_pairs_triples(board){ | |
let naked_pairs = new Map();// type|type_num : ij, eg 04 : 23 means a naked pair at row 4 involving numbers 2 and 3 | |
let naked_triples = new Map();// type|type_num : ij, eg 24 : 235 means a naked triple at row 4 involving numbers 2, 3 and 5 | |
for(let type=0;type<3;type++){//0=row,1==col,2===box | |
for(let i=0;i<9;i++){ | |
if(possibilities_freq4rcb(board, type, i)){ | |
for(const val of possibilities_freq4rcb(board, type, i).rcb_frequency){ | |
let each_number__freq = possibilities_freq4rcb(board, type, i).each_number_frequency; | |
let p_num = val[0]; | |
let freq = val[1]; | |
if(p_num%100==p_num && freq==2){ | |
let num1 = Math.floor(p_num/10); | |
let num2 = p_num%10; | |
if(!each_number__freq.get(num1)==freq || !each_number__freq.get(num2)==freq){ | |
continue; | |
} | |
let num3 = type*10 + i | |
naked_pairs.set(num3, p_num); | |
} | |
if(p_num%1000==p_num && p_num>99 && freq==3){ | |
let num1 = Math.floor(p_num/100) | |
let num2 = Math.floor(p_num/10); | |
let num3 = p_num%10; | |
if(!each_number__freq.get(num1)==freq || !each_number__freq.get(num2)==freq || !each_number__freq.get(num3)==freq){ | |
continue; | |
} | |
let num4 = type*10 + i | |
naked_triples.set(num4, p_num); | |
} | |
} | |
} | |
} | |
} | |
let result = { | |
naked__pairs : naked_pairs, | |
naked__triples : naked_triples | |
} | |
return result; | |
} | |
// returns => number(1 to 9) : [row_where_its_possible*10+col_where_its_possible(note this are numbers),..., number_of_rows_it_occurs, num_of_cols_it_occurs] | |
// this function is used in finding pointing pairs and triples as it provides necessary data in finding them | |
function box_element_mapping(board, box_num){ | |
let x, y, i, j; | |
let box_info = {// note this mapping is only for UNKNOWN elements in the box, | |
element_mapping : new Map(), | |
row_count : new Map(),// contains number : set of the distint rows num is a possibliltiy of in box box_num | |
col_count : new Map(), | |
// possible elements in each row of the 3x3 in the 9x9 in order except the ones in the box | |
// 3 rows 3 cols(6 sets total) left->right, top->bottom | |
row_col_elements : new Map(), | |
boxes_pointing_pairs : new Map()// box : numbers involved in the pointing paircontains the possiblities of each cell in the box.e.g 42 | |
} | |
i = x = 3*Math.floor(box_num/3); | |
j = y = 3*(box_num%3); | |
let r = 0; | |
let possibilities_freq = new Map();// stores frequency of each possiblity | |
let total_possibilties = new Array(0);// all possiblities for box in one | |
let restrict = 0 // check frequencies just once | |
for(let num=1;num<10;num++){ | |
box_info.element_mapping.set(num, new Array(0)); | |
box_info.row_count.set(num, new Set()); | |
box_info.col_count.set(num, new Set()); | |
for(;i<x+3;i++){ | |
for(;j<y+3;(r++,j++)){ | |
//console.log("i",i,"j",j); | |
//console.log("i*3+j", i*9+j) | |
//check if duplicate cell possibilies is already in box | |
if(possible_values4cell(board).get(9*i+j) && restrict==0){ | |
total_possibilties = [...total_possibilties, ...possible_values4cell(board).get(9*i+j)]; | |
} | |
if(possible_values4cell(board).get(9*i+j) && possible_values4cell(board).get(9*i+j).size==2 && restrict==0 ){ | |
arr0 = [...possible_values4cell(board).get(9*i+j)]; | |
Max = Math.max(...arr0); | |
Min = Math.min(...arr0); | |
if(possibilities_freq.has(Max*10+Min)){ | |
let temp = possibilities_freq.get(Max*10+Min); | |
temp[0]+=1; | |
temp[1].add(i*10+j); | |
possibilities_freq.set(Max*10+Min, temp); | |
}else{ | |
possibilities_freq.set(Max*10+Min, [1, new Set([i*10+j])]);// store {2,3} as 32(key in possiblities_freq) : [frequency, ij(as i*10+j)] | |
} | |
} | |
// space | |
let check = possible_values4cell(board).get(9*i+j); | |
if(check && check.has(num)){ | |
// update element mapping | |
let temp = box_info.element_mapping.get(num); | |
temp.push(i*10+j); | |
box_info.element_mapping.set(num,temp); | |
// update row count | |
temp = box_info.row_count.get(num) | |
temp.add(i) | |
box_info.row_count.set(num, temp); | |
// update col count | |
temp = box_info.col_count.get(num) | |
temp.add(j) | |
box_info.col_count.set(num, temp); | |
} | |
// now that we have info on box, we need to find the other elements in same row/col in search of pointing pair | |
if(r<3){ | |
box_info.row_col_elements.set(r, new Set()); | |
for(let m = 0;m<9;m++){ | |
if(!(m>=y && m<y+3) && possible_values4cell(board).get(9*(x+r)+m)){ | |
for(let n of possible_values4cell(board).get(9*(x+r)+m)){ | |
let temp = box_info.row_col_elements.get(r); | |
temp.add(n); | |
box_info.row_col_elements.set(r, temp); | |
} | |
} | |
} | |
}else if(r>=3 && r<6){ | |
box_info.row_col_elements.set(r, new Set()); | |
for(let m = 0;m<9;m++){ | |
if(!(m>=x && m<x+3) && possible_values4cell(board).get(9*m+y+r%3)){ | |
for(let n of possible_values4cell(board).get(9*m+y+r%3)){ | |
let temp = box_info.row_col_elements.get(r); | |
temp.add(n); | |
box_info.row_col_elements.set(r, temp); | |
} | |
} | |
} | |
} | |
} | |
j = y = 3*(box_num%3); | |
} | |
restrict = 1; | |
i = x = 3*Math.floor(box_num/3); | |
j = y = 3*(box_num%3); | |
} | |
const total_possibilties_frequency = total_possibilties.reduce((acc, curr) => { | |
acc[curr] = (acc[curr] || 0) + 1; | |
return acc; | |
}, {}); | |
for(element of possibilities_freq.entries()){ | |
let duo = element[1]; | |
let same_row = new Set(); | |
let same_col = new Set(); | |
if(duo==undefined){ | |
continue; | |
} | |
for(position of duo[1]){ | |
same_row.add(Math.floor(position/10)); | |
same_col.add(position%10); | |
} | |
if(same_row.size==1){ | |
let x = Array.from(same_row)[0]; | |
let lonely_check=0;// check if dual is the only one in row | |
// check if other row spots are filled | |
for(let j=0;j<9;j++){ | |
if(board[x][j]==0){ | |
lonely_check+=1; | |
} | |
} | |
if(lonely_check==2 && (total_possibilties_frequency[Math.floor(element[0]/10)]>duo[0] || total_possibilties_frequency[element[0]%10]>duo[0])){ | |
if(box_info.boxes_pointing_pairs.has(box_num)){ | |
let temp = box_info.boxes_pointing_pairs.get(box_num); | |
temp.push(element); | |
box_info.boxes_pointing_pairs.set(box_num, temp); // store in box_number : array with eah duo pair present | |
}else{ | |
box_info.boxes_pointing_pairs.set(box_num, [element[0]]); | |
} | |
} | |
} | |
if(same_col.size==1){ | |
let y = Array.from(same_col)[0]; | |
let lonely_check=0;// check if dual is the only one in row | |
// check if other row spots are filled | |
for(let i=0;i<9;i++){ | |
if(board[i][y]==0){ | |
lonely_check+=1; | |
} | |
} | |
if(lonely_check==2 && (total_possibilties_frequency[Math.floor(element[0]/10)]>duo[0] || total_possibilties_frequency[element[0]%10]>duo[0])){ | |
if(box_info.boxes_pointing_pairs.has(box_num)){ | |
let temp = box_info.boxes_pointing_pairs.get(box_num); | |
temp.push(element); | |
box_info.boxes_pointing_pairs.set(box_num, temp); // store in box_number : array with eah duo pair present | |
}else{ | |
box_info.boxes_pointing_pairs.set(box_num, [element[0]]); | |
} | |
} | |
} | |
} | |
//console.log("possiblities-freq", possibilities_freq); | |
return box_info; | |
} | |
// using function box_element_mapping, this function finds pointing pairs and triples | |
function pointing_pairs(board){ | |
let x, y, i, j; | |
/* | |
let ppairs = { | |
ppair_rows : new Map(), // stores number : row with pointing pair/triple of number | |
ppair_cols : new Map(), | |
boxes_pointing_pairs_triples : new Map() // box num: pair | |
}*/ | |
let ppairs = new Map(); | |
for(let box=0;box<9;box++){ | |
i = x = 3*Math.floor(box/3); | |
j = y = 3*(box%3); | |
for(let num=1;num<10;num++){ | |
let num_info = box_element_mapping(board, box); | |
let arr1 = [...num_info.row_count.get(num)];// stores row containing point pair | |
let arr2 = [...num_info.col_count.get(num)];// stores col containing pointing pair | |
// check row for pointing pair | |
if(num_info.row_count.get(num).size==1 && num_info.row_col_elements.get((arr1[0]-x)%3)){ | |
if(num_info.row_col_elements.get((arr1[0]-x)%3).has(num)){// found a row pointing pair/triple | |
ppairs.set(arr1[0], num) | |
} | |
} | |
// check col for pointing pair | |
if(num_info.col_count.get(num).size==1 && num_info.row_col_elements.get(3+(arr2[0]-y)%3)){// found a col pointing pair/triple | |
if(num_info.row_col_elements.get(3+(arr2[0]-y)%3).has(num)){ | |
arr2[0] = 10+arr2[0]; | |
ppairs.set(arr2[0], num) | |
} | |
} | |
// check box for pointing pair | |
if(num_info.boxes_pointing_pairs.get(box)){ | |
ppairs.set(20+box, num_info.boxes_pointing_pairs.get(box)); | |
} | |
} | |
} | |
return ppairs; | |
} | |
// this function calls all previous hint functions and organizes them into an object for sorting | |
function generate_hints(board){ | |
/*=> Hidden singles: Map of ij(cell number) row-col values to the correct value for the cell | |
=> naked pairs/triples: Map of ijkl(i=0 means if row, i=1 means col,i=2 means box i is row/col/box number(0 indexed), j is the corresponding number of i(e.g jth row) | |
the k and l are the location row/col for the pair in ith row/col) row-col values to the list of correct values for the cell | |
if i is a box, then k-l represent the nth element of the box e.g kl=56 means the 5th and 6th elements for the box | |
example ijkl = 0106 means there is naked pair at row 1 at columns 0 and 6 | |
=> for pointing pairs, we map ijkl to a set of the point, i=0 means row i=1 means col,i=2 means box | |
j is the corresponding number of i(e.g jth row) | |
the k and l are the location row/col for the pair in ith row/col that have pointing pairs | |
same goes for the triples | |
*/ | |
let all_hint_info = { | |
// hint levels are base on Simplicity from 1 to 3 | |
hidden_singles : h_singles(board), | |
naked_pairs : naked_pairs_triples(board).naked__pairs, | |
naked_triple : naked_pairs_triples(board).naked__triples, | |
pointing_pairs : pointing_pairs(board), | |
Intersection_removal : new Map(), | |
X_wing : new Map() | |
} | |
return all_hint_info | |
} | |
// using the generate_hints function, this function sorts the hints based on certain criteria | |
function sort_hints(board){ | |
// hint levels are base on Simplicity from 1 to 3 | |
let all_hint_info = generate_hints(board); | |
let level_1_hint = { | |
hidden_singles : all_hint_info.hidden_singles, // Map of ij(cell number) row-col values to the correct value for the cell | |
naked_pairs : all_hint_info.naked_pairs, // Map of ijkl(i=0 means if row, i=1 means col,i=2 means box i is row/col/box number(0 indexed), j is the corresponding number of i(e.g jth row) | |
// the k and l are the location row/col for the pair in ith row/col) row-col values to the list of correct values for the cell | |
// if i is a box, then k-l represent the nth element of the box e.g kl=56 means the 5th and 6th elements for the box | |
// for example ijkl = 0106 means there is naked pair at row 1 at columns 0 and 6 | |
naked_triples : all_hint_info.naked_triple, // Same concept as naked pairs but with 3 values hence 21067, means triple at box 1 in the 0th, 6th and 7th digits of the box | |
naked_quads : new Map() // Same concept as triple pairs but wit 4 vals | |
} | |
let level_2_hint = { | |
// for pointing pairs, we map ijkl to a set of the point, i=0 means row i=1 means col,i=2 means box | |
// j is the corresponding number of i(e.g jth row) | |
// the k and l are the location row/col for the pair in ith row/col that have pointing pairs | |
// same goes for the triples | |
pointing_pairs : all_hint_info.pointing_pairs, | |
pointing_triples : new Map(), | |
} | |
let level_3_hint = { | |
Intersection_removal : new Map(), | |
X_wing : new Map() | |
} | |
let result = { | |
hint_type : "", | |
hint_location : "", // row/col/box | |
hint_location_number : 0 | |
} | |
// | |
let location = ["row", "column", "box"] | |
if(level_1_hint.naked_triples.size!=0){ | |
//if(level_1_hint.naked_pairs.size!=0){ | |
result.hint_type = "naked triple"; | |
//let num = Array.from(level_1_hint.naked_pairs)[0][0]; | |
let num = Array.from(level_1_hint.naked_triples)[0][0]; | |
let num1 = Math.floor(num/10); | |
result.hint_location = location[num1]; | |
result.hint_location_number = num%10 + 1; | |
}else if(level_1_hint.naked_pairs.size!=0){ | |
result.hint_type = "naked pair"; | |
let num = Array.from(level_1_hint.naked_pairs)[0][0]; | |
let num1 = Math.floor(num/10); | |
result.hint_location = location[num1]; | |
result.hint_location_number = num%10 + 1; | |
}else if(level_1_hint.hidden_singles.size!=0){ | |
result.hint_type = "hidden single"; | |
result.hint_location = "column"; | |
let num = Array.from(level_1_hint.hidden_singles)[0][0]; | |
let num1 = Math.floor(num/10); | |
result.hint_location_number = num%10 + 1; | |
}else if(level_2_hint.pointing_pairs.size!=0){ | |
result.hint_type = "pointing pair"; | |
let num = Array.from(level_1_hint.naked_pairs)[0][0]; | |
let num1 = Math.floor(num/10); | |
result.hint_location = location[num1]; | |
result.hint_location_number = num%10; | |
}else{ | |
//console.log("no hint"); | |
} | |
//console.log("sort_hints > level_1_hint", level_1_hint); | |
//console.log("sort_hints > level_2_hint", level_2_hint); | |
//console.log("sort_hints > level_3_hint", level_3_hint); | |
return Object.assign(result, {level_1_hint, level_2_hint, level_3_hint}); | |
} | |
// converts hint data to a basic sentence | |
function hint_to_word(result){ | |
console.log("There is a ", result.hint_type, " in the ", result.hint_location_number, "th ", result.hint_location ) | |
} | |
function hintToString() { | |
const {hint_type, hint_location, hint_location_number} = this; | |
return `There is a ${hint_type} in ${hint_location} ${hint_location_number}`; | |
}; | |
const p81ToBoard = p81 => p81.replace(/[^0-9]/g, '0').match(/.{9}/g).map(r=>r.split('').map(d=>parseInt(d))); | |
function getHint(p81) { | |
let board = p81ToBoard(p81); | |
let hint = sort_hints(board); | |
hint.toString = hintToString; | |
return hint | |
} | |
return getHint; | |
}); | |
Framework.features.userplugins.addPlugin( | |
'HintSystemPT01', | |
`{ | |
settingName: 'HintSystemPT01', | |
handleInfoClick: function (event) { | |
document.querySelector('.info-overlay').dispatchEvent(new Event('click')); | |
let hint = this.generateHint(Framework.app.toP81()); | |
console.log('hint:', hint.toString(), hint); | |
Framework.showAlert(hint.toString()); | |
}, | |
handleSettingChange: function() { | |
const setting = Framework.getSetting(this.settingName); | |
if(setting !== this.enabled) { | |
this.enabled = setting; | |
if(this.enabled) { | |
Framework.app.on('control-info', this.handleInfoClick); | |
} | |
else { | |
Framework.app.off('control-info', this.handleInfoClick); | |
} | |
} | |
}, | |
handleInit: function() { | |
this.enabled = false; | |
this.generateHint = (${generateHintFunc})(); | |
Framework.addSetting({ | |
group: 'experimental', name: this.settingName, content: 'Hints', | |
tag: 'toggle', | |
init: this.handleSettingChange, onToggle: this.handleSettingChange, | |
}); | |
}, | |
}`, | |
{overwrite: true} | |
); | |
// Paste into console to add as user plugin. Setting in "Advanced" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment