import random,pygame,sys,time
def copy(board):return [row[:] for row in board] #copies a board
def maxnum(board):return max(max(row) for row in board) #finds the max number in a board
def rr(board):return [list(row) for row in zip(*board[::-1])] #rotates a board clockwise
def flp(board):return [[board[j][i] for j in range(len(board))] for i in range(len(board[0]))] #flips a board diagonally
def score(board):return sum(3**(x-2) for row in board for x in row if x>2) #scores a board
def up(board): #moves a board upwards
nBoard=copy(board)
moved=[0,0,0,0] #moved columns
for y in range(4): #iterates all 4 columns
for x in range(3): #iterates from 1st row to the 3rd row
if nBoard[x][y]==0 and nBoard[x+1][y]!=0: #an empty block with a non-empty neighbor block below it
moved[y]=1
nBoard[x][y]=nBoard[x+1][y]
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
moved[y]=1
nBoard[x][y]=3
elif nBoard[x][y]==nBoard[x+1][y] and nBoard[x][y]>=3: #merge same numbers
moved[y]=1
nBoard[x][y]+=1
if moved[y]==1: #move numbers below
for i in range(x+1,3):
nBoard[i][y]=nBoard[i+1][y]
nBoard[3][y]=0
break
return nBoard,moved
def down(board):
nBoard,moved=up(rr(rr(board)))
return rr(rr(nBoard)),moved[::-1]
def left(board):
nBoard,moved=up(rr(board))
return rr(rr(rr(nBoard))),moved[::-1]
def right(board):
nBoard,moved=up(rr(rr(rr(board))))
return rr(nBoard),moved
def next(board,moved):
if sum(moved)==0:
return nNum
ones=sum(row.count(1) for row in board)
twos=sum(row.count(2) for row in board)
if twos-ones>=4: #no twos if already many twos
weights=[20,0,10,1]
elif ones-twos>=4: #no ones if already many ones
weights=[0,20,10,1]
else:
weights=[10+2*(twos-ones),10+2*(ones-twos),10,1] #weight also floats depending on current ones and twos
n=random.choices([1,2,3,4],weights=weights,k=1)[0]
if n!=4:
return n
m=maxnum(Board)
mid=random.randint(5,m-4)
return mid
def insert(board,moved,nNum,dir):
if sum(moved)==0: #unable to insert
return board
if nNum>=5:
nNum=random.choice([nNum-1,nNum,nNum+1])
nBoard=copy(board)
i=random.choices([0,1,2,3],weights=moved,k=1)[0] #choses a moved row or column to insert
if dir==0:
nBoard[3][i]=nNum
if dir==1:
nBoard[0][i]=nNum
if dir==2:
nBoard[i][3]=nNum
if dir==3:
nBoard[i][0]=nNum
return nBoard
def draw(scr):
scr.fill((235,235,235))
pygame.draw.line(scr,(23,23,23),(10,10),(410,10))
pygame.draw.line(scr,(23,23,23),(10,160),(410,160))
pygame.draw.line(scr,(23,23,23),(10,310),(410,310))
pygame.draw.line(scr,(23,23,23),(10,460),(410,460))
pygame.draw.line(scr,(23,23,23),(10,610),(410,610))
pygame.draw.line(scr,(23,23,23),(10,10),(10,610))
pygame.draw.line(scr,(23,23,23),(110,10),(110,610))
pygame.draw.line(scr,(23,23,23),(210,10),(210,610))
pygame.draw.line(scr,(23,23,23),(310,10),(310,610))
pygame.draw.line(scr,(23,23,23),(410,10),(410,610)) #draws the grids
for x in range(4):
for y in range(4):
num=Board[x][y] #draws tiles
if num==0:
color2=(220,220,220)
pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
continue
if num>2:
color1=(23,23,23)
color2=(242,242,242)
pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
num=3*2**(num-3)
if num==1:
color1=(255,235,235)
color2=(23,180,255)
pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
if num==2:
color1=(235,255,255)
color2=(255,90,135)
pygame.draw.rect(scr,color2,(100*y+20,150*x+20,80,130))
d=len(str(num))
if d==1:
s=50
if d==2 or d==3:
s=40
if d==4:
s=32
if d>=5:
s=26
font=pygame.font.SysFont('Monaco',s)
img=font.render(str(num),True,color1,color2)
img_rect=img.get_rect()
img_rect.center=(60+100*y,85+150*x)
scr.blit(img,img_rect)
font=pygame.font.SysFont('Monaco',45)
img=font.render('Next Num',True,(23,23,23),(235,235,235))
img_rect=img.get_rect()
img_rect.center=(580,80)
scr.blit(img,img_rect)
if nNum<=3:
font=pygame.font.SysFont('Monaco',50)
color=(23,23,23)
if nNum==1:
color=(40,40,192)
if nNum==2:
color=(192,40,40)
img=font.render(str(nNum),True,color,(235,235,235))
img_rect=img.get_rect()
img_rect.center=(580,170)
scr.blit(img,img_rect)
if nNum>=5: #here 5 stands for 6,12,24, 8 stands for 48,96,192, etc.
color=(23,23,23)
n=3*2**(nNum-4)
font=pygame.font.SysFont('Monaco',50-8*(n>100))
img=font.render(str(n),True,color,(235,235,235))
img_rect=img.get_rect()
img_rect.center=(490,170)
scr.blit(img,img_rect)
n=3*2**(nNum-3)
font=pygame.font.SysFont('Monaco',50-8*(n>100))
img=font.render(str(n),True,color,(235,235,235))
img_rect=img.get_rect()
img_rect.center=(580,170)
scr.blit(img,img_rect)
n=3*2**(nNum-2)
font=pygame.font.SysFont('Monaco',50-8*(n>100))
img=font.render(str(n),True,color,(235,235,235))
img_rect=img.get_rect()
img_rect.center=(670,170)
scr.blit(img,img_rect)
font=pygame.font.SysFont('Monaco',45)
img=font.render('Score',True,(23,23,23),(235,235,235))
img_rect=img.get_rect()
img_rect.center=(580,250)
scr.blit(img,img_rect)
img=font.render(str(score(Board)),True,(23,23,23),(235,235,235)) #draws the score
img_rect=img.get_rect()
img_rect.center=(580,340)
scr.blit(img,img_rect)
pygame.display.update()
Board=[[0,0,1,1],
[2,3,0,2],
[0,0,3,0],
[1,1,0,9]] #initial board
moved=[1,1,1,1]
nNum=next(Board,moved)
pygame.init()
screen=pygame.display.set_mode((800,620))
pygame.display.set_caption('Threes!'*random.choice([1,3]))
draw(screen)
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_UP:
Board,moved=up(Board)
Board=insert(Board,moved,nNum,0)
elif event.key==pygame.K_DOWN:
Board,moved=down(Board)
Board=insert(Board,moved,nNum,1)
elif event.key==pygame.K_LEFT:
Board,moved=left(Board)
Board=insert(Board,moved,nNum,2)
elif event.key==pygame.K_RIGHT:
Board,moved=right(Board)
Board=insert(Board,moved,nNum,3)
elif event.key==pygame.K_BACKSPACE: #resets game
Board=[[0,0,1,1],
[2,3,0,2],
[0,0,3,0],
[1,1,0,9]]
moved=[1,1,1,1]
nNum=next(Board,moved)
draw(screen)
else:
continue
nNum=next(Board,moved)
draw(screen)