freeCodeCamp/curriculum/challenges/chinese/10-coding-interview-prep/rosetta-code/knights-tour.md

3.2 KiB

id title challengeType forumTopicId dashedName
5a23c84252665b21eecc7ed5 Knight's tour 5 302297 knights-tour

--description--

Knight's TourProblem: You have an empty w * h chessboard, but for a single knight on some square. The knight must perform a sequence of legal moves that result in the knight visiting every square on the chessboard exactly once. Note that it is not a requirement that the tour be "closed"; that is, the knight need not end within a single move of its start position.

--instructions--

Write a function that takes w and h as parameters and returns the number of initial positions from where it is possible to achieve the task stated above.

--hints--

knightTour should be a function.

assert(typeof knightTour == 'function');

knightTour(6, 6) should return a number.

assert(typeof knightTour(6, 6) == 'number');

knightTour(6, 6) should return 35.

assert.equal(knightTour(6, 6), 35);

knightTour(5, 6) should return 20.

assert.equal(knightTour(5, 6), 20);

knightTour(4, 6) should return 10.

assert.equal(knightTour(4, 6), 10);

knightTour(7, 3) should return 4.

assert.equal(knightTour(7, 3), 4);

knightTour(8, 6) should return 47.

assert.equal(knightTour(8, 6), 47);

--seed--

--seed-contents--

function knightTour(w, h) {

}

--solutions--

function knightTour(w, h) {
  var b,
    cnt = 0;

  var dx = [-2, -2, -1, 1, 2, 2, 1, -1];
  var dy = [-1, 1, 2, 2, 1, -1, -2, -2];

  function init_board() {
    var i, j, k, x, y;
    // * b is board; a is board with 2 rows padded at each side

    for (i = 0; i < h; i++) {
      for (j = 0; j < w; j++) {
        b[i][j] = 255;
      }
    }

    for (i = 0; i < h; i++) {
      for (j = 0; j < w; j++) {
        for (k = 0; k < 8; k++) {
          (x = j + dx[k]), (y = i + dy[k]);
          if (b[i][j] == 255) b[i][j] = 0;
          if (x >= 0 && x < w && y >= 0 && y < h) b[i][j]++;
        }
      }
    }
  }

  function walk_board(x, y) {
    var i, nx, ny, least;
    var steps = 0;
    // printf(E"H"E"J"E"%d;%dH"E"32m[]"E"m", y + 1, 1 + 2 * x);

    while (1) {
      // * occupy cell
      b[y][x] = 255;

      // * reduce all neighbors' neighbor count
      for (i = 0; i < 8; i++)
        if (y + dy[i] >= 0 && x + dx[i] >= 0 && y + dy[i] < h && x + dx[i] < w)
          b[y + dy[i]][x + dx[i]]--;

      // find neighbor with lowest neighbor count
      least = 255;
      for (i = 0; i < 8; i++) {
        if (y + dy[i] >= 0 && x + dx[i] >= 0 && y + dy[i] < h && x + dx[i] < w)
          if (b[y + dy[i]][x + dx[i]] < least) {
            nx = x + dx[i];
            ny = y + dy[i];
            least = b[ny][nx];
          }
      }

      if (least > 7) {
        return steps == w * h - 1;
      }

      steps++;
      (x = nx), (y = ny);
    }
  }

  function solve(x, y) {
    b = new Array(h);
    for (var i = 0; i < h; i++) b[i] = new Array(w);

    init_board();
    if (walk_board(x, y)) {
      cnt++;
    }
  }

  for (var i = 0; i < h; i++) {
    for (var j = 0; j < w; j++) {
      solve(j, i);
    }
  }

  return cnt;
}