728x90
반응형
지난 시간
지난번엔 지뢰찾기 게임에 종료와 현재 상태를 알려주었다.
이번엔 지난번에 만든 게임의 기능을 더 추가하여 완성도를 높인다.
지뢰찾기 게임 만들기
지뢰찾기 룰에 기반해 파이썬으로 제작한다.
얼추 게임의 모습은 갖추었지만 아직 기능이 부족해 보인다.
오늘은 게임이 종료되었을 때 모든 셀이 오픈되고 칸을 클릭했을 때 주위의 빈칸이 있으면 열리는 기능을 만들 것이다.
def reveal_all_cells():
for row in range(board_size):
for col in range(board_size):
if board[row][col] == '*':
revealed[row][col] = 'X' # 지뢰 셀은 'X'로 공개
else:
revealed[row][col] = str(count_mines_around(board, row, col)) # 나머지 셀은 주변 지뢰 개수로 공개
update_board() # 보드 업데이트
모든 셀을 공개하는 함수이다.
반복문을 돌면서 모든 셀을 오픈한다.
이 함수는 게임이 종료되었을 때 작동하기에 게임 종료 함수 부분에 넣어준다.
def open_empty_cells(board, revealed, row, col):
revealed[row][col] = str(count_mines_around(board, row, col))
global remaining_cells
remaining_cells -= 1
if revealed[row][col] == '0':
for r in range(row - 1, row + 2):
for c in range(col - 1, col + 2):
if 0 <= r < len(board) and 0 <= c < len(board[0]):
open_empty_cells(board, revealed, r, c)
이 함수는 주위에 지뢰개수가 0개인 셀을 같이 열어주는 함수다.
원래 셀 오픈 식에서 셀이 0이면 셀 주위 9칸을 반복문으로 돌면서 open_empty_cells 함수를 실행한다.
재귀함수 형식으로 주위 셀이 0이 아닐 때까지 오픈하게 된다.
leftclick else문을 대신에 이 함수를 넣어준다.
그리고 지뢰가 없는 부분을 0으로 표현하다 보니 너무 난잡한 것이 있어 빈칸으로 표현해 주겠다.
def update_board():
for row in range(board_size):
for col in range(board_size):
if revealed[row][col] == ' ':
buttons[row][col].config(text='', state='normal', bg='light gray')
else:
# 표시할 텍스트가 '0'인 경우 빈 문자열로 표시하고, 그렇지 않은 경우에는 지뢰 개수로 표시
text_to_display = revealed[row][col] if revealed[row][col] != '0' else ''
buttons[row][col].config(text=text_to_display, state='disabled', bg='white')
update_board 부분의 else문을 수정해 준다.
그리고 빈칸으로 표시하니 열린 셀과 안 열린 셀 구분이 안 돼서 버튼에 색을 넣어줬다.
def right_click(event, row, col):
if revealed[row][col] == ' ':
revealed[row][col] = 'F' # 깃발 표시
buttons[row][col].config(text='F', disabledforeground='red') #빨간색으로 변경
elif revealed[row][col] == 'F':
revealed[row][col] = ' ' # 깃발 제거
buttons[row][col].config(text='', disabledforeground='black')
update_board()
또 종료 메시지와 깃발 색도 넣어줬다.
지뢰찾기(ver.4) 플레이해 보기
import tkinter as tk
import random
# 게임 설정
board_size = 9
num_mines = 10
remaining_cells = board_size * board_size - num_mines
# 게임 보드 초기화
def initialize_board(size, mines):
board = [[' ' for _ in range(size)] for _ in range(size)]
placed_mines = 0
while placed_mines < mines:
row, col = random.randint(0, size - 1), random.randint(0, size - 1)
if board[row][col] != '*':
board[row][col] = '*'
placed_mines += 1
return board
# 지뢰 주변의 지뢰 개수 계산
def count_mines_around(board, row, col):
count = 0
for r in range(row - 1, row + 2):
for c in range(col - 1, col + 2):
if 0 <= r < len(board) and 0 <= c < len(board[0]) and board[r][c] == '*':
count += 1
return count
# 주변 빈 칸들을 재귀적으로 열기
def open_empty_cells(board, revealed, row, col):
if revealed[row][col] != ' ':
return
revealed[row][col] = str(count_mines_around(board, row, col))
global remaining_cells
remaining_cells -= 1
if revealed[row][col] == '0':
for r in range(row - 1, row + 2):
for c in range(col - 1, col + 2):
if 0 <= r < len(board) and 0 <= c < len(board[0]):
open_empty_cells(board, revealed, r, c)
def update_info_labels():
mine_count_label.config(text=f"지뢰 개수: {num_mines}")
remaining_cells_label.config(text=f"남은 셀 개수: {remaining_cells}")
# 다시 시작
def restart_game():
global board, revealed, remaining_cells
board = initialize_board(board_size, num_mines)
revealed = [[' ' for _ in range(board_size)] for _ in range(board_size)]
remaining_cells = board_size * board_size - num_mines
message_label.config(text="")
update_board()
update_info_labels()
# GUI 초기화
root = tk.Tk()
root.title("지뢰찾기")
root.resizable(False, False)
# 게임 보드 생성
board = initialize_board(board_size, num_mines)
revealed = [[' ' for _ in range(board_size)] for _ in range(board_size)]
# 게임 보드의 각 셀을 버튼으로 만들기
buttons = []
for row in range(board_size):
row_buttons = []
for col in range(board_size):
button = tk.Button(root, text='', width=4, height=2)
button.grid(row=row, column=col)
row_buttons.append(button)
buttons.append(row_buttons)
# 게임 종료 메시지 표시
message_label = tk.Label(root, text="", font=("Helvetica", 16))
message_label.grid(row=board_size, columnspan=board_size)
# 다시하기 버튼 추가
restart_button = tk.Button(root, text="다시하기", command=restart_game, font=("Helvetica", 12))
restart_button.grid(row=board_size + 1, column=0, columnspan=board_size)
info_label_frame = tk.Frame(root)
info_label_frame.grid(row=board_size + 2, column=0, columnspan=board_size)
mine_count_label = tk.Label(info_label_frame, text=f"지뢰 개수: {num_mines}", font=("Helvetica", 12))
mine_count_label.grid(row=0, column=0)
remaining_cells_label = tk.Label(info_label_frame, text=f"남은 셀 개수: {remaining_cells}", font=("Helvetica", 12))
remaining_cells_label.grid(row=0, column=1)
# 게임 종료
def check_game_over():
for row in range(board_size):
for col in range(board_size):
if revealed[row][col] == 'X':
message_label.config(text="지뢰를 밟았습니다! 게임 종료!", fg='red')
reveal_all_cells() # 게임 종료 시 모든 셀 공개
root.update() # 화면 갱신
# root.after(2000, root.destroy) # 2초 후에 게임 종료
return
if remaining_cells == 0:
message_label.config(text="축하합니다! 모든 안전한 셀을 찾았습니다. 게임 승리!")
reveal_all_cells() # 게임 종료 시 모든 셀 공개
# root.update() # 화면 갱신
root.after(2000, root.destroy) # 2초 후에 게임 종료
# 모든 셀을 공개하는 함수
def reveal_all_cells():
for row in range(board_size):
for col in range(board_size):
if board[row][col] == '*':
revealed[row][col] = 'X' # 지뢰 셀은 'X'로 공개
else:
revealed[row][col] = str(count_mines_around(board, row, col)) # 나머지 셀은 주변 지뢰 개수로 공개
update_board() # 보드 업데이트
# 게임 실행
def update_board():
for row in range(board_size):
for col in range(board_size):
if revealed[row][col] == ' ':
buttons[row][col].config(text='', state='normal', bg='light gray')
else:
# 표시할 텍스트가 '0'인 경우 빈 문자열로 표시하고, 그렇지 않은 경우에는 지뢰 개수로 표시
text_to_display = revealed[row][col] if revealed[row][col] != '0' else ''
buttons[row][col].config(text=text_to_display, state='disabled', bg='white')
def left_click(event, row, col):
if board[row][col] == '*':
revealed[row][col] = 'X' # 지뢰 밟음
else:
open_empty_cells(board, revealed, row, col)
update_board()
update_info_labels()
check_game_over()
def right_click(event, row, col):
if revealed[row][col] == ' ':
revealed[row][col] = 'F' # 깃발 표시
buttons[row][col].config(text='F', disabledforeground='red')
elif revealed[row][col] == 'F':
revealed[row][col] = ' ' # 깃발 제거
buttons[row][col].config(text='', disabledforeground='black')
update_board()
# 각 버튼에 클릭 이벤트 바인딩
for row in range(board_size):
for col in range(board_size):
buttons[row][col].bind("<Button-1>", lambda event, row=row, col=col: left_click(event, row, col))
buttons[row][col].bind("<Button-3>", lambda event, row=row, col=col: right_click(event, row, col))
update_board()
root.mainloop()
전체 코드이다.

잘 작동되는 것을 확인할 수 있었다.
Next
다음엔 게임 외적인 부분을 보안해 주도록 하겠다.
728x90
반응형
'지뢰찾기 게임' 카테고리의 다른 글
지뢰찾기 게임 제작기 5 (0) | 2024.04.02 |
---|---|
지뢰찾기 게임 제작기 3 (0) | 2024.03.19 |
지뢰찾기 게임 제작기 2 (7) | 2024.03.12 |
지뢰찾기 게임 제작기 1 (0) | 2024.03.05 |