Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
165 changes: 165 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/bin/env python
# encoding: utf-8
from flask import Flask, render_template, jsonify, request
import random

app = Flask(__name__)

def init():
matrix = [0 for i in range(16)]
random_lst = random.sample(range(16), 2)
matrix[random_lst[0]] = matrix[random_lst[1]] = 2
return matrix

def move(matrix, direction):
mergedList = []
if direction == 'w':
for i in range(16):
j = i
while j - 4 >= 0:
if matrix[j-4] == 0:
matrix[j-4] = matrix[j]
matrix[j] = 0
elif matrix[j-4] == matrix[j] and j not in mergedList:
matrix[j-4] *= 2
matrix[j] = 0
mergedList.append(j-4)
mergedList.append(j)
j -= 4
elif direction == 's':
for i in range(15, -1, -1):
j = i
while j + 4 < 16:
if matrix[j+4] == 0:
matrix[j+4] = matrix[j]
matrix[j] = 0
elif matrix[j+4] == matrix[j] and j not in mergedList:
matrix[j+4] *= 2
matrix[j] = 0
mergedList.append(j)
mergedList.append(j+4)
j += 4
elif direction == 'a':
for i in range(16):
j = i
while j % 4 != 0:
if matrix[j-1] == 0:
matrix[j-1] = matrix[j]
matrix[j] = 0
elif matrix[j-1] == matrix[j] and j not in mergedList:
matrix[j-1] *= 2
matrix[j] = 0
mergedList.append(j-1)
mergedList.append(j)
j -= 1
else:
for i in range(15, -1, -1):
j = i
while j % 4 != 3:
if matrix[j+1] == 0:
matrix[j+1] = matrix[j]
matrix[j] = 0
elif matrix[j+1] == matrix[j] and j not in mergedList:
matrix[j+1] *= 2
matrix[j] = 0
mergedList.append(j)
mergedList.append(j+1)
j += 1
return matrix

def insert(matrix):
getZeroIndex = []
for i in range(16):
if matrix[i] == 0:
getZeroIndex.append(i)
if not getZeroIndex:
return matrix
randomZeroIndex = random.choice(getZeroIndex)
max_num = max(matrix)
if max_num > 128:
matrix[randomZeroIndex] = random.choice([4, 8, 16, 32])
else:
matrix[randomZeroIndex] = random.choice([4, 8])
return matrix

def isOver(matrix):
if 0 in matrix:
return False
else:
for i in range(16):
if i % 4 != 3:
if matrix[i] == matrix[i+1]:
return False
if i < 12:
if matrix[i] == matrix[i+4]:
return False
return True

game_state = {
'matrix': init(),
'history': [],
'score': 0
}

@app.route('/')
def index():
return render_template('index.html')

@app.route('/new_game')
def new_game():
game_state['matrix'] = init()
game_state['history'] = []
game_state['score'] = 0
return jsonify({
'matrix': game_state['matrix'],
'score': game_state['score'],
'game_over': False,
'win': False
})

@app.route('/move/<direction>')
def handle_move(direction):
old_matrix = list(game_state['matrix'])
game_state['matrix'] = move(game_state['matrix'], direction)

changed = game_state['matrix'] != old_matrix

if changed:
game_state['history'].append(old_matrix)
game_state['matrix'] = insert(game_state['matrix'])
game_state['score'] = sum(game_state['matrix'])

game_over = isOver(game_state['matrix'])
win = 2048 in game_state['matrix']

return jsonify({
'matrix': game_state['matrix'],
'score': game_state['score'],
'game_over': game_over,
'win': win,
'changed': changed
})

@app.route('/back')
def handle_back():
if game_state['history']:
game_state['matrix'] = game_state['history'].pop()
game_state['score'] = sum(game_state['matrix'])
return jsonify({
'matrix': game_state['matrix'],
'score': game_state['score'],
'game_over': isOver(game_state['matrix']),
'win': 2048 in game_state['matrix']
})

@app.route('/state')
def get_state():
return jsonify({
'matrix': game_state['matrix'],
'score': game_state['score'],
'game_over': isOver(game_state['matrix']),
'win': 2048 in game_state['matrix']
})

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
107 changes: 107 additions & 0 deletions static/game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
class Game2048 {
constructor() {
this.board = document.getElementById('game-board');
this.scoreElement = document.getElementById('score');
this.gameOverOverlay = document.getElementById('game-over');
this.winOverlay = document.getElementById('win-overlay');
this.setupEventListeners();
this.init();
}

init() {
fetch('/new_game')
.then(response => response.json())
.then(data => {
this.renderBoard(data.matrix);
this.updateScore(data.score);
this.hideOverlays();
});
}

setupEventListeners() {
document.addEventListener('keydown', (e) => this.handleKeyPress(e));
document.getElementById('new-game-btn').addEventListener('click', () => this.init());
document.getElementById('restart-btn').addEventListener('click', () => this.init());
document.getElementById('new-game-win-btn').addEventListener('click', () => this.init());
document.getElementById('continue-btn').addEventListener('click', () => this.hideOverlays());
document.getElementById('back-btn').addEventListener('click', () => this.undo());
}

handleKeyPress(e) {
const keyMap = {
'ArrowUp': 'w', 'ArrowDown': 's', 'ArrowLeft': 'a', 'ArrowRight': 'd',
'w': 'w', 'W': 'w',
's': 's', 'S': 's',
'a': 'a', 'A': 'a',
'd': 'd', 'D': 'd'
};

if (keyMap[e.key]) {
e.preventDefault();
this.move(keyMap[e.key]);
} else if (e.key === 'b' || e.key === 'B') {
e.preventDefault();
this.undo();
}
}

move(direction) {
fetch(`/move/${direction}`)
.then(response => response.json())
.then(data => {
this.renderBoard(data.matrix);
this.updateScore(data.score);

if (data.win && !this.winShown) {
this.showWin();
this.winShown = true;
}

if (data.game_over) {
this.showGameOver();
}
});
}

undo() {
fetch('/back')
.then(response => response.json())
.then(data => {
this.renderBoard(data.matrix);
this.updateScore(data.score);
this.hideOverlays();
});
}

renderBoard(matrix) {
this.board.innerHTML = '';
matrix.forEach((value, index) => {
const tile = document.createElement('div');
tile.className = `tile tile-${value > 2048 ? 'super' : value}`;
tile.textContent = value === 0 ? '' : value;
this.board.appendChild(tile);
});
}

updateScore(score) {
this.scoreElement.textContent = score;
}

showGameOver() {
this.gameOverOverlay.classList.remove('hidden');
}

showWin() {
this.winOverlay.classList.remove('hidden');
}

hideOverlays() {
this.gameOverOverlay.classList.add('hidden');
this.winOverlay.classList.add('hidden');
this.winShown = false;
}
}

document.addEventListener('DOMContentLoaded', () => {
new Game2048();
});
Loading