PyQt 5 오목 게임 실현(인간 과 컴퓨터 대국)

12911 단어 PyQt5오목
이 블 로 그 는 주로 Python 과 PyQt 를 배우 기 위해 서 입 니 다.보드게임 에 열중 하기 때문에 규칙 이 간단 한 오목 에 착안 하여 PyQt 5 를 이용 하여 그래 픽 인터페이스 를 실현 하고 인간 과 컴퓨터 의 대국 을 할 수 있 는 스 크 립 트 를 만 들 고 마지막 에 응용 프로그램 으로 포장 합 니 다.AI 알고리즘 은 신경 망 으로 완성 하려 고 텐 서 플 로 우 를 고심 중이 다.
원래 저 는 오목 규칙 이 간단 하 다 고 생각 했 습 니 다.초등학교 때 했 던 것 처럼 다섯 개의 바둑 알 을 연결 하면 이 겼 잖 아 요.그런데 일이 그렇게 간단 하지 않다 는 것 을 알 게 되 었 습 니 다.현재 의 오목 은 금 수 라 는 규칙 이 있 습 니 다.'3,3 금 수','4,4 금 수','장 련 금 수'등 은 모두 현 행 한 측의 필승 을 제한 하기 위해 서 입 니 다.저도 프로 기사 가 아 닙 니 다.그 렇 죠?그래서 금 수 는 생각 하지 않 고 간단 한 완제품 을 만 들 면 만족 합 니 다.
코드 는 모두 공부 하면 서 쓴 것 입 니 다.하 자가 있 는 곳 에 서 는 제출 을 환영 합 니 다.
첫 번 째,소재 수집
주로 바둑 알·바둑판 의 그림 과 바둑 의 음향 효과 가 있다



음향 효 과 는 코드 와 함께 마지막 에 드 립 니 다.
두 번 째 단계,오목 의 논리 류
소 재 를 수집 한 후에 인터페이스의 작성 을 서 두 르 지 않 고 먼저 오목 의 논 리 를 잘 쓰 고 인터페이스 와 논 리 를 분리 하 는 것 이 중요 합 니 다.
먼저 오목 의 논리 류 에 어떤 것 이 있어 야 하 는 지 생각해 보 세 요.
먼저 바둑판,바둑판 은 15*15 의 수조 로 표시 한다
그 다음은 바둑 알,검 은 바둑 은 1 로 표시 하고,흰 바둑 은 2 로 표시 하 며,공백 은 0 으로 표시 한다.
그리고 지정 한 점 의 좌 표를 가 져 오고 지정 한 점 의 방향 을 가 져 와 야 합 니 다.
가장 중요 한 것 도 조금 어 려 운 부분 은 승 부 를 판단 하 는 것 이다.인터넷 의 방법 과 나의 이 해 를 결합 하여 아래 에 내 가 쓴 코드 를 붙 여 참고 하 시기 바 랍 니 다.
chessboard.py

# ----------------------------------------------------------------------
#       ,    
# ----------------------------------------------------------------------
EMPTY = 0
BLACK = 1
WHITE = 2


# ----------------------------------------------------------------------
#      ,       ,     ,     
# ----------------------------------------------------------------------
class ChessBoard(object):
 def __init__(self):
 self.__board = [[EMPTY for n in range(15)] for m in range(15)]
 self.__dir = [[(-1, 0), (1, 0)], [(0, -1), (0, 1)], [(-1, 1), (1, -1)], [(-1, -1), (1, 1)]]
 #  (   ) (   ) (     ) (     )

 def board(self): #       
 return self.__board

 def draw_xy(self, x, y, state): #           
 self.__board[x][y] = state

 def get_xy_on_logic_state(self, x, y): #           
 return self.__board[x][y]

 def get_next_xy(self, point, direction): #              
 x = point[0] + direction[0]
 y = point[1] + direction[1]
 if x < 0 or x >= 15 or y < 0 or y >= 15:
  return False
 else:
  return x, y

 def get_xy_on_direction_state(self, point, direction): #              
 if point is not False:
  xy = self.get_next_xy(point, direction)
  if xy is not False:
  x, y = xy
  return self.__board[x][y]
 return False

 def anyone_win(self, x, y):
 state = self.get_xy_on_logic_state(x, y) #              ,       state 
 for directions in self.__dir: #     4          5     
  count = 1 #      1,         
  for direction in directions: #                   ,    
  point = (x, y) #          
  while True:
   if self.get_xy_on_direction_state(point, direction) == state:
   count += 1
   point = self.get_next_xy(point, direction)
   else:
   break
  if count >= 5:
  return state
 return EMPTY

 def reset(self): #   
 self.__board = [[EMPTY for n in range(15)] for m in range(15)]
