From af96206d62f68e6b93911caa0078282828758f54 Mon Sep 17 00:00:00 2001 From: JunhoYeo <32605822+JunhoYeo@users.noreply.github.com> Date: Sun, 20 May 2018 18:57:59 +0900 Subject: [PATCH] =?UTF-8?q?dev=20:=20=ED=98=84=EC=9E=AC=20AI=EA=B0=80=20?= =?UTF-8?q?=EB=B3=B4=EB=8A=94=20=EA=B2=8C=EC=9E=84=ED=8C=90=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=A5=BC=20=EB=B0=94=ED=83=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=B6=94=EB=A1=A0=ED=95=9C=20=EA=B0=92=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 그냥 좀 있어 보임 --- app.py | 65 +++++++++++++++++++++++----- game.py | 128 ++++++++++++++++++++++++++++++++++++-------------------- net.py | 20 ++++----- 3 files changed, 146 insertions(+), 67 deletions(-) diff --git a/app.py b/app.py index 1bd677d..9c4f7a8 100644 --- a/app.py +++ b/app.py @@ -5,17 +5,17 @@ from net import * from game import * -if __name__ == '__main__': - net = Network(26, [50, 100], 26) - # x = np.array([1.0, 0.5]) - # y = network.predict(x) - # print(y) - print('w1 shape : ' + str(net.params['w1'].shape)) - print('L b1 shape : ' + str(net.params['b1'].shape)) - print('w2 shape : ' + str(net.params['w2'].shape)) - print('L b2 shape : ' + str(net.params['b2'].shape)) - print('w3 shape : ' + str(net.params['w3'].shape)) - print('L b3 shape : ' + str(net.params['b3'].shape)) +# if __name__ == '__main__': +# net = Network(26, [50, 100], 26) +# # x = np.array([1.0, 0.5]) +# # y = network.predict(x) +# # print(y) +# print('w1 shape : ' + str(net.params['w1'].shape)) +# print('L b1 shape : ' + str(net.params['b1'].shape)) +# print('w2 shape : ' + str(net.params['w2'].shape)) +# print('L b2 shape : ' + str(net.params['b2'].shape)) +# print('w3 shape : ' + str(net.params['w3'].shape)) +# print('L b3 shape : ' + str(net.params['b3'].shape)) # 현재 게임판의 타일 상태를 입력으로 받음 # 배열의 인덱스 : 흰 타일(0~11 + 조커) + 검은 타일(0~11 + 조커) => 26개 원소(인덱스 0~25) @@ -102,6 +102,49 @@ # plt.legend(loc='lower right') # plt.show() +if __name__ == '__main__': + net = Network(26, [50, 200, 800], 676) + print('w1 shape : ' + str(net.params['w1'].shape)) + print('L b1 shape : ' + str(net.params['b1'].shape)) + print('w2 shape : ' + str(net.params['w2'].shape)) + print('L b2 shape : ' + str(net.params['b2'].shape)) + print('w3 shape : ' + str(net.params['w3'].shape)) + print('L b3 shape : ' + str(net.params['b3'].shape)) + print('w4 shape : ' + str(net.params['w4'].shape)) + print('L b4 shape : ' + str(net.params['b4'].shape)) + print('network ready\n') + + game = newGame() + m1 = ai(1) # monorial 1 + m2 = ai(2) # monorial 2 + + m1.getTiles(game) + m1.sortTiles(game) + m2.getTiles(game) + m2.sortTiles(game) + game.updateAll(m1, m2) # 패 다 뽑았으면 업데이트 + print('m1 : tiles\n' + m1.printTiles(game)) + print('m2 : tiles\n' + m2.printTiles(game)) + + # ai에 turn 메소드가 있어서 자신 턴에 드로우 하고 하는 처리를 만들어도 좋을 것 같음 + print('m1 : draw') + m1.drawTiles(game) + game.updatePlayerTiles(1, m1) # 드로우 후 업데이트 + print('m1 : tiles\n' + m1.printTiles(game)) + print('m1 : view\n' + str(m1.getAiView(game)) + '\n') # m1가 보는 게임판 상황 가져오기 + + # 인공신경망에 input(test) + test_data = [] + test_data.append(m1.tile_view) + x = np.array(test_data) + print(x) + y = net.predict(x) + print(y) + print(y.tolist()[0]) + + # output을 처리 후 행동 + # 원래 정답을 구하고 한 100번?쯤 train + # 2. input data, get output # 3. output과 answer(상대의 타일)를 비교, get loss diff --git a/game.py b/game.py index 427a62c..9ab77dc 100644 --- a/game.py +++ b/game.py @@ -3,7 +3,7 @@ import random -def getTileData(tile): +def getTileData(tile, game): tile_data = [] if tile == 12: # white joker tile_data.append('white') @@ -17,6 +17,11 @@ def getTileData(tile): else: # white tile tile_data.append('white') tile_data.append(tile) + # game.revealed 확인 + if tile in game.revealed: + tile_data.append('known') + else: + tile_data.append('unknown') return tile_data class newGame: @@ -24,10 +29,26 @@ def __init__(self): self.deck = [] for tile in range(26): self.deck.append(tile) # 덱에 타일들을 채움 + self.revealed = [] # 공개된 타일을 이곳에 저장한 뒤 하나씩 맞춰보는 식으로 한다 + self.player1tiles = [] # player 1 패 + self.player2tiles = [] # player 2 패 + + def updatePlayerTiles(self, playerNum, player): + if playerNum == 1: + self.player1tiles = player.tiles + else: + self.player2tiles = player.tiles + # 사용자 타일 정보를 업데이트 + + def updateAll(self, player1, player2): + self.updatePlayerTiles(1, player1) + self.updatePlayerTiles(2, player2) class ai: - def __init__(self): + def __init__(self, _playerNum): + self.playerNum = _playerNum # 해당 ai의 플레이어 번호 self.tiles = [] # 해당 ai가 가진 현재 타일(패) + # self.tiles_side = [] # 같은 인덱스의 현재 타일의 면(앞면 2/뒷면 0) self.tiles_view = [] # 해당 ai가 보는 게임판 위의 현재 타일 상태(0~25 index로 표현) # tiles_view는 곧 신경망의 input self.current_tile = 'none' # 이번 턴 드로우한 타일, 없으면 none @@ -38,22 +59,24 @@ def getTiles(self, game): for tile in newtiles: game.deck.remove(tile) # 덱에서 빼고 self.tiles.append(tile) # ai 패에 넣기 + # for tile in self.tiles: + # self.tiles_side.append(0) # 처음에는 각 모두 뒷면(상대에게 unknown) - def sortTiles(self): + def sortTiles(self, game): # getTiles() 실행 이후, 랜덤하게 가져온 타일을 정렬 # 13번부터 검은 타일(검은 타일 숫자 = n-13), 12/25번 조커 jokers = [] for tile in self.tiles: - if getTileData(tile)[1] == 'joker': + if getTileData(tile, game)[1] == 'joker': jokers.append(tile) self.tiles.remove(tile) # 조커가 있을 경우 정렬 전 조커 인덱스 따로 저장 # 정렬 시작 blackTiles = [] for tile in self.tiles: - if getTileData(tile)[0] == 'black': + if getTileData(tile, game)[0] == 'black': blackTiles.append(tile) # 먼저 검정 타일은 타일의 인덱스 따로 저장 for idx, tile in enumerate(self.tiles): - if getTileData(tile)[0] == 'black': + if getTileData(tile, game)[0] == 'black': self.tiles[idx] -= 13 # self.tiles에서는 검정 타일 원래 수만 남겨 놓고(-13) self.tiles.sort() # 오름차순으로 정렬 for blackTile in blackTiles: @@ -71,11 +94,11 @@ def sortTiles(self): # print('joker : ' + str(joker)) # self.tiles의 랜덤 위치에 처음에 따로 빼 둔 조커를 끼워 넣음 - def printTiles(self): + def printTiles(self, game): tiles = '' for tile in self.tiles: - tiles += str(getTileData(tile)) - tiles += ' ' + tiles += str(getTileData(tile, game)) + tiles += '\n' return tiles def drawTiles(self, game): @@ -83,67 +106,80 @@ def drawTiles(self, game): return # 덱에 카드가 없으면 드로우하지 못함 drawTile = random.choice(game.deck) game.deck.remove(drawTile) - print(str(getTileData(drawTile))) # print data of drawed tile + self.current_tile = drawTile # 현재 드로우한 타일을 저장(패 깔 때 필요함) + print(str(getTileData(drawTile, game)) + '\n') # print data of drawed tile # game.deck에서 타일 하나를 랜덤으로 가져와 => random.choice(game.deck) # self.tiles.append(drawTile) # 현재 타일에 추가 # 이 부분을 그냥 뒷부분에 추가하는 대신, 제대로 된 위치로 가게 수정해야 함 # 어떻게? 리스트의 두 수를 비교한 뒤 색에 따라 추가할지 결정하는 식으로 가능 # 만약 새로 가져온 타일이 조커라면 랜덤으로 넣어야 하니까 먼저 확인해야 함 - if (getTileData(drawTile)[1] == 'joker'): # 드로우한 타일이 조커 (랜덤 추가) - self.tiles.insert(random.randrange(len(self.tiles)+1), drawTile) + insert = 0 # 타일을 삽입한 위치 + if (getTileData(drawTile, game)[1] == 'joker'): # 드로우한 타일이 조커 (랜덤 추가) + insert = random.randrange(len(self.tiles)+1) + self.tiles.insert(insert, drawTile) # 현재 패의 랜덤 위치에 조커를 삽입 else: - # getTileData(tile) = [color, number] + # getTileData(tile, game) = [color, number, status] for i in range(len(self.tiles)): # self.tiles의 맨 앞에 추가가 가능한지 확인 - if getTileData(self.tiles[i])[1] == 'joker': + if getTileData(self.tiles[i], game)[1] == 'joker': # 현재 탐색 중인 타일이 조커면 패스 continue - if int(getTileData(self.tiles[i])[1]) > int(getTileData(drawTile)[1]): + if int(getTileData(self.tiles[i], game)[1]) > int(getTileData(drawTile, game)[1]): # 새로 드로우한 타일이 맨 앞 타일의 수보다 크면(앞에 둘 수 있음) self.tiles.insert(i, drawTile) # 원래 타일 앞에 추가 - # print('added on front' + str(getTileData(self.tiles[i]))) + insert = i + # print('added on front' + str(getTileData(self.tiles[i], game))) break - elif int(getTileData(self.tiles[i])[1]) == int(getTileData(drawTile)[1]): + elif int(getTileData(self.tiles[i], game)[1]) == int(getTileData(drawTile, game)[1]): # 새로 드로우한 타일이 맨 앞 타일의 수와 같으면(색에 따라 앞에 둘 수 있음) - if getTileData(drawTile)[0] == 'white': + if getTileData(drawTile, game)[0] == 'white': # 두 타일의 색이 다르니까 원래 있던 타일은 검은색 - self.tiles.insert(i+1, drawTile) + self.tiles.insert(i + 1, drawTile) + insert = i + 1 # 검은색이 흰색보다 앞에 와야 하므로 원래 타일 다음 자리에 추가 - # print('added on next' + str(getTileData(self.tiles[i]))) + # print('added on next' + str(getTileData(self.tiles[i], game))) break else: # 새로 드로우한 타일은 검은색, 원래 타일은 흰색: self.tiles.insert(i, drawTile) # 원래 타일 전 자리에 추가 - # print('added on front' + str(getTileData(self.tiles[i]))) + insert = i + # print('added on front' + str(getTileData(self.tiles[i], game))) break else: if i == len(self.tiles)-1: # 패에 있는 모든 타일보다도 큰 수의 타일 self.tiles.append(drawTile) # print('added on last') continue - -if __name__ == '__main__': - game = newGame() - m1 = ai() # monorial 1 - m2 = ai() # monorial 2 - m1.getTiles(game) - m1.sortTiles() - m2.getTiles(game) - m2.sortTiles() - print('m1 : ' + m1.printTiles()) - print('m2 : ' + m2.printTiles()) - # game start - while(1): - # m1 turn => ai에 turn() 메소드 만들기 - print('m1 : draw') - m1.drawTiles(game) - print('m1 : ' + m1.printTiles()) - # todo - # m1가 보는 게임판 상황 가져오기 - # 인공신경망에 input(test) - # output을 처리 후 행동 - # 원래 정답을 구하고 한 100번?쯤 train - print('m2 : draw') - m2.drawTiles(game) - print('m2 : ' + m2.printTiles()) \ No newline at end of file + # self.tiles_side.insert(insert, 0) + + def getAiView(self, game): + # 상대방의 타일 = 번호 + 상대 패 인덱스 + # 0(상태를 알 수 없음) + # 1(AI가 가진 타일) + # 2 이상(상대방이 가진 타일) + # 모든 타일의 상태가 들어간 사이즈 26(index 0~25)의 배열을 반환하면 됨 + view = [] + for index in range(26): + # index는 데이터 수집이 필요한 타일의 번호 + # index가 본인 패면 1 + # index가 game.revealed에 있으면 상대방 타일이므로 2+상대 패 index + # 둘 다 아니면 0 + if index in self.tiles: # 본인 패 + view.append(1) + elif index in game.revealed: # 본인 것 아니고 공개된 패(상대 패) + # 상대 패는 game.player(?)tiles에 있음 + # index가 game.player(?)tiles에 있으면 상대방 타일 2 + 인덱스(tile_idx) + # (?)은 self.playerNum에 따라 결정 + tile_idx = 0 + if self.playerNum == 1: + tile_idx = game.player2tiles.index(index) + # 상대 playerNum은 2 + else: + tile_idx = game.player1tiles.index(index) + # 상대 playerNum은 1 + view.append(2 + tile_idx) + else: + view.append(0) + self.tile_view = view + return view diff --git a/net.py b/net.py index 9631929..448b833 100644 --- a/net.py +++ b/net.py @@ -154,13 +154,13 @@ def gradient(self, x, t): grads['w4'], grads['b4'] = self.layers['Affine4'].dW, self.layers['Affine4'].db return grads -if __name__ == '__main__': - net = Network(26, [50, 200, 800], 676) - print('w1 shape : ' + str(net.params['w1'].shape)) - print('L b1 shape : ' + str(net.params['b1'].shape)) - print('w2 shape : ' + str(net.params['w2'].shape)) - print('L b2 shape : ' + str(net.params['b2'].shape)) - print('w3 shape : ' + str(net.params['w3'].shape)) - print('L b3 shape : ' + str(net.params['b3'].shape)) - print('w4 shape : ' + str(net.params['w4'].shape)) - print('L b4 shape : ' + str(net.params['b4'].shape)) +# if __name__ == '__main__': +# net = Network(26, [50, 200, 800], 676) +# print('w1 shape : ' + str(net.params['w1'].shape)) +# print('L b1 shape : ' + str(net.params['b1'].shape)) +# print('w2 shape : ' + str(net.params['w2'].shape)) +# print('L b2 shape : ' + str(net.params['b2'].shape)) +# print('w3 shape : ' + str(net.params['w3'].shape)) +# print('L b3 shape : ' + str(net.params['b3'].shape)) +# print('w4 shape : ' + str(net.params['w4'].shape)) +# print('L b4 shape : ' + str(net.params['b4'].shape))