diff --git a/index.html b/index.html index 81b761b..154feeb 100644 --- a/index.html +++ b/index.html @@ -34,7 +34,10 @@ td.visible { - +
+ + +
diff --git a/main.js b/main.js index e957054..38a6b9a 100644 --- a/main.js +++ b/main.js @@ -1,14 +1,21 @@ const globals = { grid: null, - tiles: [], }; -const btnGo_onClick = () => { +const btnStart_onClick = () => { globals.grid = makeGrid(4, 4, {value: 0, visible: false}); addRandomTile(); + // globals.grid = makeDevGrid([ // can't slide down or left + // [0,0,1,0], + // [0,0,0,0], + // [0,0,0,0], + // [3,2,3,0], + // ]); + redraw(globals.grid); +} + +const btnRedraw_onClick = () => { redraw(globals.grid); - // drawGrid(globals.grid, document.getElementById('output')); - // alert("Go"); } const btnUp_onClick = () => { @@ -71,34 +78,84 @@ const drawGrid = (grid, element) => { } const makeGrid = (numRows, numColumns, initialValue) => { + const tiles = []; const rows = []; for (rowIndex = 0; rowIndex < numRows; rowIndex++) { const row = []; for (columnIndex = 0; columnIndex < numColumns; columnIndex++) { position = {row: rowIndex, column: columnIndex}; const tile = makeTile(initialValue.value, initialValue.visible, rowIndex, columnIndex); - globals.tiles.push(tile); + tiles.push(tile); row.push(tile); } rows.push(row); } + const getTile = (grid, row, column) => { + return grid.getTile(row, column); + } const grid = { rows, numRows, numColumns, + tiles, + clone: () => { + const newGrid = makeGrid(numRows, numColumns, makeTile(0, false, 0, 0)); + for (let rowIndex = 0; rowIndex < numRows; rowIndex++) { + for (let columnIndex = 0; columnIndex < numColumns; columnIndex++) { + const newTile = newGrid.getTile(rowIndex, columnIndex); + const oldTile = grid.getTile(rowIndex, columnIndex); + newTile.originalLocation.column = oldTile.originalLocation.column; + newTile.originalLocation.row = oldTile.originalLocation.row; + newTile.value = oldTile.value; + newTile.visible = oldTile.visible; + } + } + return newGrid; + }, + getColumn: (index) => { + let vector = []; + for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { + vector.push(grid.getTile(rowIndex, index)); + } + return vector; + }, + getRow: (index) => { + let vector = []; + for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { + vector.push(grid.getTile(index, columnIndex)); + } + return vector; + }, getTile: (row, column) => { - return rows[row][column]; + if (row >= 0 && row < numRows && column >= 0 && column < numColumns) { + return rows[row][column]; + } + return null; }, setTile: (row, column, tile) => { - rows[row][column] = tile; + if (row >= 0 && row < numRows && column >= 0 && column < numColumns) { + rows[row][column] = tile; + } }, swapTiles: (fromRow, fromColumn, toRow, toColumn) => { - fromTile = grid.getTile(fromRow, fromColumn); - toTile = grid.getTile(toRow, toColumn); - // maybe set previous locations on the tiles - grid.setTile(fromRow, fromColumn, toTile); - grid.setTile(toRow, toColumn, fromTile); + if ( + fromRow >= 0 && fromRow < numRows + && fromColumn >= 0 && fromColumn < numColumns + && toRow >= 0 && toRow < numRows + && toColumn >= 0 && toColumn < numColumns) { + fromTile = grid.getTile(fromRow, fromColumn); + toTile = grid.getTile(toRow, toColumn); + // maybe set previous locations on the tiles + grid.setTile(fromRow, fromColumn, toTile); + grid.setTile(toRow, toColumn, fromTile); + } }, + toString: (mapFn = i => i.value) => { + return "[[" + mapFn(grid.getTile(0, 0)) + "," + mapFn(grid.getTile(0, 1)) + "," + mapFn(grid.getTile(0, 2)) + "," + mapFn(grid.getTile(0, 3)) + "],\n" + + " [" + mapFn(grid.getTile(1, 0)) + "," + mapFn(grid.getTile(1, 1)) + "," + mapFn(grid.getTile(1, 2)) + "," + mapFn(grid.getTile(1, 3)) + "],\n" + + " [" + mapFn(grid.getTile(2, 0)) + "," + mapFn(grid.getTile(2, 1)) + "," + mapFn(grid.getTile(2, 2)) + "," + mapFn(grid.getTile(2, 3)) + "],\n" + + " [" + mapFn(grid.getTile(3, 0)) + "," + mapFn(grid.getTile(3, 1)) + "," + mapFn(grid.getTile(3, 2)) + "," + mapFn(grid.getTile(3, 3)) + "]]"; + } }; return grid; } @@ -121,7 +178,7 @@ const makeTile = (value, visible, row, column) => { }; const addRandomTile = () => { - const hiddenTiles = globals.tiles.filter(tile => !tile.visible); + const hiddenTiles = globals.grid.tiles.filter(tile => !tile.visible); if (hiddenTiles.length <=0) return; const index = Math.floor(Math.random() * hiddenTiles.length); const tile = hiddenTiles[index]; @@ -134,148 +191,198 @@ const redraw = (grid) => { drawGrid(grid, element); } -const slideUp = (grid) => { +const slide = (fromIndex, toIndex, vector, advance, swap, merge, testForDone) => { + // const oldSwap = swap; + // swap = (fromIndex, toIndex) => { + // const temp = vector[toIndex]; + // vector[toIndex] = vector[fromIndex]; + // vector[fromIndex] = temp; + // oldSwap(fromIndex, toIndex); + // }; let didIDoIt = false; - for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - lastIndex = -1; - for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex++; - if (lastIndex != rowIndex) { - grid.swapTiles(rowIndex, columnIndex, lastIndex, columnIndex); - didIDoIt = true; + let hasMergedPrevious = false; + while(!testForDone(fromIndex)) { + const fromTile = vector[fromIndex]; + const toTile = toIndex < vector.length && toIndex >= 0 ? vector[toIndex] : null; + if (toTile == null) { + // Advance toIndex + toIndex = advance(toIndex); + hasMergedPrevious = false; + continue; + } + if (fromIndex == toIndex) { + // Advance fromIndex + fromIndex = advance(fromIndex); + hasMergedPrevious = false; + continue; + } + if (!toTile.visible) { + if (fromTile.visible) { + // need to choose row or column + swap(fromIndex, toIndex); + // Advance fromIndex + fromIndex = advance(fromIndex); + hasMergedPrevious = false; + didIDoIt = true; + } else { + // Advance fromIndex + fromIndex = advance(fromIndex); + hasMergedPrevious = false; + } + } else { + if (fromTile.visible) { + if (fromTile.value == toTile.value) { + if (hasMergedPrevious) { + // Advance toIndex + toIndex = advance(toIndex); + hasMergedPrevious = false; + didIDoIt = true; + } else { + // Merge tiles + merge(fromTile, toTile); + // Advance fromIndex + fromIndex = advance(fromIndex); + hasMergedPrevious = true; + didIDoIt = true; + } + } else { + // Advance toIndex + toIndex = advance(toIndex); + hasMergedPrevious = false; } + } else { + fromIndex = advance(fromIndex); + hasMergedPrevious = false; } } } return didIDoIt; } +const slideUp = (grid) => { + let didIDoIt = false; + const advance = i => i + 1; + for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { + const swap = (from, to) => { + grid.swapTiles(from, columnIndex, to, columnIndex); + const tempTile = vector[to]; + vector[to] = vector[from]; + vector[from] = tempTile; + }; + const merge = (from, to) => { + to.value++; + from.value = 0; + from.visible = false; + }; + const vector = grid.getColumn(columnIndex); + const testForDone = fromIndex => fromIndex >= vector.length; + let fromIndex = 0; + let toIndex = -1; + const didChangeThisPass = slide(fromIndex, toIndex, vector, advance, swap, merge, testForDone); + didIDoIt = didIDoIt || didChangeThisPass; + } + return didIDoIt; +} + const slideLeft = (grid) => { let didIDoIt = false; + const advance = i => i + 1; for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - lastIndex = -1; - for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex++; - if (lastIndex != columnIndex) { - grid.swapTiles(rowIndex, columnIndex, rowIndex, lastIndex); - didIDoIt = true; - } - } - } + const swap = (from, to) => { + grid.swapTiles(rowIndex, from, rowIndex, to); + const tempTile = vector[to]; + vector[to] = vector[from]; + vector[from] = tempTile; + }; + const merge = (from, to) => { + to.value++; + from.value = 0; + from.visible = false; + }; + const vector = grid.getRow(rowIndex); + const testForDone = fromIndex => fromIndex >= vector.length; + let fromIndex = 0; + let toIndex = -1; + const didChangeThisPass = slide(fromIndex, toIndex, vector, advance, swap, merge, testForDone); + didIDoIt = didIDoIt || didChangeThisPass; + } return didIDoIt; } const slideDown = (grid) => { let didIDoIt = false; + const advance = i => i - 1; for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - lastIndex = grid.numRows; - for (let rowIndex = grid.numRows - 1; rowIndex >= 0; rowIndex -= 1) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex--; - if (lastIndex != rowIndex) { - grid.swapTiles(rowIndex, columnIndex, lastIndex, columnIndex); - didIDoIt = true; - } - } - } + const swap = (from, to) => { + grid.swapTiles(from, columnIndex, to, columnIndex); + const tempTile = vector[to]; + vector[to] = vector[from]; + vector[from] = tempTile; + }; + const merge = (from, to) => { + to.value++; + from.value = 0; + from.visible = false; + }; + const vector = grid.getColumn(columnIndex); + const testForDone = fromIndex => fromIndex < 0; + let fromIndex = vector.length - 1; + let toIndex = vector.length; + const didChangeThisPass = slide(fromIndex, toIndex, vector, advance, swap, merge, testForDone); + didIDoIt = didIDoIt || didChangeThisPass; } return didIDoIt; } const slideRight = (grid) => { let didIDoIt = false; + const advance = i => i - 1; for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - lastIndex = grid.numColumns; - for (let columnIndex = grid.numColumns - 1; columnIndex >= 0; columnIndex -= 1) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex--; - if (lastIndex != columnIndex) { - grid.swapTiles(rowIndex, columnIndex, rowIndex, lastIndex); - didIDoIt = true; - } - } - } + const swap = (from, to) => { + grid.swapTiles(rowIndex, from, rowIndex, to); + const tempTile = vector[to]; + vector[to] = vector[from]; + vector[from] = tempTile; + }; + const merge = (from, to) => { + to.value++; + from.value = 0; + from.visible = false; + }; + const vector = grid.getRow(rowIndex); + const testForDone = fromIndex => fromIndex < 0; + let fromIndex = vector.length - 1; + let toIndex = vector.length; + const didChangeThisPass = slide(fromIndex, toIndex, vector, advance, swap, merge, testForDone); + didIDoIt = didIDoIt || didChangeThisPass; } return didIDoIt; } const canSlideUp = (grid) => { - canIDoIt = false; - for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - lastIndex = -1; - for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex++; - if (lastIndex != rowIndex) { - canIDoIt = true; - } - } - } - } - return canIDoIt; -} - -const canSlideLeft = (grid) => { - let canIDoIt = false; - for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - lastIndex = -1; - for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex++; - if (lastIndex != columnIndex) { - canIDoIt = true; - } - } - } - } - return canIDoIt; + const cloneGrid = grid.clone(); + return slideUp(cloneGrid); } const canSlideDown = (grid) => { - let canIDoIt = false; - for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { - lastIndex = grid.numRows; - for (let rowIndex = grid.numRows - 1; rowIndex >= 0; rowIndex -= 1) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex--; - if (lastIndex != rowIndex) { - canIDoIt = true; - } - } - } - } - return canIDoIt; + const cloneGrid = grid.clone(); + return slideDown(cloneGrid); +} +const canSlideLeft = (grid) => { + const cloneGrid = grid.clone(); + return slideLeft(cloneGrid); } const canSlideRight = (grid) => { - let canIDoIt = false; - for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { - lastIndex = grid.numColumns; - for (let columnIndex = grid.numColumns - 1; columnIndex >= 0; columnIndex -= 1) { - const tile = grid.getTile(rowIndex, columnIndex); - if (tile.visible) { - lastIndex--; - if (lastIndex != columnIndex) { - canIDoIt = true; - } - } - } - } - return canIDoIt; + const cloneGrid = grid.clone(); + return slideRight(cloneGrid); } const gameIsLost = (grid) => { + // return !canSlideUp(grid); + // return false; return !canSlideUp(grid) && !canSlideRight(grid) && !canSlideDown(grid) @@ -286,4 +393,40 @@ const checkForEnd = (grid) => { if (gameIsLost(grid)) { alert('A loser is you!'); } -} \ No newline at end of file +} + +const makeDevGrid = (matrix) => { + const numRows = matrix.length; + const numColumns = matrix[0].length; + const initialValue = makeTile(0, false, 0, 0); + const grid = makeGrid(numRows, numColumns, initialValue); + for (let rowIndex = 0; rowIndex < numRows; rowIndex++) { + const row = matrix[rowIndex]; + for (let colIndex = 0; colIndex < numColumns; colIndex++) { + const value = row[colIndex]; + const tile = grid.getTile(rowIndex, colIndex); + tile.value = value; + tile.visible = value > 0; + } + } + return grid; +} +/* +[0,0,0,0], +[0,0,1,0], +[0,0,0,0], +[2,1,2,2], +can't slide down. +[0,0,1,0], +[0,0,0,0], +[0,0,0,0], +[3,2,3,0], +can't slide down. +can't slide left. +up() +[1,0,1,0], +[0,0,3,0], +[0,0,0,0], +[3,2,0,0], either the 3 doesn't go up or the 1 bounces it back? +// fixed +*/