2048 game in python (no GUI)

Introduction

I did a simple python project by making the fun and simple game 2048. For anyone that does not know the game, its a simple game where you have a 4x4 matrix with tiles that initially have the number 2. we can slide the tiles in a direction to add it with a tile with the same number. Finally we need to get the number 2048.

I did this without a GUI. As GUI using python is still in my to-learn list

Explanation with code

So, first we need the 4x4 matrix which ill fill with 0 for default value

mat=[]
for i in range(4):
    mat.append([0]*4)
  • now that we have the grid we need to make two random tiles into the number two.

  • I created a function to do this

def add_2(mat):
    #r-> row c->column
    r,c=random.randint(0,3),random.randint(0,3)#picking random c and r
    while mat[r][c]!=0:# if picked (r,c) is not empty
    r,c=random.randint(0,3),random.randint(0,3)#pick other random numbers

    mat[r][c]=2 #after choosing the random cell make it 2
  • we will call this function twice initially to have two random tiles with the number two.
  • Now we need to have a way to move the tiles. i used the controls as given and took them as simple string inputs
print("W for up")
print("A for left")
print("D for right")
print("S for down")
  • To actually make the game work i made 4 functions one for moving in each direction
def up(mat):
    for i in range(1,4):#1 to 4 because the 0th row cannot move up
        for j in range(4):
        k=i
        l=j
        #keep moving it up if there are more spaces above it
        while mat[k][l]!=0  and k>0 and mat[k-1][l]==0:
             mat[k-1][l]=mat[k][l]
             mat[k][l]=0#make previous tile empty
             k-=1
        mat=merge(mat,'w')#To add ajacent similar numbers
        return mat

def right(mat):
    for i in range(4):
         for j in range(2,-1,-1):# checking from right to left to avoid complications
              k=i
              l=j
              while mat[k][l]!=0 and l<3 and mat[k][l+1]==0:
                   mat[k][l+1]=mat[k][l]
                   mat[k][l]=0
                   l+=1
     mat=merge(mat,'d')
     return mat
  • Two of them are given above.
  • The other two should be easy to make from these two full code is given at the end.
  • Now as you saw I've used a function called merge which i use to add two similar numbers that collide
def merge(mat,dir):
     if dir=='s':#merging down
           for i in range(2,-1,-1):#checking from bottom to top
                for j in range(4):
                     k=i
                     l=j
                      #If same number found multiply the lower one by two and continue    
                      while mat[k][l]!=0 and k<3 and mat[k+1][l]==mat[k][l]:
                           mat[k+1][l]*=2
                           mat[k][l]=0
                           k+=1#to check if there are more similar numbers below
     return mat
  • Here is one of the 4 merges the other three can be made with slight modifications. full code below
  • Great! now we can play the game, But how de we know if we won or lost?
  • I created a function to check that

def game_state(mat):
      for i in mat:
           for j in i:
                if j ==2048:#checking if there is a 2048 in the matrix
                     return "WON"
      for i in mat:
            for j in i:#checking if there are blank spots
                 if j==0:
                      return "NOT OVER"
      #next three nested loops check if there are any more plays possible
      for i in range(3):
            for j in range(3):
                 if mat[i][j]==mat[i+1][j] or mat[i][j]==mat[i][j+1]:
                       return "NOT OVER"
      for i in range(3):
             if mat[i][3]==mat[i+1][j]:
                 return "NOT OVER"
      for j in range(3):
              if mat[3][j]==mat[3][j+1]:
                  return "NOT OVER"
       #if there are no possible plays left GAME OVER
       return "OVER"
  • The above function works most of the time but does have a few bugs I cant figure out(Any help is appreciated).

  • Putting all this together we get a pretty functional game of 2048 without a gui complete code is given below

import random

