JSFiddle - React, Tailwind, and code Playground

by Rolf

HTML

<label>
  Schreibe Checkpoints bis Stufe<br>
  <input type="number" id="traceTo" value="12">
</label>
<label>
  Beende Test nach Durchlauf von Stufe<br>
  <input type="number" id="clipLevel" value="12">
</label>
<label>
  Begrenze Laufzeit auf<br>
  <input type="number" id="maxRuntime" value="10"> Sekunden
</label>
<label>
  Diagonalen prüfen <input type="checkbox" id="checkDiagonal">
</label>
<br>
<button type="button" onclick="runTest()">Run</button>

CSS

label {
  display: block;
  margin-bottom: 0.5em;
}

JavaScript

function runTest() {
  // Kalender mit Dummyzellen einrahmen um Abfragen auf Randpositionen zu vermeiden
  // Kalender linear statt als 2D Array für Performance
  let field = [
  	-2, -2, -2, -2, -2, -2, -2, -2,   // y=0
    -2, -1, -1, -1, -1, -1, -1, -2,   // y=8
    -2, -1, -1, -1, -1, -1, -1, -2,   // y=16
    -2, -1, -1, -1, -1, -1, -1, -2,   // y=24
    -2, -1, -1, -1, -1, -1, -1, -2,   // y=32
    -2, -2, -2, -2, -2, -2, -2, -2    // y=40
  ];
  
  console.clear();
  
  const groupingFormat = new Intl.NumberFormat("de-DE", { useGrouping: true});

  const traceTo = document.getElementById("traceTo").valueAsNumber;
  const clipLevel = document.getElementById("clipLevel").valueAsNumber;
  const maxRuntime = document.getElementById("maxRuntime").valueAsNumber;
  const checkDiagonal = document.getElementById("checkDiagonal").checked;
  const begin = Date.now();
  
  let solCount = 0;      // Anzahl gefundener Platzierungen
  let result = tryNumber(1);

  console.log(`found ${groupingFormat.format(solCount)} possibilities, ${result ? "" : "aborted"}`);

  function tryNumber(num) {
    if (num <= traceTo)
      console.log(`try number ${num} (solCount=${groupingFormat.format(solCount)}`);
   
    let x, y, xBase, xMax, pred = num-1;

    // Schleifensteuerung so, dass der Kalender als lineares Array gespeichert werden kann
    for ( y = 1; y < 5; y ++) {
      xBase = y*8;
      xMax = xBase + 7;
      for ( x = xBase + 1; x < xMax; x++) {
        // Feld schon besetzt
        if (field[x] > 0) continue;
        // Ist der Vorgänger in der Nachbarschaft?
        // Links oder rechts
        if (pred == field[x-1] || pred == field[x+1]) continue;
        // Senkrecht darüber oder darunter
        //if (y > 1) {
          if (pred == field[x-8] || checkDiagonal && (pred == field[x-9] || pred == field[x-7])) continue;
        //}
        //if (y < 4) {
          if (pred == field[x+8] || checkDiagonal && (pred == field[x+7] || pred == field[x+9])) continue;
       ...