找回密码
 立即注册
搜索
热搜: 活动 交友
查看: 297|回复: 5

Threes!游戏及其AI的Python实现

[复制链接]
39 金钱 回复本帖可获得 3 金钱奖励! 每人限 2 次(中奖概率 80%)

9

主题

20

回帖

720

积分

版主

积分
720
发表于 7-5-2025 14:39:44 | 显示全部楼层 |阅读模式

〇、 游戏简介


Threes!
是一款由Sirvo LLC开发并发行的益智类游戏,于2014年2月10日发布,游戏平台为iOS。



Threes!为2048的灵感来源。


Threes!曾获得2014年度App Store中国区iPhone年度最佳游戏的荣誉。






一、 游戏规则

它的主要规则如下:

1. 盘面大小为4*4



2. 盘面由1,2,3,6,12,24,48,...,3072,6144,12288和空格组成,合成12288后游戏通关 (人力打到3072就很强了)


3. 相邻的1和2可以合成3,相邻的相同的3*2^k可以合成3*2^(k+1)
  例如: 3和3合成6,6和6合成12

4. 每次可以将盘面向上下左右中的一个方向移动,其间每一行每一列都有可能可以移动或无法移动





5. (每次移动)(合并)(移动方向上)(无法平移)且(可以合并)的(第一组相邻数字块)并(平移剩下数字块与空格)并(添加一块空格)
  例如: 1212→0123 1210→0121 1332→0162 3033→0306


6. 下一块为1,2,3或大数字块,其中大数字块为3选1,中间那个的取值范围为[12,maxnum/16]
  例如: maxnum=192,大数字块必为[[6,12,24]三选一];
      maxnum=1536,大数字块为[[6,12,24]三选一,[12,24,48]三选一,[24,48,96]三选一,[48,96,192]三选一]四选一


7. 盘面上如果1比2多4块,则下一块必不为1,反之亦然。


8. 下一块必出现在下一次发生移动的随机一行内


9. 无法移动则游戏结束


10. 开局时有一个大数字块和7个1,2,3数字块和8个空格 (本人代码实现时将大数字块设为192)






二、游戏技巧


欢迎大家讨论,并贴出自己的最高分!






三、代码实现


因为希望有同学也可以做出这个游戏的AI,所以本贴直接贴出可运行的无AI版代码。


  1. <blockquote>import random,pygame,sys,time
复制代码




四、实现AI





上面四张图是同一局游戏的截图,已经实现了AI合成6144+3072 (可以上手一下看看有多难)


