{
  "information": {
    "Title": "Knight's Move Game for 1 PLayer Strategy Game to maximise number of moves",
    "Author": [
      "Shaun Quek",
      "Loo Kang Wee",
      "based on idea by Theresa Heng",
      "Francisco Esquembre",
      "F\u00e9lix Jes\u00fas Garcia Clemente"
    ],
    "AuthorLogo": [
      "",
      "",
      "",
      "",
      ""
    ],
    "Password": "",
    "Keywords": "",
    "Abstract": "",
    "Copyright": "",
    "Level": "",
    "Language": "",
    "Logo": [
      "./knight_intro/Screenshot 2021-05-27 at 10.31.22 AM.png"
    ],
    "RunAlways": "true",
    "ModelTab": "",
    "ModelTabTitle": "",
    "ModelName": "",
    "FixedNavigationBar": "false",
    "CSSFile": "",
    "DetectedFiles": [
      "./knight_intro/Screenshot 2021-05-27 at 10.31.22 AM.png"
    ],
    "AuxiliaryFiles": [
      "./knight_intro/"
    ],
    "HTMLHead": "<script async=\"true\" src=\"https://www.googletagmanager.com/gtag/js?id=UA-3326007-19\"></script>\n<script>\n  window.dataLayer = window.dataLayer || [];\n  function gtag(){dataLayer.push(arguments);}\n  gtag('js', new Date());\n  gtag('config', 'UA-3326007-19');\n</script>\n<script data-ad-client=\"ca-pub-0121577198857509\" async=\"true\" src=\"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js\"></script>\n",
    "SaveInXMLFormat": "false",
    "IncludeSource": "true",
    "IncludeLibrary": "true",
    "UglifyJS": "false",
    "PreviewFullModel": "false",
    "UseInterpreter": "true",
    "UseDeltaForODE": "false"
  },
  "description": {
    "pages": []
  },
  "model": {
    "variables": {
      "pages": [
        {
          "Name": "Var Table",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "numOfRows",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "5",
              "Domain": "public"
            },
            {
              "Name": "numOfCols",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "5",
              "Domain": "public"
            },
            {
              "Name": "numOfSquares",
              "Value": "0",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareX",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareY",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareColor",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareHighlighted",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareFilled",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "squareLength",
              "Value": "1",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "idxToPos",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "posToIdx",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "textStr",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "textX",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "textY",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "moveCounter",
              "Value": "1",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "interact",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "gameOver",
              "Value": "false",
              "Type": "boolean",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "font",
              "Value": "\"normal normal 2vw\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            }
          ]
        },
        {
          "Name": "Var Table 2",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "filledColor",
              "Value": "\"rgba(0,255,0,0.5)\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "\"#bdbdbd\"",
              "Domain": "public"
            },
            {
              "Name": "unfilledColor",
              "Value": "\"rgba(255,200,0,0.5)\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "\"#e0e0e0\"",
              "Domain": "public"
            },
            {
              "Name": "highlightColor",
              "Value": "\"#aed581\"",
              "Type": "String",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            }
          ]
        },
        {
          "Name": "lookang",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "",
          "Variables": [
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "textXunicode",
              "Value": "-1",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "textYunicode",
              "Value": "0",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "storehighscore",
              "Value": "",
              "Type": "double",
              "Dimension": "[3]",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "storecomboxboxvalue",
              "Value": "",
              "Type": "double",
              "Dimension": "[3]",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "storehighscore1",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "storehighscore2",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "storehighscore3",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "null",
              "Domain": "public"
            }
          ]
        },
        {
          "Name": "AutoSolver",
          "Active": "true",
          "Internal": "false",
          "Type": "VARIABLE_EDITOR",
          "PageComment": "Variables for auto-solve animation at human speed",
          "Variables": [
            {
              "Name": "autoSolve",
              "Value": "false",
              "Type": "boolean",
              "Dimension": "",
              "Comment": "Toggle to run the solver and animate moves",
              "Domain": "public"
            },
            {
              "Name": "humanDelay",
              "Value": "800",
              "Type": "double",
              "Dimension": "",
              "Comment": "Delay between auto moves in milliseconds",
              "Domain": "public"
            },
            {
              "Name": "autoTimerId",
              "Value": "-1",
              "Type": "double",
              "Dimension": "",
              "Comment": "Holds the timeout id used for animation",
              "Domain": "public"
            },
            {
              "Name": "solutionPath",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "Stores the sequence of indices for the solution path",
              "Domain": "public"
            },
            {
              "Name": "solutionStep",
              "Value": "0",
              "Type": "double",
              "Dimension": "",
              "Comment": "Index into solutionPath",
              "Domain": "public"
            },
            {
              "Name": "lastIdx",
              "Value": "-1",
              "Type": "double",
              "Dimension": "",
              "Comment": "Index of the last clicked square",
              "Domain": "public"
            },
            {
              "Name": "solving",
              "Value": "false",
              "Type": "boolean",
              "Dimension": "",
              "Comment": "Internal flag while animating",
              "Domain": "public"
            },
            {
              "Name": "showAutoSolve",
              "Value": "false",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            },
            {
              "Name": "",
              "Value": "",
              "Type": "double",
              "Dimension": "",
              "Comment": "",
              "Domain": ""
            }
          ]
        }
      ]
    },
    "initialization": {
      "pages": [
        {
          "Name": "undefined",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// nice trick to \"store or remember values\"\n\nif (numOfRows==undefined){\n  numOfRows=3;\n}\n\nif (numOfCols==undefined){\n  numOfCols=3;\n}\n\nif (storehighscore[1]==undefined){ storehighscore[1]=0 }\nif (storehighscore[2]==undefined){ storehighscore[2]=0 }\nif (storehighscore[3]==undefined){ storehighscore[3]=0 }\n\nif (storehighscore1==undefined){ storehighscore1=0; }\nif (storehighscore2==undefined){ storehighscore2=0; }\nif (storehighscore3==undefined){ storehighscore3=0; }\n"
        },
        {
          "Name": "Init Page",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// INITIALISATION\ntextStr = [], textX = [], textY = [];\n\nsquareX = [], squareY = [], squareColor = [], squareHighlighted = [], squareFilled = [];\nidxToPos = [], posToIdx = [];\nnumOfSquares = 0;\nfor(var i = 0; i < numOfRows; i++) {\n  posToIdx.push([]);\n  for(var j = 0; j < numOfCols; j++) {\n    squareX.push(squareLength * j);\n    squareY.push(squareLength * i);\n\n    squareHighlighted.push(0);\n    squareFilled.push(0);\n    squareColor.push(unfilledColor);\n\n    idxToPos.push([j, i]);\n    posToIdx[i].push(numOfSquares++);\n  }\n}\n\n_tools.showOkDialog(\"Click any square to begin!\");\n"
        },
        {
          "Name": "Init Page 2",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "if (_isMobile){\n  //do nothing\n}\nelse{\n  // copy this into the initialization\n  // make the font bigger\n  _view.plottingPanel.getMessageDecoration(\"TL\").getFont().setFontSize(\"2vw\");\n  _view.plottingPanel.getMessageDecoration(\"TR\").getFont().setFontSize(\"2vw\");\n  _view.plottingPanel.getMessageDecoration(\"BL\").getFont().setFontSize(\"2vw\");\n  _view.plottingPanel.getMessageDecoration(\"BR\").getFont().setFontSize(\"2vw\");\n  //_view.plottingPanel.getMessageDecoration(\"TL\").getStyle().setFillColor(\"red\");\n}\n"
        },
        {
          "Name": "AutoSolve Init",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// Auto-solver defaults and cleanup\nsolving = false;\nsolutionPath = [];\nsolutionStep = 0;\nlastIdx = -1;\nif (humanDelay === undefined || humanDelay <= 0) humanDelay = 800;\n// clear any pending timer (if resetting)\nif (autoTimerId && autoTimerId !== -1) {\n  try { clearTimeout(autoTimerId); } catch(e){}\n}\nautoTimerId = -1;\n// If autoSolve is true, start after board (re)initialization\nif (autoSolve) {\n  startAutoSolve();\n}\n"
        },
        {
          "Name": "Keyboard Shortcuts",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "Reveal Auto-solve checkbox with ESC",
          "Code": "// Reveal the Auto-solve checkbox when pressing ESC\nif (typeof window !== 'undefined') {\n  if (!window.__autoSolveRevealBound) {\n    window.addEventListener('keydown', function(ev){\n      var k = ev.key || ev.keyCode;\n      if (k === 'Escape' || k === 'Esc' || k === 27) {\n        try { _view.autoSolveCheckbox.setProperty(\"Display\", \"inline-block\"); } catch(e){}\n      }\n    });\n    window.__autoSolveRevealBound = true;\n  }\n}\n"
        }
      ]
    },
    "evolution": {
      "information": {
        "FPS": "20",
        "SPD": "1",
        "RealTimeVariable": "",
        "Autoplay": "true"
      },
      "pages": []
    },
    "fixed_relations": {
      "pages": [
        {
          "Name": "FixRel Page 1",
          "Active": "true",
          "Internal": "false",
          "Type": "undefined",
          "Comment": "",
          "Code": "// FixRel Page 1\n//Variable\n//escKeyPressed = boolean to control certain thing from true\n\n\n// copy into custom function\ndocument.onkeydown = function(evt) {\n    evt = evt || window.event;\n    var isEscape = false;\n    if (\"key\" in evt) {\n        isEscape = (evt.key === \"Escape\" || evt.key === \"Esc\");\n    } else {\n        isEscape = (evt.keyCode === 27);\n    }\n    if (isEscape) {\n        //alert(\"Escape\");\n        //escKeyPressed = true\n        showAutoSolve = !showAutoSolve; // Toggle escKeyPressed\n    }\n};\n\nif (storehighscore3>0&&storehighscore2>0&&storehighscore1>0) {\n    showAutoSolve = true\n}"
        }
      ]
    },
    "custom": {
      "pages": [
        {
          "Name": "findPossibleMoves",
          "Active": "true",
          "Internal": "false",
          "Type": "LIBRARY_EDITOR",
          "Comment": "",
          "Code": "function findPossibleMoves(x, y) {\n  // the 8 directions a knight can move on a chess board\n  const dx = [-1, 1, 2, 2, -1, 1, -2, -2];\n  const dy = [2, 2, 1, -1, -2, -2, 1, -1];\n\n  var possible = false;\n  for(var i = 0; i < 8; i++) {\n    var curX = x + dx[i], curY = y + dy[i];\n    if(curX < 0 || curX >= numOfCols || curY < 0 || curY >= numOfRows) { // out of bound and illegal\n      continue;\n    } \n    var curIdx = posToIdx[curY][curX];\n    if(!squareFilled[curIdx]){\n      possible = true;\n      squareHighlighted[curIdx] = 1;\n    }\n  }\n  return possible;\n}"
        },
        {
          "Name": "onClickSquare",
          "Active": "true",
          "Internal": "false",
          "Type": "LIBRARY_EDITOR",
          "Comment": "",
          "Code": "// on clicking of a square\nfunction onClickSquare(idx) {\n  if(gameOver)\n    return;\n\n  var x = idxToPos[idx][0], y = idxToPos[idx][1];\n  // idex == -1 blank space or landed on before\n  if(moveCounter > 1 && !squareHighlighted[idx]) {\n    _tools.showOkDialog(\"You cannot move to this square! Click a legal move using the green squares.\");\n    for(var i = 0; i < numOfSquares; i++) {\n      if(squareHighlighted[i])\n        squareColor[i] = highlightColor;\n        //squareColor[i] = unfilledColor; // make invisible\n    }\n    return;\n  }\n  // set the current grid square to be filled\n  squareFilled[idx] = 1;\n\n  for(var i = 0; i < numOfSquares; i++) { // refresh color\n    if(squareColor[i] == highlightColor) {\n      squareColor[i] = unfilledColor;\n    }\n    if(squareHighlighted[i])\n      squareHighlighted[i] = 0;\n  }\n\n  squareColor[idx] = filledColor;\n  textStr.push(moveCounter++);\n  textX.push(x * squareLength);\n  textY.push(y * squareLength);\n  \n  //lookang attempt to add unicode knight position\n  textXunicode=(x * squareLength);\n  textYunicode=(y * squareLength);\n  lastIdx = idx;\n\n  // if no more moves\n  if(moveCounter == numOfSquares + 1) {\n    _tools.showOkDialog(\"The whole board has been filled, good job!\");\n    gameOver = true;\n    storeHighScore ()\n  } else if(!findPossibleMoves(x, y)) {\n    _tools.showOkDialog(\"There are no more possible moves :(\");\n    gameOver = true;\n    storeHighScore ()\n  }\n}\n"
        },
        {
          "Name": "storeHighScore",
          "Active": "true",
          "Internal": "false",
          "Type": "LIBRARY_EDITOR",
          "Comment": "",
          "Code": "function storeHighScore () {\n  storehighscore[_view.comboBox.getSelectedOptionsIndexes()]= Math.max(moveCounter-1,storehighscore[_view.comboBox.getSelectedOptionsIndexes()]);\n  // ejss only remember for variable, not array\n  if (numOfRows==3&&numOfCols==3){\n    storehighscore1= Math.max(moveCounter-1,storehighscore1);\n  }\n  else if (numOfRows==4&&numOfCols==4){\n    storehighscore2= Math.max(moveCounter-1,storehighscore2);\n  }\n  else if (numOfRows==5&&numOfCols==5){\n    storehighscore3= Math.max(moveCounter-1,storehighscore3);\n  }\n}\n"
        },
        {
          "Name": "autoSolver",
          "Active": "true",
          "Internal": "false",
          "Type": "LIBRARY_EDITOR",
          "Comment": "Warnsdorff-based auto-solver and animator",
          "Code": "function legalMovesFrom(x, y, visited) {\n  const dx = [-1, 1, 2, 2, -1, 1, -2, -2];\n  const dy = [2, 2, 1, -1, -2, -2, 1, -1];\n  var moves = [];\n  for (var i = 0; i < 8; i++) {\n    var nx = x + dx[i], ny = y + dy[i];\n    if (nx >= 0 && nx < numOfCols && ny >= 0 && ny < numOfRows && !visited[ny][nx]) {\n      moves.push([nx, ny]);\n    }\n  }\n  return moves;\n}\n\nfunction warnsdorffNext(x, y, visited) {\n  var moves = legalMovesFrom(x, y, visited);\n  if (moves.length === 0) return null;\n  // choose move with minimum onward degree\n  moves.sort(function(a, b) {\n    var da = legalMovesFrom(a[0], a[1], visited).length;\n    var db = legalMovesFrom(b[0], b[1], visited).length;\n    if (da !== db) return da - db;\n    // tie-breaker: lexicographic for determinism\n    if (a[1] !== b[1]) return a[1] - b[1];\n    return a[0] - b[0];\n  });\n  return moves[0];\n}\n\nfunction buildVisitedFromSquares() {\n  var visited = [];\n  for (var i = 0; i < numOfRows; i++) {\n    visited.push([]);\n    for (var j = 0; j < numOfCols; j++) {\n      var idx = posToIdx[i][j];\n      visited[i].push(!!squareFilled[idx]);\n    }\n  }\n  return visited;\n}\n\nfunction recommendedStart() {\n  if (numOfRows === 3 && numOfCols === 3) return [0,0];\n  if (numOfRows === 4 && numOfCols === 4) return [0,0];\n  return [0,0];\n}\n\nfunction generateSolutionPathFromCurrent() {\n  var visited = buildVisitedFromSquares();\n  var path = [];\n  var sx, sy;\n  if (lastIdx >= 0) {\n    sx = idxToPos[lastIdx][0];\n    sy = idxToPos[lastIdx][1];\n  } else {\n    var rs = recommendedStart();\n    sx = rs[0]; sy = rs[1];\n  }\n  var cx = sx, cy = sy;\n  if (moveCounter === 1) {\n    path.push(posToIdx[cy][cx]);\n    visited[cy][cx] = true;\n  }\n  var next;\n  while (true) {\n    next = warnsdorffNext(cx, cy, visited);\n    if (!next) break;\n    cx = next[0]; cy = next[1];\n    visited[cy][cx] = true;\n    path.push(posToIdx[cy][cx]);\n    if (path.length >= numOfSquares) break;\n  }\n  return path;\n}\n\nfunction scheduleNextAutoStep() {\n  if (!autoSolve || solving || gameOver) {}\n  if (!autoSolve || gameOver) return;\n  if (solutionStep >= solutionPath.length) {\n    solving = false;\n    autoSolve = false;\n    try { _view.autoSolveCheckbox.setProperty(\"Checked\", false); } catch(e){}\n    return;\n  }\n  solving = true;\n  autoTimerId = setTimeout(function() {\n    var idx = solutionPath[solutionStep++];\n    onClickSquare(idx);\n    solving = false;\n    if (autoSolve && !gameOver) {\n      scheduleNextAutoStep();\n    } else {\n      autoSolve = false;\n      try { _view.autoSolveCheckbox.setProperty(\"Checked\", false); } catch(e){}\n    }\n  }, humanDelay);\n}\n\nfunction startAutoSolve() {\n  stopAutoSolve();\n  solutionPath = generateSolutionPathFromCurrent();\n  solutionStep = 0;\n  if (solutionPath.length === 0) {\n    autoSolve = false;\n    try { _view.autoSolveCheckbox.setProperty(\"Checked\", false); } catch(e){}\n    return;\n  }\n  scheduleNextAutoStep();\n}\n\nfunction stopAutoSolve() {\n  try { clearTimeout(autoTimerId); } catch(e){}\n  autoTimerId = -1;\n  solving = false;\n}\n"
        },
        {
          "Name": "autoSolverOverride",
          "Active": "true",
          "Internal": "false",
          "Type": "LIBRARY_EDITOR",
          "Comment": "Override: DFS longest path to improve coverage on small boards",
          "Code": "function generateSolutionPathFromCurrent() {\n  var visited = buildVisitedFromSquares();\n  var bestPath = [];\n  var startCandidates = [];\n  if (lastIdx >= 0) {\n    startCandidates.push(idxToPos[lastIdx]);\n  } else {\n    for (var ry = 0; ry < numOfRows; ry++) {\n      for (var rx = 0; rx < numOfCols; rx++) {\n        startCandidates.push([rx, ry]);\n      }\n    }\n  }\n  function cloneVisited(v){ var c=[]; for (var r=0;r<numOfRows;r++){ c.push(v[r].slice()); } return c; }\n  function orderedMoves(x,y,v){ var m=legalMovesFrom(x,y,v).slice(); m.sort(function(a,b){ var da=legalMovesFrom(a[0],a[1],v).length; var db=legalMovesFrom(b[0],b[1],v).length; if(da!==db) return da-db; if(a[1]!==b[1]) return a[1]-b[1]; return a[0]-b[0]; }); return m; }\n  function dfs(cx,cy,v){ var path=[]; if(!v[cy][cx]){ v[cy][cx]=true; path.push(posToIdx[cy][cx]); }\n    var moves=orderedMoves(cx,cy,v); var bestTail=[]; for(var i=0;i<moves.length;i++){ var nx=moves[i][0], ny=moves[i][1]; var v2=cloneVisited(v); var tail=dfs(nx,ny,v2); if(tail.length>bestTail.length){ bestTail=tail; if(bestTail.length+path.length>=numOfSquares) break; } }\n    return path.concat(bestTail);\n  }\n  for (var s=0; s<startCandidates.length; s++){ var sx=startCandidates[s][0], sy=startCandidates[s][1]; var v0=cloneVisited(visited); var prefix=[]; if (moveCounter===1 && lastIdx<0){ prefix.push(posToIdx[sy][sx]); v0[sy][sx]=true; }\n    var tail=dfs(sx,sy,v0); var candidate=prefix.concat(tail); if(candidate.length>bestPath.length){ bestPath=candidate; if(bestPath.length>=numOfSquares) break; }\n  }\n  return bestPath;\n}\n"
        },
        {
          "Name": "fullScreen",
          "Active": "true",
          "Internal": "false",
          "Type": "CODE_EDITOR",
          "Comment": "",
          "Code": "// fullScreen\n// add toggleFullScreen() to onDoubleclick of plottingPanel\n\n/*jslint browser:true */\n// copy to custom function\nfunction toggleFullScreen() {\n  try {\n    const doc = document.documentElement;\n    \n    // Check if any fullscreen element exists\n    const isFullScreen = document.fullscreenElement || \n                         document.mozFullScreenElement || \n                         document.webkitFullscreenElement || \n                         document.msFullscreenElement;\n\n    if (!isFullScreen) {\n      // Request full-screen mode based on the browser\n      if (doc.requestFullscreen) {\n        doc.requestFullscreen();\n      } else if (doc.msRequestFullscreen) {\n        doc.msRequestFullscreen();\n      } else if (doc.mozRequestFullScreen) {\n        doc.mozRequestFullScreen();\n      } else if (doc.webkitRequestFullscreen) {\n        doc.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); // Pass input permission for older WebKit\n      }\n    } else {\n      // Exit full-screen mode based on the browser\n      if (document.exitFullscreen) {\n        document.exitFullscreen();\n      } else if (document.msExitFullscreen) {\n        document.msExitFullscreen();\n      } else if (document.mozCancelFullScreen) {\n        document.mozCancelFullScreen();\n      } else if (document.webkitExitFullscreen) {\n        document.webkitExitFullscreen();\n      }\n    }\n  } catch (e) {\n    console.error(\"Error toggling full-screen mode:\", e);\n  }\n}\n\n// Handle screen orientation for mobile devices (optional)\nwindow.addEventListener(\"orientationchange\", () => {\n  if (screen.orientation && screen.orientation.lock) {\n    screen.orientation.lock('landscape').catch(err => console.warn('Failed to lock orientation:', err));\n  }\n});\n"
        }
      ]
    },
    "elements": {
      "list": []
    }
  },
  "view": {
    "Tree": [
      {
        "Name": "topPanel",
        "Type": "Panel",
        "Expanded": "true",
        "Properties": [
          {
            "name": "OnMove",
            "value": "// make combo box reflect correct state\n\n//_view.comboBox.setSelectedOptions([\"3x3\"])\n//var opts = _view.comboBox.getProperty(\"SelectedOptions\"); \nif (numOfRows==3&&numOfCols==3){\n_view.comboBox.setSelectedOptions([\"3x3\"])\n//alert()\n}\n\nelse if (numOfRows==4&&numOfCols==4){\n_view.comboBox.setSelectedOptions([\"4x4\"])\n}\n\nelse  if (numOfRows==5&&numOfCols==5){\n_view.comboBox.setSelectedOptions([\"5x5\"])\n}\n"
          },
          {
            "name": "Width",
            "value": "\"100%\""
          },
          {
            "name": "Display",
            "value": "\"inline-flex\""
          }
        ],
        "Children": [
          {
            "Name": "button",
            "Type": "Button",
            "Properties": [
              {
                "name": "Text",
                "value": "\"button\""
              },
              {
                "name": "OnPress",
                "value": "//_view.comboBox.setSelectedOptions([\"3x3\"])\nvar opts = _view.comboBox.getProperty(\"SelectedOptions\"); \nif (opts==\"3x3\"){\n_view.comboBox.setSelectedOptions([\"3x3\"])\nalert()\n}\n"
              },
              {
                "name": "Display",
                "value": "\"none\""
              }
            ]
          },
          {
            "Name": "comboBox",
            "Type": "ComboBox",
            "Properties": [
              {
                "name": "Options",
                "value": "[\"\",\"3x3\",\"4x4\",\"5x5\"]"
              },
              {
                "name": "OnChange",
                "value": "// to use\nvar opts = _view.comboBox.getProperty(\"SelectedOptions\");  // array of options\n    var option = (opts.length > 0)? opts[0]:\"\"; // selected option \nif ( option==\"5x5\"){\n  numOfRows=5\n  numOfCols=5\n  }\n else if ( option==\"4x4\"){\n  numOfRows=4\n  numOfCols=4\n  }\n   else if ( option==\"3x3\"){\n  numOfRows=3\n  numOfCols=3\n  }\n_initialize()"
              },
              {
                "name": "Width",
                "value": "\"50%\""
              },
              {
                "name": "Font",
                "value": "font"
              }
            ]
          },
          {
            "Name": "reset",
            "Type": "Button",
            "Properties": [
              {
                "name": "Text",
                "value": "\"\u21bbReset\""
              },
              {
                "name": "OnPress",
                "value": "\nstopAutoSolve();\nautoSolve=false;\nif (_view.autoSolveCheckbox) _view.autoSolveCheckbox.setProperty(\"Checked\", false);\n_reset()\n"
              },
              {
                "name": "Width",
                "value": "\"50%\""
              },
              {
                "name": "Font",
                "value": "font"
              }
            ]
          },
          {
            "Name": "autoSolveCheckbox",
            "Type": "CheckBox",
            "Properties": [
              {
                "name": "Text",
                "value": "\"Auto-solve?\""
              },
              {
                "name": "Checked",
                "value": "autoSolve"
              },
              {
                "name": "OnChange",
                "value": "\nif (autoSolve) {\n  startAutoSolve();\n} else {\n  stopAutoSolve();\n}\n"
              },
              {
                "name": "Width",
                "value": "\"50%\""
              },
              {
                "name": "Font",
                "value": "font"
              },
              {
                "name": "Display",
                "value": "showAutoSolve?\"inline\":\"none\""
              }
            ]
          }
        ]
      },
      {
        "Name": "mainPanel",
        "Type": "Panel",
        "Expanded": "true",
        "Properties": [
          {
            "name": "OnMove",
            "value": "// make combo box reflect correct state\n\n//_view.comboBox.setSelectedOptions([\"3x3\"])\n//var opts = _view.comboBox.getProperty(\"SelectedOptions\"); \nif (numOfRows==3&&numOfCols==3){\n_view.comboBox.setSelectedOptions([\"3x3\"])\n//alert()\n}\n\nelse if (numOfRows==4&&numOfCols==4){\n_view.comboBox.setSelectedOptions([\"4x4\"])\n}\n\nelse  if (numOfRows==5&&numOfCols==5){\n_view.comboBox.setSelectedOptions([\"5x5\"])\n}\n"
          }
        ],
        "Children": [
          {
            "Name": "plottingPanel",
            "Type": "PlottingPanel",
            "Expanded": "true",
            "Properties": [
              {
                "name": "Gutters",
                "value": "[0, 0, 0, 0]"
              },
              {
                "name": "YScalePrecision",
                "value": "0"
              },
              {
                "name": "XFixedTick",
                "value": "-0.5"
              },
              {
                "name": "Enabled",
                "value": "true"
              },
              {
                "name": "SquareAspect",
                "value": "true"
              },
              {
                "name": "YFixedTick",
                "value": "-0.5"
              },
              {
                "name": "YAutoTicks",
                "value": "false"
              },
              {
                "name": "TRMessage",
                "value": "\"High scores\\n3x3 =\"+storehighscore1+\"\\n4x4 =\"+storehighscore2+\"\\n5x5 =\"+storehighscore3"
              },
              {
                "name": "XTickStep",
                "value": "numOfRows * squareLength"
              },
              {
                "name": "YTickStep",
                "value": "numOfCols * squareLength"
              },
              {
                "name": "AutoScaleY",
                "value": "true"
              },
              {
                "name": "AutoScaleX",
                "value": "true"
              },
              {
                "name": "CursorTypeForMove",
                "value": "\"pointer\""
              },
              {
                "name": "XAutoTicks",
                "value": "false"
              },
              {
                "name": "Height",
                "value": "\"90vh\""
              },
              {
                "name": "XScalePrecision",
                "value": "0"
              },
              {
                "name": "Width",
                "value": "\"100%\""
              },
              {
                "name": "OnDoubleClick",
                "value": "toggleFullScreen()"
              }
            ],
            "Children": [
              {
                "Name": "shapeSet",
                "Type": "ShapeSet2D",
                "Properties": [
                  {
                    "name": "NumberOfElements",
                    "value": "numOfSquares"
                  },
                  {
                    "name": "FillColor",
                    "value": "%squareColor%"
                  },
                  {
                    "name": "Sensitivity",
                    "value": "0"
                  },
                  {
                    "name": "SizeX",
                    "value": "squareLength"
                  },
                  {
                    "name": "ShapeType",
                    "value": "\"RECTANGLE\""
                  },
                  {
                    "name": "X",
                    "value": "squareX"
                  },
                  {
                    "name": "Y",
                    "value": "squareY"
                  },
                  {
                    "name": "OnPress",
                    "value": "onClickSquare(interact);"
                  },
                  {
                    "name": "SizeY",
                    "value": "squareLength"
                  },
                  {
                    "name": "EnabledPosition",
                    "value": "\"ENABLED_NO_MOVE\""
                  },
                  {
                    "name": "ElementInteracted",
                    "value": "interact"
                  }
                ]
              },
              {
                "Name": "unicodeknight",
                "Type": "Text2D",
                "Properties": [
                  {
                    "name": "FillColor",
                    "value": "\"Magenta\""
                  },
                  {
                    "name": "X",
                    "value": "textXunicode"
                  },
                  {
                    "name": "Y",
                    "value": "textYunicode"
                  },
                  {
                    "name": "Text",
                    "value": "\"\u265e\""
                  },
                  {
                    "name": "Font",
                    "value": "\"normal normal 7vw \""
                  }
                ]
              },
              {
                "Name": "textSet",
                "Type": "TextSet2D",
                "Properties": [
                  {
                    "name": "X",
                    "value": "textX"
                  },
                  {
                    "name": "Y",
                    "value": "textY"
                  },
                  {
                    "name": "Text",
                    "value": "%textStr%"
                  },
                  {
                    "name": "Font",
                    "value": "font"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "Name": "html",
        "Type": "Panel",
        "Properties": [
          {
            "name": "Html",
            "value": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Knight's Move</title>\n</head>\n<body>\n  <h2>Knight's Move</h2>\n<!-- YouTube video at the beginning -->\n  <p>\n    <a href=\"https://www.youtube.com/watch?v=8SHnLz1cdfI\" target=\"_blank\" rel=\"noopener noreferrer\">\n      Watch on YouTube\n    </a>\n  </p>\n  <iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/8SHnLz1cdfI?si=tZNuFnk00u8W4KCS\"\n    title=\"YouTube video player\" frameborder=\"0\"\n    allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n    referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen>\n  </iframe>\n\n  <p>The knight (\u2658, \u265e) is a piece in the game of chess and is represented by a horse's head and neck.</p>\n  <p>The knight's movement is unique: it may move two squares vertically and one square horizontally, or two squares horizontally and one square vertically (forming an \u201cL\u201d). This way, a knight can have a maximum of 8 moves. While moving, the knight can jump over pieces to reach its destination.</p>\n\n  <h2>Single Player Game</h2>\n  <p>A combo box allows young players to try to discover the best strategy/pattern to maximise the number of moves.</p>\n  <p>Try to move the maximum possible number of knight's moves given the square grid\u2014for example, on a 5\u00d75 grid, the maximum number of visited squares is 25.</p>\n\n  <h2>For more resources</h2>\n  <ul>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/interactive-resources/mathematics/1054-knight-intro\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Knight \u2014 Intro\n      </a>\n    </li>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/interactive-resources/mathematics/1101-knight-moves-no-hint\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Knight Moves (No Hint)\n      </a>\n    </li>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/interactive-resources/mathematics/1057-knight-moves\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Knight Moves\n      </a>\n    </li>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/interactive-resources/mathematics/1055-knight-star-to-star\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Knight: Star to Star\n      </a>\n    </li>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/interactive-resources/mathematics/1102-knight-star-to-star-no-hint\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Knight: Star to Star (No Hint)\n      </a>\n    </li>\n    <li>\n      <a href=\"https://sg.iwant2study.org/ospsg/index.php/events/1106-20210830-digital-e2k-applications-knights-move\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Digital E2K Applications: Knight\u2019s Move (Event)\n      </a>\n    </li>\n  </ul>"
          }
        ]
      }
    ],
    "RootProperties": []
  },
  "metadata": {
    "APP": "WebEJS",
    "CreatedWith": "WebEJS : The web version of Easy JavaScript Simulations",
    "MoreInfo": "WebEJS 1.2",
    "version": "https://www.um.es/fem/wikis/webejs/"
  }
}