위의 코드 를 chessboard.py 에 넣 으 면 가장 기본 적 인 작업 이 완 료 됩 니 다.
세 번 째 단계,PyQt 5 를 이용 하여 그래 픽 인터페이스 구현
생각 부터 해.
1.간단 한 오목 인 터 페 이 스 를 만 드 는 것 이 목표 입 니 다.메 인 창 은 Widget 하나만 있 으 면 됩 니 다.
2.Widget 배경 을 바둑판 그림 으로 설정
3.마우스 가 공백 영역 을 클릭 할 때마다 탭 을 추가 하고 탭 에 바둑돌 그림 을 삽입 합 니 다.
4.인간 과 컴퓨터 의 대국 이기 때문에 게이머 들 이 검 은 바둑 을 두 기 때문에 마 우 스 를 검 은 바둑 그림 으로 바 꿀 수 있다(이 점 은 복잡 하 므 로 라벨 류 를 다시 써 야 한다)
5.전체적인 논 리 는 마 우 스 를 한 번 클릭 하면―->환산 좌표(UI 좌표 에서 바둑판 좌표 까지)―->좌표 가 합 리 적 인지 판단 하 는 것―->검 은 바둑 이 바둑판 에 떨 어 졌 는 지 판단 하 는 것―->컴퓨터 사고->컴퓨터 에서 흰 바둑 을 두 는 것―->바둑 을 이 길 지 여 부 를 판단 하 는 것 이다.
6.AI 가 생각 하 는 데 시간 이 필요 하기 때문에 스 레 드 를 추가 하여 AI 의 주 행 방법 을 따로 계산 하도록 해 야 한다.
7.일부 세부 적 인 문제:바둑 을 이 기 는 것 과 지 는 것 을 어떻게 처리 하 는 지(대화 상자),바둑 을 두 는 것 은 어떻게 하 는 지(이것 은 먼저 고려 하지 않 는 다),게임 후기 에 바둑 알 이 매우 많 을 때 눈 이 침침 해 지기 쉽 고 AI 가 어디로 가 는 지 모 르 는 지(지시 화살표 추가),음향 효과 가 어떻게 삽입 되 는 지(QSound 로)등 이다.
다음은 전체 코드 를 드 립 니 다.
gobangGUI.py

from chessboard import ChessBoard
from ai import searcher

WIDTH = 540
HEIGHT = 540
MARGIN = 22
GRID = (WIDTH - 2 * MARGIN) / (15 - 1)
PIECE = 34
EMPTY = 0
BLACK = 1
WHITE = 2


import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QMessageBox
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QIcon, QPalette, QPainter
from PyQt5.QtMultimedia import QSound


# ----------------------------------------------------------------------
#        AI   
# ----------------------------------------------------------------------
class AI(QtCore.QThread):
 finishSignal = QtCore.pyqtSignal(int, int)

 #          
 def __init__(self, board, parent=None):
 super(AI, self).__init__(parent)
 self.board = board

 #    run()   
 def run(self):
 self.ai = searcher()
 self.ai.board = self.board
 score, x, y = self.ai.search(2, 2)
 self.finishSignal.emit(x, y)


