输入“/”快速插入内容

[算法学习]2048小游戏理解算法对应用性能的影响

2024年3月9日创建
2271
2615
5
0
本文讨论了作者以制作 5*5 的 2048 小游戏为背景,用 Pygame 搭建游戏要素,为 AI 提供多种算法支持实现自动游戏,并探讨超参数调整及新增算法解决方案的相关内容。关键要点包括:
1.
游戏开发背景:作者因写算法内容疲惫,为调剂学习 Pygame 做 2048 小游戏,后想让 AI 代玩并开源供大家体验。
2.
游戏搭建:用 Pygame 安装依赖,搭建游戏框架,设定游戏规则、界面绘制等相关类与函数。
3.
AI 算法支持:使用贪心算法并优化,通过多个函数计算启发式得分、棋盘得分、平滑度得分等,实现向前看逻辑评估移动策略。
4.
游戏主循环:用 pygame 库实现游戏可视化,在主循环中调用 AI 移动函数自动运行游戏。
5.
目前结果:算法最高合成到 4096,后续还会探索如蒙特卡洛树(MCTS)等更高级算法。
6.
超参数调整:调整空格、最大瓦片分数权重等超参数,会影响 AI 决策策略和游戏表现。
7.
新增算法:增加向左和向上移动的评分权重,影响 AI 决策以提高获得高分几率 。
🤖
作者:吵爷
吵爷主攻算法,会做一些数据分析。大家感兴趣可以一起交流
这个无聊的想法产生的背景
前阵子写了一篇BP算法入门,由于公式太多,遭到了大家的一致批评~然后最近肝Transformer也有点伤,为了调剂下脑子,去稍微学了点Pygame,做点弹球游戏这种没什么用的东西玩一玩。
偶然想到2048,之前玩的都是4*4的,有点不过瘾,于是想自己做一个5*5的,做出来以后又觉得自己玩太费时间了,就产生了让AI帮我玩的想法...人总是懒的。
简单和GPT聊了下,发现其实还真可以,带入一些简单的算法,就可以让AI把游戏跑起来了,虽然性能还是不如人来玩,但也是可以慢慢进步的。玩了两天发现,其实这东西可以挺直观的感受算法给模型性能带来的提升,对初学者而言比看数学公式要友好不少,所以把它开源出来供大家体验。目前还没用到比较高级的算法,只是在基础逻辑上做了一些优化,后面我会继续做。
效果视频⬆️
用Pygame搭建游戏基本要素
安装依赖
目前用到的前置依赖(后面涉及新算法后还会有调整)
import pygame
import sys
import random
import copy
大家可以根据自己的Python安装缺失的库,这种简易的游戏用pygame来开发还是挺高效的。
写出游戏框架
游戏界面的设置比较简单,我这里就先不细讲了,大家可以直接看代码。总体来讲就是设置一个5*5的区域,在空白处随机生成2或者4数字的方格,设定合并和移动规则,最后把这些东西都画出来。由于比较懒,没有写分数牌,步数计算,重新开始之类的按钮,大家有需要可以让GPT帮忙写一个。
class Game2048:
def __init__(self, size=5):
self.size = size
self.board = [[0] * size for _ in range(size)]
self.add_tile()
self.add_tile()
def add_tile(self):
empty_cells = [(r, c) for r in range(self.size) for c in range(self.size) if self.board[r][c] == 0]
if empty_cells:
row, col = random.choice(empty_cells)
self.board[row][col] = random.choice([2, 4])
def compress(self, row):
new_row = [i for i in row if i != 0]
new_row += [0] * (self.size - len(new_row))
return new_row
def merge(self, row):
for i in range(self.size - 1):
if row[i] == row[i + 1] and row[i] != 0:
row[i] *= 2
row[i + 1] = 0
return self.compress(row)
def reverse(self, row):
return row[::-1]
def transpose(self):
self.board = [list(row) for row in zip(*self.board)]
def move_up(self):
self.transpose()
for i in range(self.size):
self.board[i] = self.compress(self.board[i])
self.board[i] = self.merge(self.board[i])
self.transpose()
def move_down(self):
self.transpose()
for i in range(self.size):
self.board[i] = self.reverse(self.board[i])
self.board[i] = self.compress(self.board[i])
self.board[i] = self.merge(self.board[i])
self.board[i] = self.reverse(self.board[i])
self.transpose()
def move_left(self):
for i in range(self.size):
self.board[i] = self.compress(self.board[i])
self.board[i] = self.merge(self.board[i])
def move_right(self):
for i in range(self.size):
self.board[i] = self.reverse(self.board[i])
self.board[i] = self.compress(self.board[i])
self.board[i] = self.merge(self.board[i])
self.board[i] = self.reverse(self.board[i])
def is_game_over(self):
for i in range(self.size):
for j in range(self.size):
if self.board[i][j] == 0:
return False
if i + 1 < self.size and self.board[i][j] == self.board[i + 1][j]:
return False
if j + 1 < self.size and self.board[i][j] == self.board[i][j + 1]:
return False
return True
def get_empty_cell_count(self):
return sum(row.count(0) for row in self.board)
def draw_board(game, screen, font):
for row in range(game.size):
for col in range(game.size):
value = game.board[row][col]
# 根据方块的值选择不同的颜色
if value == 0:
color = pygame.Color(120, 110, 102) # 空方块的颜色
elif value <= 4:
color = pygame.Color(238, 228, 218)
elif value <= 8:
color = pygame.Color(237, 224, 200)
elif value <= 16:
color = pygame.Color(242, 177, 121)
elif value <= 32:
color = pygame.Color(245, 149, 99)
elif value <= 64:
color = pygame.Color(246, 124, 95)
elif value <= 128:
color = pygame.Color(246, 94, 59)
else:
color = pygame.Color(237, 207, 114) # 更大的数字用更鲜艳的颜色
pygame.draw.rect(screen, color, (col * 100 + 10, row * 100 + 10, 90, 90))
if value != 0:
# 根据方块的值调整数字颜色
text_color = pygame.Color(255, 255, 255) if value > 4 else pygame.Color(0, 0, 0)
text_surface = font.render(f'{value}', True, text_color)
text_rect = text_surface.get_rect(center=(col * 100 + 55, row * 100 + 55))
screen.blit(text_surface, text_rect)