그놈의 깃허브도 개설해보고 아무것도 커밋하지 않다가 드디어 허접한 무언가라도 만들게 되어 신나서 호다닥 블로그 첫 글을 쓰러왔다!!!😊 글재주 없는 설명충인데 어떡하지
작년 10월이었나.. 심심하면 지뢰찾기를 즐겨하는 친구한테 우스갯소리로 지뢰찾기를 만들어주겠다고 했었다. 대학교 1학년 시절 재미있어보여 사두고 묵혀두었던 Python과 Pygame으로 게임만들기
를 이번에 파이썬 공부를 하면서 꺼내보게 되었다. 이참에 지뢰찾기나 만들어볼까 싶어 만든 choco_sweeper_v1
(사실은 정처기 공부가 하기 싫었어요)
생각보다 만들기 어렵거나 오래걸리진 않았는데 뭔가 내 코드가 썩 맘에든다거나 깔끔한거 같지는 않은 기분.. 분명 나중에 보면 허접 찌끄레기 일테지만🙉🙊 그래도 한게 있으니 일단 올려놓기는 해야지 나중에 시간나면 pygame에 관한 글도 올려보려고 한다.
(초코 똥 밟았다 !)
게임판인 board의 자료구조는 다음과 같은 딕셔너리의 리스트 형태이다.
x와 y는 게임판에서의 좌표, count는 지뢰의 갯수, flag는 상태정보를 담고 있다.
board = [{'x': x, 'y': y, 'count': count, 'flag': flag}, ...]
count의 상수
POO = -1
flag의 상수
NONE = 0
FLAG = -1
OPENED = 1
count는 0~8
의 주변 지뢰의 갯수 또는 지뢰인 경우 POO
의 값을 갖는다.
flag는 초기상태인 NONE
또는 깃발상태인 FLAG
또는 열린상태인 OPENED
의 값을 갖는다.
(지뢰를 초코 똥으로 그렸기 때문에 지뢰는 POO💩인 것으로..)
def getRandomPoo():
poos = []
while len(poos) < POOCOUNT :
x = random.randint(0, CELLWIDTH-1)
y = random.randint(0, CELLHEIGHT-1)
poo = {'x': x, 'y': y}
if poo not in poos:
poos.append(poo)
return poos
지뢰의 리스트인 poos
의 길이가 지뢰의 갯수인 POOCOUNT
가 될때까지 지뢰의 좌표를 생성한다.
중복되는 좌표가 아닌경우에만 리스트에 좌표를 추가한다.
def getStartingBoard():
poos = getRandomPoo()
board = []
for x in range(CELLWIDTH):
for y in range(CELLHEIGHT):
count = 0
if {'x': x, 'y': y} in poos:
count = POO
else:
if {'x': x-1, 'y': y-1} in poos:
count +=1
if {'x': x, 'y': y-1} in poos:
count +=1
if {'x': x+1, 'y': y-1} in poos:
count +=1
if {'x': x-1, 'y': y} in poos:
count +=1
if {'x': x+1, 'y': y} in poos:
count +=1
if {'x': x-1, 'y': y+1} in poos:
count +=1
if {'x': x, 'y': y+1} in poos:
count +=1
if {'x': x+1, 'y': y+1} in poos:
count +=1
cell = {'x': x, 'y': y, 'count' : count, 'flag': NONE}
board.append(cell)
return board
getRandomPoo()
를 실행하여 지뢰를 생성하고 해당좌표의 주변 지뢰갯수를 계산하여 board를 생성한다.
def runGame():
resetButton, boardSurf = drawBorder()
board = getStartingBoard()
startTime = 0
drawBorder()
함수로 게임화면을 그리고 리셋버튼과 보드의 위치를 저장하고 getStartingBoard()
로 보드판을 생성한다.
while True:
cellx, celly = None, None
#click event
for event in pygame.event.get():
if event.type == QUIT:
terminate()
elif event.type == MOUSEBUTTONUP:
cellx, celly = getSpotClicked(board, event.pos[0], event.pos[1])
if event.button == 1: #left click
if resetButton.collidepoint(event.pos): #resetButton pressed
playButtonSound()
return
elif boardSurf.collidepoint(event.pos) : #board pressed
if startTime == 0: #timer on
startTime = time.time()
index = getBoardIndex(cellx, celly)
setFlagOpened(board[index])
elif event.button == 3: #right click
if boardSurf.collidepoint(event.pos):
index = getBoardIndex(cellx, celly)
setFlagFlag(board[index])
event가 발생했을때
QUIT
의 경우
terminate()
함수를 실행하여 게임을 종료시킨다.
마우스 클릭의 경우
getSpotClicked()
함수를 실행하여 마우스 좌표에 해당하는 보드 좌표를 반환하여 cellx
,celly
에 저장한다.
왼쪽 클릭
리셋 버튼이 눌린 경우 return
하여 runGame()
함수가 다시 실행될 수 있게 한다.
보드판이 눌린 경우 타이머를 시작하고 해당 칸을OPENED
로 바꾼다.
오른쪽 클릭
setFlagFlag()
함수는 보드판이 눌린 경우 해당 칸을FLAGED
로 바꾼다.
이미 FLAGED
인 경우 NONE
으로 바꾼다.
for cell in board:
if cell['count'] == 0 and cell['flag'] == OPENED: #open cell if there`s no poo around
setAroundOpened(board, cell)
주변에 지뢰가 없고 해당 칸이 열려있는 경우 setAroundOpened()
는 주변의 모든 칸을 연다.
runGame()
의 무한 루프안에서 실행되기 때문에 주변으로 퍼져나가며 열리게 된다.
for cell in board:
if cell['count'] == POO and cell['flag'] == OPENED: #GAME OVER
for cell in board: #open all poo left
if cell['count'] == POO :
setFlagOpened(cell)
drawBoard(board, startTime)
showGameOverScreen(board, cellx, celly)
if checkForNext(resetButton) == 1:
return
else:
drawBoard(board, startTime)
if getPooCount(board) == 0:
for cell in board:
if cell['flag'] == FLAG and cell['count'] != POO: #wrong flag
break
if cell['flag'] == NONE and cell['count'] != POO: #not poo cell not opened
break
else: #YOUWIN!
showYouWinScreen()
if checkForNext(resetButton) == 1:
return
지뢰칸이 열린 경우 남은 지뢰칸을 모두 열고 게임 실패화면을 보인다.
지뢰칸을 제외한 모든 칸이 열린 경우 게임 성공화면을 보인다.
def main():
global DISPLAYSURF, BASICFONT, CHOCOIMG
pygame.init()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('source/Jalnan.ttf',18)
pygame.display.set_caption('Choco Sweeper')
CHOCOIMG = pygame.image.load('source/choco.png')
pygame.display.set_icon(CHOCOIMG)
showStartScreen()
while True:
runGame()
showStartScreen()
으로 시작화면이 보여지고 runGame()
함수가 게임 종료시까지 무한루프를 도는 구조이다.
깃헙에서 확인하는 것으로 😺
https://github.com/yevini118/choco_sweeper.git
사실 코딩하는 시간보다 그림그리고 디자인하는데 시간을 더 많이 쓴거같다. 그래도 나름 초코 잘그린거 같음 (멍멍..)
중간에 약간의 삽질을 하느라 시간을 좀 버렸다.☹️
조금이라도 더 빠른 코드를 쓰고 싶어서 보드의 인덱스를 구해 칸에 접근하는 방법으로 for문을 줄여봤는데 이게 효과가 있기는 한걸까라는 의문이 들긴해..
친구하라고 exe로 만들어 보내줬는데 pyinstaller
로 windows10에서 만든 exe가 친구의 컴퓨터인 windows7에서 돌아가지 않는 덕분에🙃 virtualBox
까지 써가며 windows7에서 만들어서 보내주니 다행히 잘 돌아갔다 ㅠ(눙물😢)
다른 친구들한테도 하라고 보내주니까 생각보다 열심히하는게 웃겼다.
v1에서는 더블클릭 구현을 못해서 아쉽다. 정처기 필기가 끝나면 언넝 v2를 만들어야겠다.
choco_sweeper_v2
에서는 더블클릭과 보드사이즈+지뢰 갯수 조절기능을 넣어야지!