# ----------------------------------------------------------------------
#     Label 
# ----------------------------------------------------------------------
class LaBel(QLabel):
 def __init__(self, parent):
 super().__init__(parent)
 self.setMouseTracking(True)

 def enterEvent(self, e):
 e.ignore()


class GoBang(QWidget):
 def __init__(self):
 super().__init__()
 self.initUI()

 def initUI(self):

 self.chessboard = ChessBoard() #    

 palette1 = QPalette() #       
 palette1.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap('img/chessboard.jpg')))
 self.setPalette(palette1)
 # self.setStyleSheet("board-image:url(img/chessboard.jpg)") #          
 self.setCursor(Qt.PointingHandCursor) #         
 self.sound_piece = QSound("sound/luozi.wav") #       
 self.sound_win = QSound("sound/win.wav") #       
 self.sound_defeated = QSound("sound/defeated.wav") #       

 self.resize(WIDTH, HEIGHT) #      540*540
 self.setMinimumSize(QtCore.QSize(WIDTH, HEIGHT))
 self.setMaximumSize(QtCore.QSize(WIDTH, HEIGHT))

 self.setWindowTitle("GoBang") #     
 self.setWindowIcon(QIcon('img/black.png')) #     

 # self.lb1 = QLabel('  ', self)
 # self.lb1.move(20, 10)

 self.black = QPixmap('img/black.png')
 self.white = QPixmap('img/white.png')

 self.piece_now = BLACK #     
 self.my_turn = True #     
 self.step = 0 #   
 self.x, self.y = 1000, 1000

 self.mouse_point = LaBel(self) #          
 self.mouse_point.setScaledContents(True)
 self.mouse_point.setPixmap(self.black) #    
 self.mouse_point.setGeometry(270, 270, PIECE, PIECE)
 self.pieces = [LaBel(self) for i in range(225)] #       ,          
 for piece in self.pieces:
  piece.setVisible(True) #     
  piece.setScaledContents(True) #            

 self.mouse_point.raise_() #         
 self.ai_down = True # AI   ,       ,   False     AI    ,           ,     mousePressEvent

 self.setMouseTracking(True)
 self.show()

 def paintEvent(self, event): #       
 qp = QPainter()
 qp.begin(self)
 self.drawLines(qp)
 qp.end()

 def mouseMoveEvent(self, e): #          
 # self.lb1.setText(str(e.x()) + ' ' + str(e.y()))
 self.mouse_point.move(e.x() - 16, e.y() - 16)

 def mousePressEvent(self, e): #     
 if e.button() == Qt.LeftButton and self.ai_down == True:
  x, y = e.x(), e.y() #     
  i, j = self.coordinate_transform_pixel2map(x, y) #       
  if not i is None and not j is None: #        ,    
  if self.chessboard.get_xy_on_logic_state(i, j) == EMPTY: #        
   self.draw(i, j)
   self.ai_down = False
   board = self.chessboard.board()
   self.AI = AI(board) #       ,      
   self.AI.finishSignal.connect(self.AI_draw) #     ,    
   self.AI.start() # run

 def AI_draw(self, i, j):
 if self.step != 0:
  self.draw(i, j) # AI
  self.x, self.y = self.coordinate_transform_map2pixel(i, j)
 self.ai_down = True
 self.update()

 def draw(self, i, j):
 x, y = self.coordinate_transform_map2pixel(i, j)

 if self.piece_now == BLACK:
  self.pieces[self.step].setPixmap(self.black) #       
  self.piece_now = WHITE
  self.chessboard.draw_xy(i, j, BLACK)
 else:
  self.pieces[self.step].setPixmap(self.white) #       
  self.piece_now = BLACK
  self.chessboard.draw_xy(i, j, WHITE)

 self.pieces[self.step].setGeometry(x, y, PIECE, PIECE) #     
 self.sound_piece.play() #     
 self.step += 1 #   +1

 winner = self.chessboard.anyone_win(i, j) #     
 if winner != EMPTY:
  self.mouse_point.clear()
  self.gameover(winner)

 def drawLines(self, qp): #   AI      
 if self.step != 0:
  pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
  qp.setPen(pen)
  qp.drawLine(self.x - 5, self.y - 5, self.x + 3, self.y + 3)
  qp.drawLine(self.x + 3, self.y, self.x + 3, self.y + 3)
  qp.drawLine(self.x, self.y + 3, self.x + 3, self.y + 3)

 def coordinate_transform_map2pixel(self, i, j):
 #   chessMap         UI          
 return MARGIN + j * GRID - PIECE / 2, MARGIN + i * GRID - PIECE / 2

 def coordinate_transform_pixel2map(self, x, y):
 #   UI         chessMap          
 i, j = int(round((y - MARGIN) / GRID)), int(round((x - MARGIN) / GRID))
 #  MAGIN,          i,j   
 if i < 0 or i >= 15 or j < 0 or j >= 15:
  return None, None
 else:
  return i, j

 def gameover(self, winner):
 if winner == BLACK:
  self.sound_win.play()
  reply = QMessageBox.question(self, 'You Win!', 'Continue?',
      QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
 else:
  self.sound_defeated.play()
  reply = QMessageBox.question(self, 'You Lost!', 'Continue?',
      QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

 if reply == QMessageBox.Yes: #   
  self.piece_now = BLACK
  self.mouse_point.setPixmap(self.black)
  self.step = 0
  for piece in self.pieces:
  piece.clear()
  self.chessboard.reset()
  self.update()
 else:
  self.close()


if __name__ == '__main__':
 app = QApplication(sys.argv)
 ex = GoBang()
 sys.exit(app.exec_())
간략하게 설명해 주세요.

class AI(QtCore.QThread):
 finishSignal = QtCore.pyqtSignal(int, int)

 #          
 def __init__(self, board, parent=None):
 super(AI, self).__init__(parent)
 self.board = board

 #    run()   
 def run(self):
 self.ai = searcher()
 self.ai.board = self.board
 score, x, y = self.ai.search(2, 2)
 self.finishSignal.emit(x, y)
여기에 AI 의 계산 을 수행 하 는 스 레 드 를 추 가 했 습 니 다.앞 에 from ai import searcher 가 있 습 니 다.ai 는 아직 쓰 지 않 았 습 니 다.먼저 인터넷 에서 게임 의 알고리즘 을 찾 았 습 니 다.searcher()는 AI 류 다.이 스 레 드 가 들 어 오 는 매개 변 수 는 board 가 바둑판 상태 입 니 다.self.ai.search(2,2)를 호출 합 니 다.첫 번 째 2 는 게임 트 리 의 깊이 이 고 값 이 클 수록 AI 가 똑똑 하지만 계산 시간 도 길 어 집 니 다.두 번 째 2 는 컴퓨터 가 백 기 를 잡 고 1 이면 흑 기 를 잡 는 다 는 것 이다.스 레 드 가 끝 난 후 전 송 된 매개 변수 x,y 는 AI 가 계산 한 후 스 레 드 에서 전 송 된 매개 변수 입 니 다.

class LaBel(QLabel):
 def __init__(self, parent):
 super().__init__(parent)
 self.setMouseTracking(True)

 def enterEvent(self, e):
 e.ignore()
레이 블 클래스 를 재 정의 하 는 것 은 검 은 바둑 그림 이 마우스 의 이동 에 따라 이동 하도록 하기 위 한 것 이다.큐 레이 블 을 직접 쓰 면 기대 에 못 미 치 는 효과 가 있 으 니 구체 적 으로 왜 알 아서 하 는 지 알 아 보 자.
마지막 으로 모든 스 크 립 트 코드 입 니 다.그 후에 도 계속 공부 하고 스 크 립 트 를 실행 가능 한 파일 로 포장 하 며 신경 망 을 넣 는 알고리즘 입 니 다.
PyQt 5 기반 오목 프로 그래 밍(인간 과 컴퓨터 의 대국)
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기