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
278 changes: 278 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
#!/usr/bin/env python
# encoding: utf-8
"""
The minigame 2048 in python with Flask Web GUI
"""
import random
from flask import Flask, render_template, jsonify, request, session
import os

app = Flask(__name__)
app.secret_key = os.urandom(24)

# 颜色配置 - 为不同数字设置背景色
TILE_COLORS = {
0: {'bg': '#cdc1b4', 'color': '#776e65'},
2: {'bg': '#eee4da', 'color': '#776e65'},
4: {'bg': '#ede0c8', 'color': '#776e65'},
8: {'bg': '#f2b179', 'color': '#f9f6f2'},
16: {'bg': '#f59563', 'color': '#f9f6f2'},
32: {'bg': '#f67c5f', 'color': '#f9f6f2'},
64: {'bg': '#f65e3b', 'color': '#f9f6f2'},
128: {'bg': '#edcf72', 'color': '#f9f6f2'},
256: {'bg': '#edcc61', 'color': '#f9f6f2'},
512: {'bg': '#edc850', 'color': '#f9f6f2'},
1024: {'bg': '#edc53f', 'color': '#f9f6f2'},
2048: {'bg': '#edc22e', 'color': '#f9f6f2'},
}

def get_tile_style(value):
"""获取数字格子的样式"""
if value in TILE_COLORS:
return TILE_COLORS[value]
# 对于更大的数字,使用默认颜色
return {'bg': '#3c3a32', 'color': '#f9f6f2'}

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 get_random_number(matrix):
"""
根据游戏规则获取随机数
- 基础随机数:2, 4
- 当矩阵中有数字超过128时,可能出现16、32
"""
max_val = max(matrix)

if max_val > 128:
# 有数字超过128,可以出现16、32
weights = [50, 30, 15, 5] # 2, 4, 8, 16, 32 的权重
choices = [2, 4, 8, 16, 32]
return random.choices(choices, weights=weights + [5])[0]
else:
# 基础随机数 2 和 4
weights = [80, 20]
choices = [2, 4]
return random.choices(choices, weights=weights)[0]

def move(matrix, direction):
"""移动矩阵"""
matrix = list(matrix) # 创建副本
mergedList = []
changed = False

if direction == 'w': # 上
for i in range(16):
j = i
while j - 4 >= 0:
if matrix[j-4] == 0 and matrix[j] != 0:
matrix[j-4] = matrix[j]
matrix[j] = 0
changed = True
elif matrix[j-4] == matrix[j] and matrix[j] != 0 and j not in mergedList:
matrix[j-4] *= 2
matrix[j] = 0
mergedList.append(j-4)
mergedList.append(j)
changed = True
j -= 4
elif direction == 's': # 下
for i in range(15, -1, -1):
j = i
while j + 4 < 16:
if matrix[j+4] == 0 and matrix[j] != 0:
matrix[j+4] = matrix[j]
matrix[j] = 0
changed = True
elif matrix[j+4] == matrix[j] and matrix[j] != 0 and j not in mergedList:
matrix[j+4] *= 2
matrix[j] = 0
mergedList.append(j)
mergedList.append(j+4)
changed = True
j += 4
elif direction == 'a': # 左
for i in range(16):
j = i
while j % 4 != 0:
if matrix[j-1] == 0 and matrix[j] != 0:
matrix[j-1] = matrix[j]
matrix[j] = 0
changed = True
elif matrix[j-1] == matrix[j] and matrix[j] != 0 and j not in mergedList:
matrix[j-1] *= 2
matrix[j] = 0
mergedList.append(j-1)
mergedList.append(j)
changed = True
j -= 1
elif direction == 'd': # 右
for i in range(15, -1, -1):
j = i
while j % 4 != 3:
if matrix[j+1] == 0 and matrix[j] != 0:
matrix[j+1] = matrix[j]
matrix[j] = 0
changed = True
elif matrix[j+1] == matrix[j] and matrix[j] != 0 and j not in mergedList:
matrix[j+1] *= 2
matrix[j] = 0
mergedList.append(j)
mergedList.append(j+1)
changed = True
j += 1

return matrix, changed

def insert(matrix):
"""在空位置插入随机数"""
getZeroIndex = []
for i in range(16):
if matrix[i] == 0:
getZeroIndex.append(i)

if getZeroIndex:
randomZeroIndex = random.choice(getZeroIndex)
matrix[randomZeroIndex] = get_random_number(matrix)
return matrix

def is_over(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

def is_win(matrix):
"""检查是否获胜"""
return 2048 in matrix

@app.route('/')
def index():
"""渲染游戏页面"""
return render_template('index.html')

@app.route('/api/init', methods=['POST'])
def api_init():
"""初始化游戏API"""
matrix = init()
session['matrix'] = matrix
session['score'] = 0
session['history'] = [list(matrix)]

# 为每个格子添加样式信息
tiles = []
for i, val in enumerate(matrix):
style = get_tile_style(val)
tiles.append({
'value': val,
'index': i,
'bg': style['bg'],
'color': style['color']
})

return jsonify({
'matrix': matrix,
'tiles': tiles,
'score': 0,
'game_over': False,
'win': False
})

@app.route('/api/move', methods=['POST'])
def api_move():
"""移动API"""
data = request.get_json()
direction = data.get('direction')

matrix = session.get('matrix', [0]*16)
score = session.get('score', 0)
history = session.get('history', [])

new_matrix, changed = move(matrix, direction)

if changed:
# 计算得分(合并产生的数值)
for i in range(16):
if new_matrix[i] != matrix[i] and matrix[i] != 0:
# 这是一个合并操作
pass

new_matrix = insert(new_matrix)
history.append(list(new_matrix))
session['matrix'] = new_matrix
session['history'] = history
session['score'] = score

# 为每个格子添加样式信息
tiles = []
for i, val in enumerate(new_matrix):
style = get_tile_style(val)
tiles.append({
'value': val,
'index': i,
'bg': style['bg'],
'color': style['color']
})

return jsonify({
'matrix': new_matrix,
'tiles': tiles,
'score': score,
'changed': changed,
'game_over': is_over(new_matrix),
'win': is_win(new_matrix)
})

@app.route('/api/back', methods=['POST'])
def api_back():
"""撤销操作API"""
history = session.get('history', [])

if len(history) > 1:
history.pop()
matrix = list(history[-1])
session['matrix'] = matrix
session['history'] = history

# 为每个格子添加样式信息
tiles = []
for i, val in enumerate(matrix):
style = get_tile_style(val)
tiles.append({
'value': val,
'index': i,
'bg': style['bg'],
'color': style['color']
})

return jsonify({
'matrix': matrix,
'tiles': tiles,
'score': session.get('score', 0),
'success': True
})

return jsonify({
'success': False,
'message': '无法继续撤销'
})

@app.route('/api/new_game', methods=['POST'])
def api_new_game():
"""新游戏API"""
return api_init()

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
Loading