Python code here.

NROWS =  10      # numer of brick rows 
NCOLS =  20      # number of brick columns
NCOLORS = 4      # 1 .. 5
B_WIDTH = 50     # brick width
FPS = 30         # frames per second
C_WIDTH =  NCOLS * B_WIDTH # canvas width
C_HEIGHT = NROWS * B_WIDTH # canvas height 

game = None

def setup():
    global game
    createCanvas(C_WIDTH, C_HEIGHT, P2D)
    rectMode(CENTER)
    frameRate(FPS)
    game = SameGame()
    
def draw(): 
    global game
    game.plotBoard()
                
def inCell(x,y):
    return (int(x) // (B_WIDTH + 1), int(y) // (B_WIDTH + 1))

def inCanvas(x,y):
    return  (0 <=  x <= C_WIDTH) and (0 <= y <= C_HEIGHT)

def mousePressed():
    global game
    x, y = mouseX, mouseY
    i, j = inCell(x,y)
    if (0 <= i < game.nc) and (0 <= j < game.nr):
        if not game.alone(i,j):
            game.floodfill(i,j)
            game.fall_all()

def keyPressed():
    global game
    if key == "n":
        game = SameGame()
    elif key in ("3","4","5"):
        colors = int(key)    
        game = SameGame(ncolors=colors)
         
cell_colors = {0:"black", 1:"green", 2:"blue", 
               3:"red", 4:"yellow", 5:"magenta"}

def cells(colors_only=False,ncolors=NCOLORS):
    ycent = B_WIDTH // 2
    pos =    [[0] * NROWS for col in range(NCOLS)]
    colors = [[0] * NROWS for col in range(NCOLS)]  
    # store cell centers coordinates and colors, columnwise
    for row in range(NCOLS):
        xcent = -B_WIDTH // 2
        for col in range(NROWS):   
            xcent += B_WIDTH
            pos[row][col] = (ycent,xcent)
            colors[row][col] = int(random(1, ncolors + 1))
        ycent += B_WIDTH
    if not colors_only:    
        return pos, colors
    return colors

class SameGame:
    def __init__(self,nr=NROWS, nc=NCOLS, ncolors=NCOLORS, 
                 colors=None, pos=None, score=0, score_diff=0, 
                 empty_cols = None, to_fill=None,score_corr=0):
        self.nr = nr
        self.nc = nc
        self.ncolors = ncolors
        self.to_fill = set()
        self.score = score
        self.score_diff = score_diff
        self.score_corr = score_corr
        self.empty_cols = []
        self.pos, self.colors = cells(ncolors=ncolors) 
        
    def plotBoard(self):
        for row in range(NROWS):
            for col in range(NCOLS):
                xc, yc = self.pos[col][row]   
                fill(cell_colors[self.colors[col][row]])
                rect(xc,yc,B_WIDTH,B_WIDTH)
                
        fill(255)
        textSize(20)
        textAlign(LEFT)
        text("Score: %d" %self.score, C_WIDTH-140, C_HEIGHT - 6)

        if self.endGame():
            if not self.score_corr: 
                self.score_correction_by_colors()
                self.score_corr = True
            self.compactLeft()
            textSize(36)
            textAlign(CENTER)
            text("End of Game",C_WIDTH // 2, C_HEIGHT // 2 - 10)

    def neighbours(self,i,j):
        possible = [(i-1,j),(i+1,j),(i,j-1),(i,j+1)]
        
        return [p for p in possible if (0 <= p[0] < self.nc) 
                                   and (0 <= p[1] < self.nr)]
    
    def alone(self,i,j):
        # i -column, j - row
        color = self.colors[i][j]
        res = True
        if color == 0:
            return res
        for k,l in self.neighbours(i,j):
            if self.colors[k][l] == color:
                res = False
                break
        return res        
    
    def floodfill(self, x, y):
        value = self.colors[x][y]
        edge = [(x,y)]    
        self.to_fill = set([x])
        self.colors[x][y] = 0
        self.score_diff = 1
        while edge:
            newedge = []
            for (x,y) in edge:
                for s,t in self.neighbours(x,y):
                    if self.colors[s][t] == value:
                        self.to_fill.add(s)
                        self.colors[s][t] = 0
                        self.score_diff += 1
                        newedge.append((s, t))
            edge = newedge

    def fall_column(self,col):
        if sum(self.colors[col]) == 0:
            self.empty_cols.append(col)
            return
        colored = []
        for row in range(self.nr):
            cc = self.colors[col][row]
            if cc:
                colored.append(cc)
        lc = len(colored)
        new_col = [0] *(self.nr - lc) + colored
        self.colors[col] = new_col         
                        
    def compactLeft(self):
        if self.empty_cols == []:
            return 
        for c in sorted(self.empty_cols,reverse=True): 
            for cindex in range(c,self.nc-1):
                    self.colors[cindex] = self.colors[cindex + 1]
            self.colors[self.nc-1] = [0] * self.nr
        self.empty_cols = []
          
    def fall_all(self):
        if self.to_fill == []:
            self.score_diff = 0
            return
        for col in self.to_fill:
            self.fall_column(col)
        self.compactLeft()
        nscore = self.score_diff - 1    
        self.score += (nscore * nscore)
        self.score_diff = 0
            
    def endGame(self):
        return sum([self.alone(i,j) for i in range(self.nc) 
                    for j in range(self.nr)]) == self.nr * self.nc

    def score_correction(self):
    
        rem = sum(bool(self.colors[c][r]) for c in range(self.nc) 
                                          for r in range(self.nr)) 
        if rem == 0:
            self.score += 1000
        else:
            self.score -= (rem-1)*(rem-1)
            self.score = max(0,self.score)

    def score_correction_by_colors(self):
        crange = range(1,self.ncolors + 1) 
        rest = {c:0 for c in crange}
        for col in range(self.nc):
            for row in range(self.nr):
                color = self.colors[col][row]
                if color: 
                    rest[color] += 1
                
        rem = 0
        for c in crange:
            ncells = rest[c]
            if ncells:
                rem += (ncells - 1) * (ncells - 1) 
        if sum(rest.values()) == 0:
            self.score += 1000
        else:
            self.score -= rem