2017-03-29 4 views
0

PyQt5を使用してTic-Tac-Toe UIを作成しようとしています。三つのモードが用意されてい複数のプログラムによるクリックイベントに対して予期しない動作が発生する

  1. 人間対人間の
  2. 人間のAI
  3. AI AIのゲーム対

すべてのモードは、2つのAIが対戦(モード3のことを除いて非常に細かい作業ゲームの開始まで、各ターンの中間ステップをリフレッシュするのではなく、UIがロードして最終結果を表示するようになりました。どうすれば達成できますか?ありがとうございました!以下は


私のコードです:

class TicTacToeUI(QtWidgets.QWidget): 
    icons = ['icons/x-mark.png', 'icons/hollow-circle.png'] 

    def __init__(self, parent=None): 
     super().__init__(parent) 
     self.setWindowTitle("TicTacToe") 
     self.setStyleSheet('background-color: #D7CCC8;') 
     # Players 
     self._players_selector = QtWidgets.QGridLayout() 
     self._players = list() 
     for p in range(2): 
      label = QtWidgets.QLabel('Player {:}'.format(p)) 
      selectbox = QtWidgets.QComboBox() 
      selectbox.setFixedHeight(24) 
      selectbox.addItems(list(PLAYERS.keys())) 
      self._players_selector.addWidget(label, 0, p) 
      self._players_selector.addWidget(selectbox, 1, p) 
      self._players.append(selectbox) 
     self._grid = QtWidgets.QGridLayout() 
     self._gameboard_buttons = dict() 
     for i in range(self.m): 
      for j in range(self.n): 
       btn = self.create_gameboard_button(row=i, col=j) 
       self._grid.addWidget(btn, i, j) 
       self._gameboard_buttons.update({(i, j): btn}) 
     self._message_box = QtWidgets.QLabel('', parent=self) 
     self._restart_button = QtWidgets.QPushButton('Start', parent=self) 
     self._restart_button.setFixedHeight(32) 
     self._restart_button.clicked.connect(self.restart) 
     # Layout 
     self._layout = QtWidgets.QVBoxLayout() 
     self._layout.addLayout(self._players_selector) 
     self._layout.addLayout(self._grid) 
     self._layout.addWidget(self._message_box) 
     self._layout.addWidget(self._restart_button) 
     self.setLayout(self._layout) 
     # The game 
     self._game = TicTacToe() 
     self._started = False 

    def create_gameboard_button(self, row, col): 
     btn = TicTacToeUIButton('', parent=self, style_sheet='background-color: #D7CCC8;') 
     btn.setFixedSize(64, 64) 
     btn.clicked.connect(functools.partial(self.click, row, col)) 
     return btn 

    def click(self, row, col): 
     if not self._started: 
      pass 
     elif self._game.is_ended: 
      pass 
     else: 
      btn = self._gameboard_buttons.get((row, col)) 
      if btn is not None: 
       if btn.is_occupied: 
        msg = 'It is occupied. Please select another one.' 
        self._message_box.setText(msg) 
       else: 
        player = self._game.turn_player 
        # Icon appearance 
        for _, b in self._gameboard_buttons.items(): 
         b.remove_border() 
        btn.setIcon(QtGui.QIcon(self.icons[player])) 
        btn.setIconSize(QtCore.QSize(48, 48)) 
        btn.add_border('border: 1px solid #FF0000;') 
        btn.occupied_player = player 
        # Check result 
        self._game.move(row=row, col=col, player=player) 
        if self._game.winner is not None: 
         if self._game.winner == -1: 
          msg = 'Draw. What a game!' 
         else: 
          msg = 'Player {:} won. Congratulations!' 
          msg = msg.format(self._game.winner) 
        else: 
         msg = '' 
        self._message_box.setText(msg) 
      # Next turn 
      if self._game.is_ended: 
       pass 
      else: 
       self._game.players[self._game.turn_player].decide_ui(self) 

    def reset(self): 
     self._started = True 
     self._game.reset() 
     self._game.player0 = PLAYERS.get(self._players[0].currentText()) 
     self._game.player1 = PLAYERS.get(self._players[1].currentText()) 
     self._restart_button.setText('Restart') 
     self._message_box.setText('') 
     for _, btn in self._gameboard_buttons.items(): 
      btn.reset() 
     if self._game.player0.is_ai: 
      self._game._player0.decide_ui(self) 

    def restart(self): 
     self.reset() 

いくつかの注意: 'スタート'/'再起動' ボタンをクリックした後

  • はゲームが右を開始します、人間やAIのどちらかのプレイヤーは、その判断/アルゴリズムに基づいてゲームボードのボタンをクリックします。

  • Human().decide_ui(self) SomeAI().decide_ui(self)はいくつかのアルゴリズムに基づいてゲームボードのボタンをクリックします。

  • TicTacToe()は、ゲームボードマトリックスと当選基準を格納するオブジェクトです。


あなたがゲームをプレイに興味がある場合は、コードhereのセット全体をダウンロードすることができます。

+0

AIがゲームを終了するスピードを遅くする必要があります。あなたは 'QTimer'クラスを試すことができます。 – Crispin

+0

@Crispin私のAIの中には1回転ごとに1-2秒かかるものもありますが、最終結果は数秒後に直ちに表示されます。中間のものは見えません。 – kitman0804

答えて

1

私はプロセス全体をよりよく理解するために完全なアプリをダウンロードしました。

実行中、AIはメインプロセスをビジー状態に保ち、Qtイベントは処理されず、UIに何も描画されません。

def click(self, row, col): 
    # "click" code 

    QtWidgets.qApp.processEvents() 

    # Next turn 
    if self._game.is_ended: 
     pass 
    else: 
     self._game.players[self._game.turn_player].decide_ui(self) 

これは、すべての保留中のイベントを処理し、移動は、一度に1つ表示されます。

最も簡単な解決策は、このように、毎ターンQApplication.processEvents()を呼び出すことです。

+0

これは機能します。ありがとう! – kitman0804

関連する問題