var mazeWidth = 10;
var mazeHeight = 10;
var blocks;

function resetMaze() {
  blocks = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [2, 0, 0, 0, 1, 0, 0, 1, 0, 1],
            [1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 0, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 0, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 0, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
  blocks = makeMaze();
  drawMaze();
}

function drawMaze() {
  var mazeHtml = '<table class="packed">';
  for (var y = 0; y < mazeHeight; y++) {
    mazeHtml += '<tr class="packed">';
    for (var x = 0; x < mazeWidth; x++) {
      var flavor = 'empty';
      if (blocks[y][x] == 1) {
        flavor = 'block';
      } else if (blocks[y][x] == 2) {
        flavor = 'path';
      }

      var command = '';
      if (flavor == 'empty') {
        command = ' onmouseover="followpath(' + x + ', ' + y + ')"';
        command += ' ontouchstart="followpath(' + x + ', ' + y + ')"';
        command += ' ontouchmove="followpath(' + x + ', ' + y + ')"';
        command += ' ontouchend="followpath(' + x + ', ' + y + ')"';
      }

      mazeHtml += '<td class="packed"><div id="square_' + x + '_' + y + '" class="packed ' + flavor + ' square"' +
                  command + '></div></td>';
    }
    mazeHtml += '</tr>';
  }
  document.getElementById('maze').innerHTML = mazeHtml;
}

function followpath(x,y) {
  if (x > 0 && blocks[y][x-1] == 2) {
    blocks[y][x] = 2;
    moveHere([y,x]);
  } else if (y > 0 && blocks[y-1][x] == 2) {
    blocks[y][x] = 2;
    moveHere([y,x]);
  } else if (y < (mazeHeight - 1) && blocks[y+1][x] == 2) {
    blocks[y][x] = 2;
    moveHere([y,x]);
  } else if (x < (mazeWidth - 1) && blocks[y][x+1] == 2) {
    blocks[y][x] = 2;
    moveHere([y,x]);
  }
}

function moveHere(here) {
    var x = here[1];
    var y = here[0];
    blocks[y][x] = 2;
    document.getElementById('square_' + x + '_' + y).className = "packed path square";
}

function makeMaze() {
    var here = [1,0]; // start at the entrance
    while (!atExit(here)) {
        here = [1,0];

        // maze uses [y][x] indexing
        var maze = Array(10);
        for (var i = 0; i < 10; i++) {
            maze[i] = Array(10);
            for (var j = 0; j < 10; j++) {
                maze[i][j] = 1;
            }
        }

        maze[1][0] = 2; // entrance
        maze[8][9] = 0; // exit

        //for (var i = 0; i < 10; i++) {
        while (!atExit(here)) {
            var choices = availableAdjacents(here, maze);
            var next = randomElement(choices);
            if (!next) {
                break;
            }
            here = next;
            makeSquareClear(here, maze);
        }
    }

    while (makeSideTunnel(maze));

    return maze;
}

function makeSideTunnel(maze) {
    var choices = possibleTunnels(maze);
    if (choices.length == 0) {
        return false;
    }

    var choice = randomElement(choices);
    while (choice) {
        makeSquareClear(choice, maze);
        choices = availableAdjacents(choice, maze);
        choice = randomElement(choices);
    }
    return true;
}

function possibleTunnels(maze) {
    var choices = Array();
    for (var x = 1; x < 9; x++) {
        for (var y = 1; y < 9; y++) {
            var here = [y,x];
            if (touchesExactlyOne(here, maze) && notClear(here, maze)) {
                choices.push(here);
            }
        }
    }
    return choices;
}

function touchesExactlyOne(here, maze) {
    var x = here[1];
    var y = here[0];
    var touches = 0;
    var offsets = [[-1,0], [1,0], [0,-1], [0,1]];
    for (var i = 0; i < offsets.length; i++) {
        var there = [y + offsets[i][0], x + offsets[i][1]];
        var x2 = there[1];
        var y2 = there[0];
        if (maze[y2][x2] == 0) {
            touches++;
        }
    }
    return (touches == 1);
}

function atExit(here) {
    var x = here[1];
    var y = here[0];
    return (x == 8 && y == 8);
}

function makeSquareClear(here, maze) {
    var x = here[1];
    var y = here[0];
    maze[y][x] = 0;
}

// Return the list of adjacent squares that could be
// opened up without touching another tunnel.
function availableAdjacents(here, maze) {
    var x = here[1];
    var y = here[0];
    var result = Array();
    var offsets = [[-1,0], [1,0], [0,-1], [0,1]];
    for (var i = 0; i < offsets.length; i++) {
        var there = [y + offsets[i][0], x + offsets[i][1]];
        if (notEdge(there) && notClear(there, maze) && available(there, maze)) {
            result.push(there);
        }
    }
    return result;
}

function notEdge(here) {
    var x = here[1];
    var y = here[0];
    return (x > 0 && y > 0 && x < 9 && y < 9);
}

function notClear(here, maze) {
    var x = here[1];
    var y = here[0];
    return (maze[y][x] != 0);
}

function notSolid(here, maze) {
    var x = here[1];
    var y = here[0];
    return (maze[y][x] != 1);
}

function available(here, maze) {
    var x = here[1];
    var y = here[0];
    var count = 0;
    var offsets = [[-1,0], [1,0], [0,-1], [0,1]];
    for (var i = 0; i < offsets.length; i++) {
        var there = [y + offsets[i][0], x + offsets[i][1]];
        if (notSolid(there, maze) && notEdge(there)) {
            count++;
        }
    }
    return (count < 2);
}

// Return a randomly selected element from an array.
function randomElement(choices) {
    var i = Math.floor(Math.random() * choices.length);
    return choices[i];
}

