Makes sliding and merging work.

This commit is contained in:
2024-07-01 11:02:48 -07:00
parent ff7a473e2e
commit cb914f53df
2 changed files with 263 additions and 117 deletions

View File

@@ -34,7 +34,10 @@ td.visible {
<button id="btnDown" onclick="btnDown_onClick()">Down</button> <button id="btnDown" onclick="btnDown_onClick()">Down</button>
<button id="btnRight" onclick="btnRight_onClick()">Right</button> <button id="btnRight" onclick="btnRight_onClick()">Right</button>
</section> </section>
<button onclick="btnGo_onClick();" id="btnGo">Go</button> <section>
<button id="btnStart" onclick="btnStart_onClick();">Start</button>
<button id="btnRedraw" onclick="btnRedraw_onClick();">Redraw</button>
</section>
<script src="main.js"></script> <script src="main.js"></script>
</body> </body>
</html> </html>

375
main.js
View File

@@ -1,14 +1,21 @@
const globals = { const globals = {
grid: null, grid: null,
tiles: [],
}; };
const btnGo_onClick = () => { const btnStart_onClick = () => {
globals.grid = makeGrid(4, 4, {value: 0, visible: false}); globals.grid = makeGrid(4, 4, {value: 0, visible: false});
addRandomTile(); 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); redraw(globals.grid);
// drawGrid(globals.grid, document.getElementById('output'));
// alert("Go");
} }
const btnUp_onClick = () => { const btnUp_onClick = () => {
@@ -71,34 +78,84 @@ const drawGrid = (grid, element) => {
} }
const makeGrid = (numRows, numColumns, initialValue) => { const makeGrid = (numRows, numColumns, initialValue) => {
const tiles = [];
const rows = []; const rows = [];
for (rowIndex = 0; rowIndex < numRows; rowIndex++) { for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
const row = []; const row = [];
for (columnIndex = 0; columnIndex < numColumns; columnIndex++) { for (columnIndex = 0; columnIndex < numColumns; columnIndex++) {
position = {row: rowIndex, column: columnIndex}; position = {row: rowIndex, column: columnIndex};
const tile = makeTile(initialValue.value, initialValue.visible, rowIndex, columnIndex); const tile = makeTile(initialValue.value, initialValue.visible, rowIndex, columnIndex);
globals.tiles.push(tile); tiles.push(tile);
row.push(tile); row.push(tile);
} }
rows.push(row); rows.push(row);
} }
const getTile = (grid, row, column) => {
return grid.getTile(row, column);
}
const grid = { const grid = {
rows, rows,
numRows, numRows,
numColumns, 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) => { 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) => { 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) => { swapTiles: (fromRow, fromColumn, toRow, toColumn) => {
fromTile = grid.getTile(fromRow, fromColumn); if (
toTile = grid.getTile(toRow, toColumn); fromRow >= 0 && fromRow < numRows
// maybe set previous locations on the tiles && fromColumn >= 0 && fromColumn < numColumns
grid.setTile(fromRow, fromColumn, toTile); && toRow >= 0 && toRow < numRows
grid.setTile(toRow, toColumn, fromTile); && 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; return grid;
} }
@@ -121,7 +178,7 @@ const makeTile = (value, visible, row, column) => {
}; };
const addRandomTile = () => { const addRandomTile = () => {
const hiddenTiles = globals.tiles.filter(tile => !tile.visible); const hiddenTiles = globals.grid.tiles.filter(tile => !tile.visible);
if (hiddenTiles.length <=0) return; if (hiddenTiles.length <=0) return;
const index = Math.floor(Math.random() * hiddenTiles.length); const index = Math.floor(Math.random() * hiddenTiles.length);
const tile = hiddenTiles[index]; const tile = hiddenTiles[index];
@@ -134,148 +191,198 @@ const redraw = (grid) => {
drawGrid(grid, element); 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; let didIDoIt = false;
for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { let hasMergedPrevious = false;
lastIndex = -1; while(!testForDone(fromIndex)) {
for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { const fromTile = vector[fromIndex];
const tile = grid.getTile(rowIndex, columnIndex); const toTile = toIndex < vector.length && toIndex >= 0 ? vector[toIndex] : null;
if (tile.visible) { if (toTile == null) {
lastIndex++; // Advance toIndex
if (lastIndex != rowIndex) { toIndex = advance(toIndex);
grid.swapTiles(rowIndex, columnIndex, lastIndex, columnIndex); hasMergedPrevious = false;
didIDoIt = true; 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; 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) => { const slideLeft = (grid) => {
let didIDoIt = false; let didIDoIt = false;
const advance = i => i + 1;
for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) {
lastIndex = -1; const swap = (from, to) => {
for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { grid.swapTiles(rowIndex, from, rowIndex, to);
const tile = grid.getTile(rowIndex, columnIndex); const tempTile = vector[to];
if (tile.visible) { vector[to] = vector[from];
lastIndex++; vector[from] = tempTile;
if (lastIndex != columnIndex) { };
grid.swapTiles(rowIndex, columnIndex, rowIndex, lastIndex); const merge = (from, to) => {
didIDoIt = true; 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; return didIDoIt;
} }
const slideDown = (grid) => { const slideDown = (grid) => {
let didIDoIt = false; let didIDoIt = false;
const advance = i => i - 1;
for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) {
lastIndex = grid.numRows; const swap = (from, to) => {
for (let rowIndex = grid.numRows - 1; rowIndex >= 0; rowIndex -= 1) { grid.swapTiles(from, columnIndex, to, columnIndex);
const tile = grid.getTile(rowIndex, columnIndex); const tempTile = vector[to];
if (tile.visible) { vector[to] = vector[from];
lastIndex--; vector[from] = tempTile;
if (lastIndex != rowIndex) { };
grid.swapTiles(rowIndex, columnIndex, lastIndex, columnIndex); const merge = (from, to) => {
didIDoIt = true; 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; return didIDoIt;
} }
const slideRight = (grid) => { const slideRight = (grid) => {
let didIDoIt = false; let didIDoIt = false;
const advance = i => i - 1;
for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) {
lastIndex = grid.numColumns; const swap = (from, to) => {
for (let columnIndex = grid.numColumns - 1; columnIndex >= 0; columnIndex -= 1) { grid.swapTiles(rowIndex, from, rowIndex, to);
const tile = grid.getTile(rowIndex, columnIndex); const tempTile = vector[to];
if (tile.visible) { vector[to] = vector[from];
lastIndex--; vector[from] = tempTile;
if (lastIndex != columnIndex) { };
grid.swapTiles(rowIndex, columnIndex, rowIndex, lastIndex); const merge = (from, to) => {
didIDoIt = true; 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; return didIDoIt;
} }
const canSlideUp = (grid) => { const canSlideUp = (grid) => {
canIDoIt = false; const cloneGrid = grid.clone();
for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { return slideUp(cloneGrid);
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 canSlideDown = (grid) => { const canSlideDown = (grid) => {
let canIDoIt = false; const cloneGrid = grid.clone();
for (let columnIndex = 0; columnIndex < grid.numColumns; columnIndex++) { return slideDown(cloneGrid);
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 canSlideLeft = (grid) => {
const cloneGrid = grid.clone();
return slideLeft(cloneGrid);
} }
const canSlideRight = (grid) => { const canSlideRight = (grid) => {
let canIDoIt = false; const cloneGrid = grid.clone();
for (let rowIndex = 0; rowIndex < grid.numRows; rowIndex++) { return slideRight(cloneGrid);
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 gameIsLost = (grid) => { const gameIsLost = (grid) => {
// return !canSlideUp(grid);
// return false;
return !canSlideUp(grid) return !canSlideUp(grid)
&& !canSlideRight(grid) && !canSlideRight(grid)
&& !canSlideDown(grid) && !canSlideDown(grid)
@@ -286,4 +393,40 @@ const checkForEnd = (grid) => {
if (gameIsLost(grid)) { if (gameIsLost(grid)) {
alert('A loser is you!'); alert('A loser is you!');
} }
} }
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
*/