def merge(mat,dir):
    if dir=='s':
        for i in range(2,-1,-1):
            for j in range(4):
                k=i
                l=j
                while mat[k][l]!=0 and k<3 and mat[k+1][l]==mat[k][l]:
                    mat[k+1][l]*=2
                    mat[k][l]=0
                    k+=1
        return mat
    elif dir=='w':
        for i in range(1,4):
            for j in range(4):
                k=i
                l=j
                while mat[k][l]!=0  and k>0 and mat[k-1][l]==mat[k][l]:
                    mat[k-1][l]*=2
                    mat[k][l]=0
                    k-=1
        return mat
    if dir=='a':
        for i in range(4):
            for j in range(1,4):
                k=i
                l=j
                while mat[k][l]!=0 and l>0 and mat[k][l-1]==mat[k][l]:
                    mat[k][l-1]*=2
                    mat[k][l]=0
                    l-=1
        return mat
    if dir=='d':
        for i in range(4):
            for j in range(2,-1,-1):
                k=i
                l=j
                while mat[k][l]!=0 and l<3 and mat[k][l+1]==mat[k][l]:
                    mat[k][l+1]*=2
                    mat[k][l]=0
                    l+=1
        return mat

def up(mat):
    for i in range(1,4):
        for j in range(4):
            k=i
            l=j
            while mat[k][l]!=0  and k>0 and mat[k-1][l]==0:
                mat[k-1][l]=mat[k][l]
                mat[k][l]=0
                k-=1
    mat=merge(mat,'w')
    return mat


def left(mat):
    for i in range(4):
        for j in range(1,4):
            k=i
            l=j
            while mat[k][l]!=0 and l>0 and mat[k][l-1]==0:
                mat[k][l-1]=mat[k][l]
                mat[k][l]=0
                l-=1
    mat=merge(mat,'a')
    return mat

def right(mat):
    for i in range(4):
        for j in range(2,-1,-1):
            k=i
            l=j
            while mat[k][l]!=0 and l<3 and mat[k][l+1]==0:
                mat[k][l+1]=mat[k][l]
                mat[k][l]=0
                l+=1
    mat=merge(mat,'d')
    return mat

def down(mat):
    temp=mat
    for i in range(2,-1,-1):
        for j in range(4):
            k=i
            l=j
            while mat[k][l]!=0 and k<3 and mat[k+1][l]==0:
                mat[k+1][l]=mat[k][l]
                mat[k][l]=0
                k+=1
    mat=merge(mat,'s')
    return mat 



def add_2(mat):
    r,c=random.randint(0,3),random.randint(0,3)
    while mat[r][c]!=0:
        r,c=random.randint(0,3),random.randint(0,3)

    mat[r][c]=2

def game_state(mat):
    for i in mat:
        for j in i:
            if j ==2048:
                return "WON"
    for i in mat:
        for j in i:
            if j==0:
                return "NOT OVER"
    for i in range(3):
        for j in range(3):
            if mat[i][j]==mat[i+1][j] or mat[i][j]==mat[i][j+1]:
                return "NOT OVER"
    for i in range(3):
        if mat[i][3]==mat[i+1][j]:
            return "NOT OVER"
    for j in range(3):
        if mat[3][j]==mat[3][j+1]:
            return "NOT OVER"

    return "OVER"

def start():

    mat=[]
    for i in range(4):
        mat.append([0]*4)
    add_2(mat)
    add_2(mat)
    print("W for up")
    print("A for left")
    print("D for right")
    print("S for down")
    while True:
        for i in mat:
            print(i)
        if game_state(mat)=="OVER":
            print("You lose")
            exit()
        elif game_state(mat)=="WON":
            print("Congratulations you win")
            exit()
        move=input("Move > ")
        if move.upper()=="W":
            mat= up(mat)
            mat=up(mat)
            add_2(mat)
        elif move.upper()=="A":
            left(mat)
            left(mat)
            add_2(mat)
        elif move.upper()=="D":
            right(mat)
            right(mat)
            add_2(mat)
        elif move.upper()=="S":
            down(mat)
            down(mat)
            add_2(mat)
        else:
            print("invalid input")


if __name__=="__main__":
    start()
  • Conclusion

  • So, i used this project as a way to learn more about how python works. and more about programming in general.

  • It was a simple, challenging project.

  • It doesn't work perfectly but it is playable.

  • I have a lot more to work on any and all advice is accepted thank you for taking you time to read through my very first step.

  • Github repository with 2048 and other simple projects -> https://github.com/P-M-Manmohan/Python

  • Twitter ->https://twitter.com/Manmohan652

Did you find this article valuable?

Support The Journey by becoming a sponsor. Any amount is appreciated!