Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solve #1078

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

solve #1078

Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
solve
  • Loading branch information
oleg19790807 committed Dec 16, 2024
commit 805be344665c1c7dd9baccd2b09a7f1f756f1965
215 changes: 183 additions & 32 deletions src/modules/Game.class.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable no-shadow */
/* eslint-disable max-len */
/* eslint-disable prefer-const */
'use strict';

/**
Expand All @@ -7,77 +10,225 @@
*/
class Game {
constructor(initialState = null) {
this.board =
initialState ||
Array(4)
.fill(null)
.map(() => Array(4).fill(0));
this.grid = initialState || this.createEmptyGrid();
this.score = 0;
this.status = 'idle';
this.status = 'game-start'; // 'game-start', 'game-over', 'game-win'
this.won = false;
this.addRandomTile(); // Начинаем с случайной плитки
}

// Создание пустого поля 4x4
createEmptyGrid() {
return [
[null, null, null, null],
[null, null, null, null],
[null, null, null, null],
[null, null, null, null],
];
}

// Получить состояние игры (поле и счет)
getState() {
return this.board;
return this.grid;
}

// Получить текущий счет
getScore() {
return this.score;
}

// Получить статус игры ('game-start', 'game-over', 'game-win')
getStatus() {
return this.status;
}

// Начать игру заново (сбросить поле и счет)
start() {
this.status = 'playing';
this.addRandomTile();
this.grid = this.createEmptyGrid();
this.score = 0;
this.status = 'game-start';
this.won = false;
this.addRandomTile();
this.addRandomTile(); // Две стартовые плитки
}

// Перезапуск игры (сброс)
restart() {
this.board = Array(4)
.fill(null)
.map(() => Array(4).fill(0));
this.score = 0;
this.status = 'idle';
this.start();
}

moveLeft() {
// Implement sliding and merging logic here
// Добавить случайную плитку (2 или 4)
addRandomTile() {
let emptyCells = [];

for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
if (this.grid[row][col] === null) {
emptyCells.push([row, col]);
}
}
}

if (emptyCells.length === 0) {
return;
}

const [row, col] =
emptyCells[Math.floor(Math.random() * emptyCells.length)];

this.grid[row][col] = Math.random() < 0.1 ? 4 : 2;
}

// Обработать перемещение клеток в заданном направлении
move(direction) {
let moved = false;

if (direction === 'left') {
for (let row = 0; row < 4; row++) {
moved = this.moveRowLeft(row) || moved;
}
} else if (direction === 'right') {
for (let row = 0; row < 4; row++) {
moved = this.moveRowRight(row) || moved;
}
} else if (direction === 'up') {
for (let col = 0; col < 4; col++) {
moved = this.moveColumnUp(col) || moved;
}
} else if (direction === 'down') {
for (let col = 0; col < 4; col++) {
moved = this.moveColumnDown(col) || moved;
}
}

if (moved) {
this.addRandomTile(); // Добавляем новую случайную плитку после хода
}

return moved;
}

moveRight() {
// Rotate the board, call moveLeft, then rotate back
// Перемещение строки влево
moveRowLeft(row) {
let changed = false;
let newRow = this.grid[row].filter((val) => val !== null); // Убираем пустые значения

for (let i = 0; i < newRow.length - 1; i++) {
if (newRow[i] === newRow[i + 1]) {
newRow[i] = newRow[i] * 2;
this.score += newRow[i];
newRow[i + 1] = null;
changed = true;
}
}
newRow = newRow.filter((val) => val !== null); // Убираем пустые значения

while (newRow.length < 4) {
newRow.push(null); // Дополняем до 4 элементов
}
this.grid[row] = newRow;

return changed;
}

moveUp() {
// Similar to moveRight
// Перемещение строки вправо (обратный порядок)
moveRowRight(row) {
this.grid[row] = this.grid[row].reverse();

const changed = this.moveRowLeft(row);

this.grid[row] = this.grid[row].reverse();

return changed;
}

moveDown() {
// Similar to moveRight
// Перемещение столбца вверх
moveColumnUp(col) {
let column = this.grid.map((row) => row[col]);
let changed = this.moveRowLeft(column);

for (let i = 0; i < 4; i++) {
this.grid[i][col] = column[i];
}

return changed;
}

addRandomTile() {
const emptyCells = [];
// Перемещение столбца вниз (обратный порядок)
moveColumnDown(col) {
let column = this.grid.map((row) => row[col]).reverse();
let changed = this.moveRowLeft(column);

for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (this.board[i][j] === 0) {
emptyCells.push([i, j]);
this.grid[i][col] = column[3 - i];
}

return changed;
}

// Проверка на окончание игры (нет доступных ходов)
checkGameOver() {
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
if (this.grid[row][col] === null) {
return false;
}

if (row < 3 && this.grid[row][col] === this.grid[row + 1][col]) {
return false;
}

if (col < 3 && this.grid[row][col] === this.grid[row][col + 1]) {
return false;
}
}
}

if (emptyCells.length === 0) {
return;
return true;
}

// Проверка на победу (2048 в любой клетке)
checkWin() {
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
if (this.grid[row][col] === 2048) {
this.status = 'game-win';

return true;
}
}
}

const [x, y] = emptyCells[Math.floor(Math.random() * emptyCells.length)];
return false;
}

this.board[x][y] = Math.random() < 0.9 ? 2 : 4;
// Обработка нажатий клавиш
handleKeyPress(event) {
let moved = false;

switch (event.key) {
case 'ArrowLeft':
moved = this.move('left');
break;
case 'ArrowRight':
moved = this.move('right');
break;
case 'ArrowUp':
moved = this.move('up');
break;
case 'ArrowDown':
moved = this.move('down');
break;
}

if (moved) {
if (this.checkWin()) {
this.status = 'game-win';
} else if (this.checkGameOver()) {
this.status = 'game-over';
}
}
}
}

