본문 바로가기
Project

[Python][미니 프로젝트] 2048

by wave_m 2020. 10. 12.
728x90

프로젝트명 : 2048

진행 기간 : 2020 7월 21일 ~ 2020년 7월 22일(2일)

개발 인원 : 3명

사용 기술 : Python

 

 


2048

 

초기화면

 

 

간단한 게임 룰 : 

 

1. 처음 시작할 때는 2 블록이 존재한다.

2. 키보드를 작동하면 모든 블록이 슬라이딩 한 방향으로 움직일 수 없을 때까지 이동한다.

   즉, 위로 슬라이딩할 경우 모든 블록이 위로 이동한다. 슬라이딩 후에는 랜덤한 빈 공간에 2 또는 4 블록이 생성된다.

3. 숫자가 같은 블록이 슬라이딩할 때 부딪치면 블록이 합체되면서 숫자가 두 배가 된다.

   예를 들면, 4 블록이 위/아래로 나란히 있을 때 위로 슬라이딩하면 4 블록 2개가 8 블록 하나로 합쳐지고 원래 있던 4 블럭 두개는 사라진다.

4. 위/아래/좌/우 모든 방향으로 슬라이딩을 못하면 게임이 종료되고 반대로 게임이 종료되기 전에 2048 블록을 만들면 성공한다.

 

 

개발 환경 : python 3.6

 

 

pip install pygame

이 코드를 꼭 cmd 관리자 모드로 열고 써야 코드가 돌아가니 참고해주세요 !

 

 

 

colors.py

GRID_COLOR = "#a39489"
EMPTY_CELL_COLOR = "#c2b3a9"
SCORE_LABEL_FONT = ("Verdana", 24)
SCORE_FONT = ("Helvetica", 36, "bold")
GAME_OVER_FONT = ("Helvetica", 42, "bold")
GAME_OVER_FONT_COLOR = "#ffffff"
WINNER_BG = "#ffcc00"
LOSER_BG = "#a39489"

CELL_COLORS = {
    2: "#fcefe6",
    4: "#f2e8cb",
    8: "#f5b682",
    16: "#f29446",
    32: "#ff775c",
    64: "#e64c2e",
    128: "#ede291",
    256: "#fce130",
    512: "#ffdb4a",
    1024: "#f0b922",
    2048: "#fad74d"
}
        
CELL_NUMBER_COLOR = {
    2: "#695c57",
    4: "#695c57",
    8: "#ffffff",
    16: "#ffffff",
    32: "#ffffff",
    64: "#ffffff",
    128: "#ffffff",
    256: "#ffffff",
    512: "#ffffff",
    1024: "#ffffff",
    2048: "#ffffff"
}

CELL_NUMBER_FONTS = {
    2: ("Helvetica", 55, "bold"),
    4: ("Helvetica", 55, "bold"),
    8: ("Helvetica", 55, "bold"),
    16: ("Helvetica", 50, "bold"),
    32: ("Helvetica", 50, "bold"),
    64: ("Helvetica", 50, "bold"),
    128: ("Helvetica", 45, "bold"),
    256: ("Helvetica", 45, "bold"),
    512: ("Helvetica", 45, "bold"),
    1024: ("Helvetica", 40, "bold"),
    2048: ("Helvetica", 40, "bold"),
}

 

 

 

 

2048.py

import tkinter as tk
import colors as c
import random
import pygame
import time

