내가 생각한 오목 변형 게임. 규칙은 오목과 비슷. 다른 점은 하나. 날일자 모양 방향으로 다섯 개 놓으면 됨. 가로 세로 대각선이 아니라.
Python만 가지고는 그림이 안 나오니 PyQt 활용. 프로그램 개발을 chatGPT에게 시킴. 수준은 향상 필요하나 일단 동작은 함. 그 뜻은 5개 놓았는데, 이겼는지 졌는지도 모르지는 않는다는 뜻. 처음엔 엉뚱하게 두기에 chatGPT에게 규칙을 가르쳐 주는 과정이 쉽지만은 않았지만, 나름 재미있었음.
아래는 그걸 구현한 소스 코드. 수시로 업그레이드 중.
import sys
import random
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
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
class NalmokGame(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("날목 (Nalmok)")
self.setFixedSize(BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE)
self.board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.turn = WHITE # Player is WHITE, computer is BLACK
# Computer plays first in the center
mid = BOARD_SIZE // 2
self.board[mid][mid] = 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)
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)
def mousePressEvent(self, event):
if 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.board[y][x] = 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 computer_move(self):
best_move = self.find_best_move()
if best_move is None:
self.game_over("무승부!")
return
x, y = best_move
self.board[y][x] = BLACK
if self.check_win(x, y, BLACK):
self.update()
self.game_over("컴퓨터(흑) 승리!")
return
self.turn = WHITE
self.update()
def find_best_move(self):
# 우선순위: 내 승리 > 상대 승리 방어 > 3개 막기 > 랜덤
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = BLACK
if self.check_win(x, y, BLACK):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = WHITE
if self.check_win(x, y, WHITE):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = WHITE
if self.count_consecutive(x, y, WHITE, 3):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
empty = [(x, y) for y in range(BOARD_SIZE) for x in range(BOARD_SIZE) if self.board[y][x] == EMPTY]
return random.choice(empty) if empty else None
def count_consecutive(self, x, y, stone, count_required):
directions = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
for dx, dy in directions:
cnt = 1
for step in range(1, 5):
nx = x + dx * step
ny = y + dy * step
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
if self.board[ny][nx] == stone:
cnt += 1
else:
break
if cnt >= count_required:
return True
return False
def check_win(self, x, y, stone):
directions = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
for dx, dy in directions:
count = 1
for dir in [1, -1]:
for i in range(1, 5):
nx = x + dx * i * dir
ny = y + dy * i * dir
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
if self.board[ny][nx] == stone:
count += 1
else:
break
if count >= 5:
return True
return False
def game_over(self, message):
QMessageBox.information(self, "게임 종료", message)
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
game = NalmokGame()
sys.exit(app.exec_())
댓글 없음:
댓글 쓰기