module.exports = Game;
export default Game;
103 changes: 56 additions & 47 deletions src/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,68 @@
'use strict';
import Game from '../modules/Game.class.js';

const game = new Game();
const startButton = document.querySelector('.button.start');
const scoreDisplay = document.querySelector('.game-score');
const gameField = document.querySelector('.game-field');
document.addEventListener('DOMContentLoaded', () => {
const game = new Game();

startButton.addEventListener('click', () => {
if (game.getStatus() === 'idle') {
game.start();
startButton.textContent = 'Restart';
} else {
game.restart();
}
updateUI();
});
const startButton = document.querySelector('.button.start');
const restartButton = document.querySelector('.button.restart');
const scoreElement = document.querySelector('.game-score');
const messageLose = document.querySelector('.message-lose');
const messageWin = document.querySelector('.message-win');
const messageStart = document.querySelector('.message-start');
const gameField = document.querySelector('.game-field');

document.addEventListener('keydown', (event) => {
if (game.getStatus() !== 'playing') {
return;
}
function updateUI() {
// Обновление счета
scoreElement.textContent = game.getScore();

switch (event.key) {
case 'ArrowLeft':
game.moveLeft();
break;
case 'ArrowRight':
game.moveRight();
break;
case 'ArrowUp':
game.moveUp();
break;
case 'ArrowDown':
game.moveDown();
break;
}
game.addRandomTile();
updateUI();
// Проверка на выигрыш или окончание игры
if (game.getStatus() === 'game-win') {
messageLose.classList.add('hidden');
messageStart.classList.add('hidden');
messageWin.classList.remove('hidden');
} else if (game.getStatus() === 'game-over') {
messageWin.classList.add('hidden');
messageStart.classList.add('hidden');
messageLose.classList.remove('hidden');
}

// Обновление игрового поля
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
const cell = gameField.rows[row].cells[col];
const value = game.getState()[row][col];

if (game.getStatus() === 'win') {
document.querySelector('.message-win').classList.remove('hidden');
} else if (game.getStatus() === 'lose') {
document.querySelector('.message-lose').classList.remove('hidden');
if (value) {
cell.textContent = value;
cell.classList.add(`field-cell--${value}`);
} else {
cell.textContent = '';
cell.classList.remove(/field-cell--\d+/);
}
}
}
}
});

function updateUI() {
const state = game.getState();
startButton.addEventListener('click', () => {
game.start();
startButton.classList.add('hidden');
updateUI();
});

gameField.querySelectorAll('.field-cell').forEach((cell, index) => {
const x = Math.floor(index / 4);
const y = index % 4;
restartButton.addEventListener('click', () => {
game.restart();
updateUI();
});

cell.textContent = state[x][y] === 0 ? '' : state[x][y];
cell.className = `field-cell field-cell--${state[x][y] || ''}`;
// Слушаем нажатия клавиш со стрелками
document.addEventListener('keydown', (event) => {
if (game.getStatus() === 'game-start') {
return;
}
game.handleKeyPress(event);
updateUI();
});
scoreDisplay.textContent = game.getScore();
}

updateUI();
});
Loading