class Game(tk.Frame) :
    def __init__(self) :
        tk.Frame.__init__(self)
        self.grid()
        self.master.title('2048')
        
        self.main_grid = tk.Frame(self, bg = c.GRID_COLOR, 
                                  bd = 3, width = 600, height = 600)
        self.main_grid.grid(pady = (100, 0))
        self.make_GUI()
        
        self.playmusic()
        self.master.bind("<Left>", self.left)
        self.master.bind("<Right>", self.right)
        self.master.bind("<Up>", self.up)
        self.master.bind("<Down>", self.down)
        self.start_game()
        
        self.mainloop()
        
    def make_GUI(self) :
        # make grid 
        self.cells = []
        for i in range(4) : 
            row = []
            for j in range(4) :
                cell_frame = tk.Frame(self.main_grid, 
                                      bg = c.EMPTY_CELL_COLOR, 
                                      width = 150, height = 150)
                cell_frame.grid(row=i, column=j, padx=5, pady=5)
                cell_number = tk.Label(self.main_grid, bg=c.EMPTY_CELL_COLOR)
                cell_number.grid(row=i, column=j)
                cell_data = {'frame': cell_frame, 'number': cell_number}
                row.append(cell_data)
            self.cells.append(row)
            
        # 점수 기록
        score_frame = tk.Frame(self)
        score_frame.place(relx=0.5, y=45, anchor='center')
        tk.Label(score_frame, text='Score', 
                 font=c.SCORE_LABEL_FONT).grid(row=0)
        self.score_label = tk.Label(score_frame, text='0',
                                    font=c.SCORE_FONT)
        self.score_label.grid(row=1)

    
    def start_game(self) :
        self.matrix = [[0] * 4 for _ in range(4)]
        
        row = random.randint(0, 3)
        col = random.randint(0, 3)
        self.matrix[row][col] = 2
        self.cells[row][col]["frame"].configure(bg=c.CELL_COLORS[2])
        self.cells[row][col]["number"].configure(bg=c.CELL_COLORS[2], 
                  fg=c.CELL_NUMBER_COLOR[2], 
                  font=c.CELL_NUMBER_FONTS[2], 
                  text="2")
        
        while(self.matrix[row][col] != 0) :
            row = random.randint(0, 3)
            col = random.randint(0, 3)
        self.matrix[row][col] = 2
        self.cells[row][col]["frame"].configure(bg=c.CELL_COLORS[2])
        self.cells[row][col]["number"].configure(bg=c.CELL_COLORS[2], 
                  fg=c.CELL_NUMBER_COLOR[2], 
                  font=c.CELL_NUMBER_FONTS[2], 
                  text="2")       
        
        self.score = 0   
        self.playmusic()

    
    def stack(self) :
        new_matrix = [[0] * 4 for _ in range(4)]
        for i in range(4) :
            fill_position = 0
            for j in range(4) :
                if self.matrix[i][j] != 0 :
                    new_matrix[i][fill_position] = self.matrix[i][j]
                    fill_position += 1 
        self.matrix = new_matrix
        
    def combine(self) :
        for i in range(4) :
            for j in range(3) :
                if self.matrix[i][j] != 0 and self.matrix[i][j] == self.matrix[i][j+1] :
                    self.matrix[i][j] *= 2 
                    self.matrix[i][j+1] = 0 
                    self.score += self.matrix[i][j] 
 
                   
    def reverse(self) :
        new_matrix = []
        for i in range(4) :
            new_matrix.append([])
            for j in range(4) :
                new_matrix[i].append(self.matrix[i][3-j])
        self.matrix = new_matrix
        
    def transpose(self) :
        new_matrix = [[0] * 4 for _ in range(4)]
        for i in range(4) :
            for j in range(4) :
                new_matrix[i][j] = self.matrix[j][i]
        self.matrix = new_matrix


    def add_new_tile(self) :
        if any(0 in row for row in self.matrix) :
            row = random.randint(0, 3)
            col = random.randint(0, 3)
            while(self.matrix[row][col] != 0) :
                row = random.randint(0, 3)
                col = random.randint(0, 3)
            self.matrix[row][col] = random.choice([2, 4])
        
    
    def update_GUI(self) :
        for i in range(4) :
            for j in range(4) :
                cell_value = self.matrix[i][j]
                if cell_value == 0 :
                    self.cells[i][j]["frame"].configure(bg=c.EMPTY_CELL_COLOR)
                    self.cells[i][j]["number"].configure(bg=c.EMPTY_CELL_COLOR, text = "")
                else : 
                    self.cells[i][j]["frame"].configure(bg=c.CELL_COLORS[cell_value])
                    self.cells[i][j]["number"].configure(bg=c.CELL_COLORS[cell_value],
                              fg=c.CELL_NUMBER_COLOR[cell_value], font=c.CELL_NUMBER_FONTS[cell_value],
                              text=str(cell_value))
                    
        self.score_label.configure(text=self.score)
        self.update_idletasks()
        
        
        # 상하좌우 이동 함수
        
    def left(self, event) :
        self.stack()
        self.combine()
        self.stack()
        self.add_new_tile()
        self.update_GUI()
        self.game_over()
            
    def right(self, event) :
        self.reverse()
        self.stack()
        self.combine()
        self.stack()
        self.reverse()
        self.add_new_tile()
        self.update_GUI()
        self.game_over()
            
    def up(self, event) :
        self.transpose()
        self.stack()
        self.combine()
        self.stack()
        self.transpose()
        self.add_new_tile()
        self.update_GUI()   
        self.game_over()
            
    def down(self, event) :
        self.transpose()
        self.reverse()
        self.stack()
        self.combine()
        self.stack()
        self.reverse()
        self.transpose()
        self.add_new_tile()
        self.update_GUI()
        self.game_over()
        
    
    # 이동 가능한지 판별하는 함수
    
    def horizontal_move_exists(self) :
        for i in range(4) :
            for j in range(3) :
                if self.matrix[i][j] == self.matrix[i][j+1] :
                    return True
        return False
    
    def vertical_move_exists(self) :
        for i in range(3) :
            for j in range(4) :
                if self.matrix[i][j] == self.matrix[i+1][j] :
                    return True
        return False
    
    
    def game_over(self) :
        if any(2048 in row for row in self.matrix) :
            game_over_frame = tk.Frame(self.main_grid, borderwidth = 2)
            game_over_frame.place(relx=0.5, rely=0.5, anchor='center')
            tk.Label(game_over_frame,
                     text = "You Win!",
                     bg = c.WINNER_BG,
                     fg = c.GAME_OVER_FONT_COLOR,
                     font = c.GAME_OVER_FONT).pack()
            self.stopmusic()
        elif not any(0 in row for row in self.matrix) and not self.horizontal_move_exists() and not self.vertical_move_exists() :
            game_over_frame = tk.Frame(self.main_grid, borderwidth = 3)
            game_over_frame.place(relx=0.5, rely=0.5, anchor='center')
            tk.Button(game_over_frame,
                     text =("Game over! \n 당신의 점수는 : %d " % self.score),
                     bg = c.LOSER_BG,
                     fg = c.GAME_OVER_FONT_COLOR,
                     font = c.GAME_OVER_FONT,
                     command = (self.master.after(3000, lambda: self.master.destroy()))).pack()
            #self.master.after(3000, lambda: self.master.destroy())
            self.stopmusic()
            
    # 음악은 본인이 원하시는 걸로 넣으시면 됩니다.
    def playmusic(self) :
        pygame.init()
        pygame.mixer.init()
        pygame.mixer.music.load("bgm.wav")
        pygame.mixer.music.play()
        
    def stopmusic(soundfile) :
        """stop currently playing music"""
        pygame.mixer.music.stop()

        
def main() :
    Game()
    
if __name__ == "__main__" :
    main()
    
    

 

 

 

결론 : 간단하게 2일만에 완성 할 수 있는 프로젝트를 진행하였다. window와 pygame에 있는 mixer.music.play() 등 다양한 함수를 여러개 사용하며 사용 방법을 익힐 수 있었던 프로젝트이었다.

 

 

 

한계점 : 

버튼을 누르면 바로 재실행 되게 하고 싶었으나 버튼의 색이 계속 background에 남게 떠서 버튼 누르면 화면이 n초 뒤에 종료되는 코드로 작성

 

 

 

 

728x90