#날목01. 사람이 시작하면 백으로 시작하는데 누가 먼저 시작하더라도 흑으로 시작하려면 어디를 바꾸어야 할까?
import sys
import random
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QPushButton, QDialog, QVBoxLayout, QLabel
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt, QTimer
BOARD_SIZE = 19
CELL_SIZE = 30
STONE_RADIUS = 12
EMPTY = 0
BLACK = 1
WHITE = 2
# 나이트 이동 방향
NALMOK_DIRECTIONS = [(2, 1), (1, 2), (-2, 1), (-1, 2), (2, -1), (1, -2), (-2, -1), (-1, -2)]
class FirstTurnDialog(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("누가 먼저 시작할까요?")
self.choice = None
layout = QVBoxLayout()
layout.addWidget(QLabel("누가 먼저 시작할까요?"))
btn_human = QPushButton("사람")
btn_computer = QPushButton("컴퓨터")
layout.addWidget(btn_human)
layout.addWidget(btn_computer)
btn_human.clicked.connect(self.choose_human)
btn_computer.clicked.connect(self.choose_computer)
self.setLayout(layout)
def choose_human(self):
self.choice = "human_first"
self.accept()
def choose_computer(self):
self.choice = "computer_first"
self.accept()
class NalmokGame(QWidget):
def __init__(self, first_turn_mode):
super().__init__()
self.setWindowTitle("날목")
self.setFixedSize(BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE)
self.board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.move_history = []
self.game_over_flag = False
self.last_black_move = None
self.last_white_move = None
undo_button = QPushButton("Undo", self)
undo_button.move(10, self.height() - 40)
undo_button.clicked.connect(self.undo_move)
if first_turn_mode == "computer_first":
center = BOARD_SIZE // 2
self.place_stone(center, center, BLACK)
self.turn = WHITE
elif first_turn_mode == "human_first": # 이 부분을 추가
self.turn = WHITE
else:
self.turn = BLACK
self.show()
def paintEvent(self, event):
qp = QPainter()
qp.begin(self)
self.draw_board(qp)
self.draw_stones(qp)
qp.end()
def draw_board(self, qp):
qp.setBrush(QColor(222, 184, 135))
qp.drawRect(0, 0, self.width(), self.height())
qp.setPen(QPen(Qt.black, 1))
for i in range(BOARD_SIZE):
qp.drawLine(CELL_SIZE // 2, CELL_SIZE // 2 + i * CELL_SIZE,
CELL_SIZE // 2 + (BOARD_SIZE - 1) * CELL_SIZE, CELL_SIZE // 2 + i * CELL_SIZE)
qp.drawLine(CELL_SIZE // 2 + i * CELL_SIZE, CELL_SIZE // 2,
CELL_SIZE // 2 + i * CELL_SIZE, CELL_SIZE // 2 + (BOARD_SIZE - 1) * CELL_SIZE)
star_points = [(3, 3), (3, 9), (3, 15),
(9, 3), (9, 9), (9, 15),
(15, 3), (15, 9), (15, 15)]
for x, y in star_points:
cx = CELL_SIZE // 2 + x * CELL_SIZE
cy = CELL_SIZE // 2 + y * CELL_SIZE
qp.setBrush(QColor(0, 0, 0))
qp.drawEllipse(cx - 3, cy - 3, 6, 6)
def draw_stones(self, qp):
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] != EMPTY:
if self.board[y][x] == BLACK:
qp.setBrush(QColor(0, 0, 0))
else:
qp.setBrush(QColor(255, 255, 255))
qp.drawEllipse(
CELL_SIZE // 2 + x * CELL_SIZE - STONE_RADIUS,
CELL_SIZE // 2 + y * CELL_SIZE - STONE_RADIUS,
STONE_RADIUS * 2,
STONE_RADIUS * 2
)
last = self.last_black_move if self.turn == WHITE else self.last_white_move
if last:
x, y = last
cx = CELL_SIZE // 2 + x * CELL_SIZE
cy = CELL_SIZE // 2 + y * CELL_SIZE
qp.setPen(QPen(Qt.red, 2))
qp.drawEllipse(cx - 5, cy - 5, 10, 10)
def mousePressEvent(self, event):
if self.game_over_flag or self.turn != WHITE:
return
x = int((event.x() - CELL_SIZE // 2 + CELL_SIZE / 2) // CELL_SIZE)
y = int((event.y() - CELL_SIZE // 2 + CELL_SIZE / 2) // CELL_SIZE)
if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and self.board[y][x] == EMPTY:
self.place_stone(x, y, WHITE)
if self.check_win(x, y, WHITE):
self.update()
self.game_over("사용자(백) 승리!")
return
self.turn = BLACK
self.update()
QTimer.singleShot(500, self.computer_move)
def place_stone(self, x, y, stone):
self.board[y][x] = stone
self.move_history.append((x, y, stone))
if stone == BLACK:
self.last_black_move = (x, y)
else:
self.last_white_move = (x, y)
def undo_move(self):
if len(self.move_history) >= 2:
for _ in range(2):
x, y, stone = self.move_history.pop()
self.board[y][x] = EMPTY
if stone == BLACK:
self.last_black_move = None
else:
self.last_white_move = None
self.turn = WHITE
self.update()
def check_win(self, x, y, stone):
for dx, dy in NALMOK_DIRECTIONS:
count = 1
for dir in [1, -1]:
for i in range(1, 5):
nx, ny = x + dx * i * dir, y + dy * i * dir
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and self.board[ny][nx] == stone:
count += 1
else:
break
if count >= 5:
return True
return False
def should_block_nalmok(self, x, y, stone, length):
for dx, dy in NALMOK_DIRECTIONS:
count = 1
blocked = 0
for i in range(1, length):
nx = x + dx * i
ny = y + dy * i
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
cell = self.board[ny][nx]
if cell == stone:
count += 1
elif cell == EMPTY:
continue
else:
blocked += 1
break
else:
blocked += 1
break
if count == length and blocked == 0:
return True
return False
def computer_move(self):
if self.game_over_flag:
return
# 우선순위 1: 컴퓨터 승리 수
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY and self.should_block_nalmok(x, y, BLACK, 4):
self.place_stone(x, y, BLACK)
if self.check_win(x, y, BLACK):
self.update()
self.game_over("컴퓨터(흑) 승리!")
return
self.turn = WHITE
self.update()
return
# 우선순위 2: 상대 열린 4 차단
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY and self.should_block_nalmok(x, y, WHITE, 4):
self.place_stone(x, y, BLACK)
self.turn = WHITE
self.update()
return
# 우선순위 3: 컴퓨터 공격 - 3 연결
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY and self.should_block_nalmok(x, y, BLACK, 3):
self.place_stone(x, y, BLACK)
self.turn = WHITE
self.update()
return
# 우선순위 4: 상대 열린 3 차단
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY and self.should_block_nalmok(x, y, WHITE, 3):
self.place_stone(x, y, BLACK)
self.turn = WHITE
self.update()
return
# 우선순위 5: 중앙 혹은 임의 착수
base_x, base_y = self.last_black_move if self.last_black_move else (BOARD_SIZE // 2, BOARD_SIZE // 2)
for dx, dy in NALMOK_DIRECTIONS:
nx = base_x + dx
ny = base_y + dy
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and self.board[ny][nx] == EMPTY:
self.place_stone(nx, ny, BLACK)
if self.check_win(nx, ny, BLACK):
self.update()
self.game_over("컴퓨터(흑) 승리!")
return
self.turn = WHITE
self.update()
return
def game_over(self, message):
self.game_over_flag = True
QMessageBox.information(self, "게임 종료", message)
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
dialog = FirstTurnDialog()
if dialog.exec_() == QDialog.Accepted:
game = NalmokGame(dialog.choice)
sys.exit(app.exec_())
댓글 없음:
댓글 쓰기