remove old placer, change Try Again to do repeated retry (avoids the generation time)

recursive
Ondřej Hruška 4 years ago
parent 98fc39027a
commit 4703ff81e7
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 164
      script.js

@ -739,11 +739,10 @@ class Board {
this.buttons.undo = addButton(x0, y0 + ysp*2, 'Undo', 'disabled');
this.buttons.working = addButton(x0, y0 + ysp*3, 'Working…', 'working');
const cfgy0 = 10;
const cfgy0 = 10.5;
this.buttons.optFancy = addButton(x0, cfgy0, 'Effects:', 'config');
this.buttons.optBlockedEffect = addButton(x0, cfgy0+ysp2, 'Dim Blocked:', 'config');
this.buttons.optSloppy = addButton(x0, cfgy0+ysp2*2, 'Sloppy Mode:', 'config');
this.buttons.toggleFullscreen = addButton(x0, cfgy0+ysp2*-1.5, 'Fullscreen', 'config');
this.buttons.btnAbout = addButton(x0, cfgy0+ysp2*-2.5, 'Help', 'config');
@ -761,7 +760,6 @@ class Board {
updateSettingsGUI(cfg) {
this.buttons.optFancy.textContent = 'Effects: '+(cfg.svgEffects ? 'On' : 'Off');
this.buttons.optBlockedEffect.textContent = 'Dim Blocked: '+(cfg.dimBlocked ? 'On' : 'Off');
this.buttons.optSloppy.textContent = 'Sloppy Mode: '+(cfg.allowTemplateAugmenting ? 'On' : 'Off');
}
}
@ -876,10 +874,8 @@ class SettingsStorage {
this.defaults = {
version: 1,
log: 'info',
allowTemplateAugmenting: false,
retryTemplate: 120,
retryTemplate: 70,
attemptTemplates: 20,
difficulty: 35,
svgEffects: false,
dimBlocked: true,
logSolution: false,
@ -1238,7 +1234,6 @@ class Game {
}
placeOrbs(template) {
// let placer = new RadialOrbPlacer(this, template);
let placer = new RecursiveOrbPlacer(this, template);
return placer.place();
}
@ -1431,7 +1426,9 @@ class Game {
installButtonHandlers() {
this.board.buttons.restart.addEventListener('click', () => {
this.info("New Game with the same seed");
this.newGameWithLoader(this.rng.seed);
while (this.undoStack.length) {
this.undo();
}
});
this.board.buttons.randomize.addEventListener('click', () => {
@ -1467,13 +1464,6 @@ class Game {
})
});
this.board.buttons.optSloppy.addEventListener('click', () => {
this.info("Toggle sloppy placement mode");
this.setCfg({
allowTemplateAugmenting: !this.cfg.allowTemplateAugmenting,
})
});
this.board.buttons.toggleFullscreen.addEventListener('click', () => {
this.info("Toggle Fullscreen");
if (document.fullscreenElement) {
@ -1833,150 +1823,6 @@ class BaseOrbPlacer {
}
}
/**
* Orb placement algorithm that starts in the center and places orbs in rings, with some
* small jitter allowed.
*/
class RadialOrbPlacer extends BaseOrbPlacer {
/**
* Find a candidate cell
*
* @param {number[]|null} except - indices to exclude
* @return {number}
*/
findBestCandidate(except = null) {
let candidates = [];
for (let n of this.template) {
if (except && except.includes(n)) continue;
if (!this.board.grid[n]) {
// is free
const neigh = this.getCellInfo(n);
if (neigh.freeSequence >= 3) {
candidates.push({
n,
cw: neigh.centerWeight
});
}
}
}
candidates.sort((a, b) => a.cw - b.cw);
if (candidates.length) {
// return candidates[0].n;
let top = [];
let topw = candidates[0].cw;
for(let cand of candidates) {
if (cand.cw <= topw + this.cfg.difficulty) { // TODO this could vary by template
top.push(cand);
}
}
//the neighbor count is not used for anything anymore, oops
// console.log('Got a choice of '+top.length+' tiles');
return this.rng.arrayChoose(top).n;
}
return false;
}
/**
* Find index for next placement
*
* @param {number[]|null} except - indices to exclude
* @return {number} - index
*/
findAvailableIndex(except = null) {
const n = this.findBestCandidate(except);
if (n !== false) return n;
// this corrupts the template, but makes the likelihood of quickly finding a valid solution much higher.
if (this.template.length !== BOARD_SIZE && this.cfg.allowTemplateAugmenting) {
// Prefer tile with more neighbours to make the game harder
let candidates = [];
this.outsideTemplate.forEach((n) => {
if (!this.templateMap[n] && this.isAvailable(n)) {
const neigh = this.getCellInfo(n);
if (!candidates[neigh.neighbours]) {
candidates[neigh.neighbours] = [n];
} else {
candidates[neigh.neighbours].push(n);
}
}
});
for (let i = 6; i >= 0; i--) {
if (!candidates[i]) continue;
let toAdd = this.rng.arrayChoose(candidates[i]);
this.templateMap[toAdd] = true;
this.outsideTemplate.splice(this.outsideTemplate.indexOf(toAdd), 1);
this.template.push(toAdd);
this.tilesAdded++;
this.warn(`Adding extra tile to template: ${toAdd}`);
return toAdd;
}
}
throw Error("Failed to find available board tile.");
}
doPlace(toPlace) {
this.tilesAdded = 0;
while (toPlace.length > 0) {
this.trace('placing a pair.');
let symbol1 = toPlace.pop();
let index1 = this.findAvailableIndex();
this.placeOrb(index1, symbol1);
this.solution.push([symbol1, index1]);
let symbol2 = toPlace.pop();
let index2 = this.findAvailableIndex();
this.placeOrb(index2, symbol2);
if (!this.isAvailable(index1)) {
this.debug(`Deadlock, trying to work around it - ${index1}, ${index2}`);
this.removeOrb(index2);
let except = [index2];
let suc = false;
for (let i = 0; i < 5; i++) {
this.trace(`try #${i + 1}`);
let index = this.findAvailableIndex(except);
this.placeOrb(index, symbol2);
if (this.isAvailable(index1)) {
suc = true;
index2 = index;
break;
} else {
this.removeOrb(index);
except.push(index);
}
}
if (!suc) {
throw new Error("Solution contains a deadlock.");
}
}
// index2 is updated in the fixing loop
this.solution.push([symbol2, index2]);
}
return {
tilesAdded: this.tilesAdded,
};
}
}
class RecursiveOrbPlacer extends BaseOrbPlacer {
doPlace(toPlace) {
this.toPlace = toPlace;

Loading…
Cancel
Save