附上[url=【Threes! AI 合成6144+3072】https://www.bilibili.com/video/BV1zd3bzoEvL]视频链接[/url] [url=【Threes! AI 合成6144+3072】https://www.bilibili.com/video/BV1zd3bzoEvL]【Threes! AI 合成6144+3072】https://www.bilibili.com/video/BV1zd3bzoEvL[/url] (在挑战高分的过程中可以借鉴打法)


回帖>=10 或 回帖不同人数>=5 或 有同学从192手打出1536: 给出基础AI实现思路


回帖>=25 或 回帖不同人数>=10: 给出基础AI代码截图


有同学做出从192合成1536的AI 或 从192手打出3072: 给出进阶AI实现思路 (手打记得录屏!)

ps: 该AI开发难度略低于五子棋AI,简单易上手

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

评分

参与人数 3威望 +5 金钱 +45 收起 理由
C0mp1ler + 20 很给力!
littleblackLB + 20 赞一个!
脆脆大奶酪 + 5 + 5 赞一个!

查看全部评分

7

主题

19

回帖

451

积分

高级程序员

积分
451
发表于 7-5-2025 15:24:51 | 显示全部楼层

回帖奖励 +3 金钱

1+1≠2真是太出生了

7

主题

19

回帖

451

积分

高级程序员

积分
451
发表于 7-5-2025 15:26:44 | 显示全部楼层

回帖奖励 +3 金钱


哦不对,2+2也≠4

7

主题

19

回帖

451

积分

高级程序员

积分
451
发表于 7-5-2025 18:26:06 | 显示全部楼层
挑战最低分

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

9

主题

20

回帖

720

积分

版主

积分
720
 楼主| 发表于 7-15-2025 18:05:24 | 显示全部楼层

9

主题

20

回帖

720

积分

版主

积分
720
 楼主| 发表于 7-15-2025 18:05:57 | 显示全部楼层
  1. import random,pygame,sys,time

  2. def copy(board):return [row[:] for row in board] #copies a board

  3. def maxnum(board):return max(max(row) for row in board) #finds the max number in a board

  4. def rr(board):return [list(row) for row in zip(*board[::-1])] #rotates a board clockwise

  5. def flp(board):return [[board[j][i] for j in range(len(board))] for i in range(len(board[0]))] #flips a board diagonally

  6. def score(board):return sum(3**(x-2) for row in board for x in row if x>2) #scores a board
  7.    
  8. def up(board): #moves a board upwards
  9.     nBoard=copy(board)
  10.     moved=[0,0,0,0] #moved columns
  11.     for y in range(4): #iterates all 4 columns
  12.         for x in range(3): #iterates from 1st row to the 3rd row
  13.             if nBoard[x][y]==0 and nBoard[x+1][y]!=0: #an empty block with a non-empty neighbor block below it
  14.                 moved[y]=1
  15.                 nBoard[x][y]=nBoard[x+1][y]
  16.             elif nBoard[x][y]==1 and nBoard[x+1][y]==2 or nBoard[x][y]==2 and nBoard[x+1][y]==1: #merge 1 and 2
  17.                 moved[y]=1
  18.                 nBoard[x][y]=3
  19.             elif nBoard[x][y]==nBoard[x+1][y] and nBoard[x][y]>=3: #merge same numbers
  20.                 moved[y]=1
  21.                 nBoard[x][y]+=1
  22.             if moved[y]==1: #move numbers below
  23.                 for i in range(x+1,3):
  24.                     nBoard[i][y]=nBoard[i+1][y]
  25.                 nBoard[3][y]=0
  26.                 break
  27.     return nBoard,moved

  28. def down(board):
  29.     nBoard,moved=up(rr(rr(board)))
  30.     return rr(rr(nBoard)),moved[::-1]

  31. def left(board):
  32.     nBoard,moved=up(rr(board))
  33.     return rr(rr(rr(nBoard))),moved[::-1]

  34. def right(board):
  35.     nBoard,moved=up(rr(rr(rr(board))))
  36.     return rr(nBoard),moved

  37. def next(board,moved):
  38.     if sum(moved)==0:
  39.         return nNum
  40.     ones=sum(row.count(1) for row in board)
  41.     twos=sum(row.count(2) for row in board)
  42.     if twos-ones>=4: #no twos if already many twos
  43.         weights=[20,0,10,1]
  44.     elif ones-twos>=4: #no ones if already many ones
  45.         weights=[0,20,10,1]
  46.     else:
  47.         weights=[10+2*(twos-ones),10+2*(ones-twos),10,1] #weight also floats depending on current ones and twos
  48.     n=random.choices([1,2,3,4],weights=weights,k=1)[0]
  49.     if n!=4:
  50.         return n
  51.     m=maxnum(Board)
  52.     mid=random.randint(5,m-4)
  53.     return mid

  54. def insert(board,moved,nNum,dir):
  55.     if sum(moved)==0: #unable to insert
  56.         return board
  57.     if nNum>=5:
  58.         nNum=random.choice([nNum-1,nNum,nNum+1])
  59.     nBoard=copy(board)
  60.     i=random.choices([0,1,2,3],weights=moved,k=1)[0] #choses a moved row or column to insert
  61.     if dir==0:
  62.         nBoard[3][i]=nNum
  63.     if dir==1:
  64.         nBoard[0][i]=nNum
  65.     if dir==2:
  66.         nBoard[i][3]=nNum
  67.     if dir==3:
  68.         nBoard[i][0]=nNum
  69.     return nBoard

  70. def draw(scr):
  71.     scr.fill((235,235,235))
  72.     pygame.draw.line(scr,(23,23,23),(10,10),(410,10))
  73.     pygame.draw.line(scr,(23,23,23),(10,160),(410,160))
  74.     pygame.draw.line(scr,(23,23,23),(10,310),(410,310))
  75.     pygame.draw.line(scr,(23,23,23),(10,460),(410,460))
  76.     pygame.draw.line(scr,(23,23,23),(10,610),(410,610))
  77.     pygame.draw.line(scr,(23,23,23),(10,10),(10,610))
  78.     pygame.draw.line(scr,(23,23,23),(110,10),(110,610))
  79.     pygame.draw.line(scr,(23,23,23),(210,10),(210,610))
  80.     pygame.draw.line(scr,(23,23,23),(310,10),(310,610))
  81.     pygame.draw.line(scr,(23,23,23),(410,10),(410,610)) #draws the grids
  82.     for x in range(4):
  83.         for y in range(4):
  84.             num=Board[x][y] #draws tiles
  85.             if num==0:
  86.                 color2=(220,220,220)
  87.                 pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
  88.                 continue
  89.             if num>2:
  90.                 color1=(23,23,23)
  91.                 color2=(242,242,242)
  92.                 pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
  93.                 num=3*2**(num-3)
  94.             if num==1:
  95.                 color1=(255,235,235)
  96.                 color2=(23,180,255)
  97.                 pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
  98.             if num==2:
  99.                 color1=(235,255,255)
  100.                 color2=(255,90,135)
  101.                 pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
  102.             d=len(str(num))
  103.             if d==1:
  104.                 s=50
  105.             if d==2 or d==3:
  106.                 s=40
  107.             if d==4:
  108.                 s=32
  109.             if d>=5:
  110.                 s=26
  111.             font=pygame.font.SysFont('Monaco',s)
  112.             img=font.render(str(num),True,color1,color2)
  113.             img_rect=img.get_rect()
  114.             img_rect.center=(60+100*y,85+150*x)
  115.             scr.blit(img,img_rect)
  116.     font=pygame.font.SysFont('Monaco',45)
  117.     img=font.render('Next Num',True,(23,23,23),(235,235,235))
  118.     img_rect=img.get_rect()
  119.     img_rect.center=(580,80)
  120.     scr.blit(img,img_rect)
  121.     if nNum<=3:
  122.         font=pygame.font.SysFont('Monaco',50)
  123.         color=(23,23,23)
  124.         if nNum==1:
  125.             color=(40,40,192)
  126.         if nNum==2:
  127.             color=(192,40,40)
  128.         img=font.render(str(nNum),True,color,(235,235,235))
  129.         img_rect=img.get_rect()
  130.         img_rect.center=(580,170)
  131.         scr.blit(img,img_rect)
  132.     if nNum>=5: #here 5 stands for 6,12,24, 8 stands for 48,96,192, etc.
  133.         color=(23,23,23)
  134.         n=3*2**(nNum-4)
  135.         font=pygame.font.SysFont('Monaco',50-8*(n>100))
  136.         img=font.render(str(n),True,color,(235,235,235))
  137.         img_rect=img.get_rect()
  138.         img_rect.center=(490,170)
  139.         scr.blit(img,img_rect)
  140.         n=3*2**(nNum-3)
  141.         font=pygame.font.SysFont('Monaco',50-8*(n>100))
  142.         img=font.render(str(n),True,color,(235,235,235))
  143.         img_rect=img.get_rect()
  144.         img_rect.center=(580,170)
  145.         scr.blit(img,img_rect)
  146.         n=3*2**(nNum-2)
  147.         font=pygame.font.SysFont('Monaco',50-8*(n>100))
  148.         img=font.render(str(n),True,color,(235,235,235))
  149.         img_rect=img.get_rect()
  150.         img_rect.center=(670,170)
  151.         scr.blit(img,img_rect)
  152.     font=pygame.font.SysFont('Monaco',45)
  153.     img=font.render('Score',True,(23,23,23),(235,235,235))
  154.     img_rect=img.get_rect()
  155.     img_rect.center=(580,250)
  156.     scr.blit(img,img_rect)
  157.     img=font.render(str(score(Board)),True,(23,23,23),(235,235,235)) #draws the score
  158.     img_rect=img.get_rect()
  159.     img_rect.center=(580,340)
  160.     scr.blit(img,img_rect)
  161.     pygame.display.update()

  162. Board=[[0,0,1,1],
  163.        [2,3,0,2],
  164.        [0,0,3,0],
  165.        [1,1,0,9]] #initial board
  166. moved=[1,1,1,1]
  167. nNum=next(Board,moved)
  168. pygame.init()
  169. screen=pygame.display.set_mode((800,620))
  170. pygame.display.set_caption('Threes!'*random.choice([1,3]))
  171. draw(screen)

  172. while True:
  173.     for event in pygame.event.get():
  174.         if event.type==pygame.QUIT:
  175.             pygame.quit()
  176.             sys.exit()
  177.         elif event.type==pygame.KEYDOWN:
  178.             if event.key==pygame.K_UP:
  179.                 Board,moved=up(Board)
  180.                 Board=insert(Board,moved,nNum,0)
  181.             elif event.key==pygame.K_DOWN:
  182.                 Board,moved=down(Board)
  183.                 Board=insert(Board,moved,nNum,1)
  184.             elif event.key==pygame.K_LEFT:
  185.                 Board,moved=left(Board)
  186.                 Board=insert(Board,moved,nNum,2)
  187.             elif event.key==pygame.K_RIGHT:
  188.                 Board,moved=right(Board)
  189.                 Board=insert(Board,moved,nNum,3)
  190.             elif event.key==pygame.K_BACKSPACE: #resets game
  191.                 Board=[[0,0,1,1],
  192.                        [2,3,0,2],
  193.                        [0,0,3,0],
  194.                        [1,1,0,9]]
  195.                 moved=[1,1,1,1]
  196.                 nNum=next(Board,moved)
  197.                 draw(screen)
  198.             else:
  199.                 continue
  200.             nNum=next(Board,moved)
  201.             draw(screen)
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|RealDevClub ( 沪ICP备2024093864号-1 )

GMT+8, 7-24-2025 03:59 , Processed in 0.073014 second(s), 29 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表