목 차
1. 들어가며
2. 사전설명
3. 코드설명
1) 3 x 3 공간을 선언
2) x, o 플레이어는 3 x 3 공간에 데이터를 입력
3) 승/패 및 게임 재시작을 작성
4. 전체코드
5. 마치며
1. 들어가며
해외선물 자동매매를 구현하는데, 파이썬 언어는 어느정도 숙지를 했지만, 알고리즘을 제대로 설정하지 못해서 계속 손실을 보고 있다. 기존의 고전적인 방법(rsi 지표, 급등/급락후 진입 등)으로는 수익을 내기 힘들것 같다.
그래서 계속 수익내는 방법을 고민해보고 있다. 이번에 접근하는 알고리즘은 몬테카를로 트리 서치(Monte Carlo Tree Search, MCTS)이다. 많이 들어봤을 2016년 알파고(Alphago)가 활용했던 방법이다.
언제적 알파고냐... 잠깐 망설에게 되지만, 그래도 하나둘 고민하다보면 답이 나오겠지... 뭐라도 하는게 좋다. 이번 도전이 만만하지는 않지만, MCTS를 잘 이해해보려고 하는데, 개념이 상당히 어렵다. 조금더 인내심을 가지고 MCTS를 공부해보자.
처음부터 알파고의 바둑(GO)을 목표로 MCTS를 구현할 자신이 없다. 틱택톡(tic tac toe)을 기반으로 MCTS를 공부해보려고 한다.
아래 틱택톡 코드는 유튜버 TokyoEdtech님의 글이다. 영어로된 설명이 어려울 수는 있겠지만, 자막을 켜고 보면 이해가 될 것 같다.
※ 코드 출처 : https://www.youtube.com/watch?v=7Djh-Cbgi0E
2. 사전설명
틱택톡(tic tac toe)은 한방향으로 세개칸을 한방향으로 점령하면 승리하게 된다.
틱택톡의 규칙은 간단하다.
1) 상대방과 번갈아 가면 총 9칸에 수(手)를 둔다.
2) 한줄 방향으로 3개칸을 차지하면 이긴다. 물론 9수 내 3개 칸을 차지하지 못하면 무승부가 난다.
3) 이기는 방법은 8가지이다.
- 가로축(①②③) : [1, 2, 3], [4,5,6], [7,8,9],
- 세로축(④⑤⑥) : [1,4,7], [2,5,8], [3,6,9],
- 대각선(⑦⑧) : [1, 5,9], [3,5,7]
![](https://blog.kakaocdn.net/dn/cdlEyb/btsCUZa5ZGY/AMnK56UNS2WWqbaLcz6mG0/img.png)
4) os.system('cls')는 파이참에서 실행되지 않음
파이썬 코드를 windows 파이참에서 구현한다면, 약간의 불편사항은 있다.
위의 링크는 linux나 mac으로 구현하려고 하는 것으로 보이나, windows의 파이참에서는 Run창은 cls 혹은 clean이 실행되지 않는다.
3. 코드설명
유튜버 TokyoEdtech님의 코드를 크게 변경하지 않는 범위 내에서 코드를 작성한다. 위에서 설명한대로 os.system('cls')가 실행되지 않으므로 클래스를 선언하는 것부터 시작한다.
전체코드는 4번(전체코드)에서 확인가능하다. 아래에서는 틱택톡이 만들어지는 과정을 알아본다.
1) 3 x 3 공간을 선언한다.
class Board():
def __init__(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def display(self):
print()
print(" %s | %s | %s " %(self.cells[1], self.cells[2], self.cells[3]))
print("-----------")
print(" %s | %s | %s " %(self.cells[4], self.cells[5], self.cells[6]))
print("-----------")
print(" %s | %s | %s " %(self.cells[7], self.cells[8], self.cells[9]))
def print_header(self):
print("Welcome to Tic-Tac-Toe")
def refresh_screen(self):
## clear the screen
# os.system('cls')
# print the header
board.print_header()
# show the board
board.display()
if __name__ == "__main__":
board = Board()
board.display()
1줄 : Board 클래스를 선언한다.
2줄 : 최초로 선언된 함수(__init__)를 선언한다.
3줄 : 3 x 3의 공간의 리스트를 선언한다. 자! 여기서 주의할 것은 리스트 내 문자(빈칸)를 10개를 선언한다. 이것은 리스트 첫번째 요소는 [0]인데, 두번째 요소[1]를 3 x 3의 공간과 일치시키기 위해 10개를 넣었다.
5줄~11줄 : 3 x 3을 print문을 활용하여 파이참의 Run창에 구현한다. 우리가 숫자를 입력하면 display 함수가 실행되어 파이참의 Run창에 출력된다.
16줄~17줄 : windows의 파이참 Run창은 초기화(clean)가 되지 않으므로 주석(17줄~18줄)처리했다. 데이터가 입력되면, 5줄~11줄의 print문을 출력하는 3 x 3의 창을 업데이트한다.
2) x, o 플레이어는 3 x 3 공간에 데이터를 입력한다.
여기에서 추가/수정된 사항은 26줄~46줄(데이터 입력내용 추가) 및 53줄(실행함수 수정)이다.
class Board():
def __init__(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def display(self):
print()
print(" %s | %s | %s " %(self.cells[1], self.cells[2], self.cells[3]))
print("-----------")
print(" %s | %s | %s " %(self.cells[4], self.cells[5], self.cells[6]))
print("-----------")
print(" %s | %s | %s " %(self.cells[7], self.cells[8], self.cells[9]))
def print_header(self):
print("Welcome to Tic-Tac-Toe")
def refresh_screen(self):
## clear the screen
# os.system('cls')
# print the header
board.print_header()
# show the board
board.display()
def update_cell(self, cell_no, player):
if self.cells[cell_no] == " ":
self.cells[cell_no] = player
def game_start(self):
while True:
board.refresh_screen() # 스크린 새로 고치기
######### 플레이 입력 ##########
# get x input
x_choice = int(input("\nx) please choose 1-9. > "))
# updata board
board.update_cell(x_choice, "x")
board.refresh_screen() # 스크린 새로 고치기
# get o input
o_choice = int(input("\no) please choose 1-9. > "))
# updata board
board.update_cell(o_choice, "o")
################################################
if __name__ == "__main__":
board = Board()
board.game_start()
26줄~28줄 : 공간번호(cell_no)가 공란이면, 공란에 플레이어(x, o)를 넣어라. 여기서 27줄~28줄이 중요하다. 1~9까지의 공간이 빈칸(" ")일 때만 숫자를 나타낸다. (중복입력 방지)
30줄~46줄 : 플레이어(x, o)가 입력 및 3 x 3공간을 새로고침(현행화)한다.
32줄 : 3 x 3 공간을 새로고침(현행화)한다.
35줄 : x 플레이어는 1~9까지 데이터를 입력(int)하고 정수화(int)한다.
38줄 : x플레이어의 "x" 표시를 26줄~28줄에 넣는다.
40줄 : 3 x 3 공간을 16줄~24줄의 함수에 의해 새로고침(현행화)한다.
43줄~46줄 : o플레이어의 데이터(1~9까지)를 입력하고 26줄~28줄의 공간을 업데이트 한다.
3) 승/패 및 게임 재시작을 구현한다.
여기에서 추가된 사항은 27줄~50줄(게임승리 및 무승부 정의), 65줄~98줄(승리, 무승부 확인)이다.
class Board():
def __init__(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def display(self):
print()
print(" %s | %s | %s " %(self.cells[1], self.cells[2], self.cells[3]))
print("-----------")
print(" %s | %s | %s " %(self.cells[4], self.cells[5], self.cells[6]))
print("-----------")
print(" %s | %s | %s " %(self.cells[7], self.cells[8], self.cells[9]))
def print_header(self):
print("Welcome to Tic-Tac-Toe")
def refresh_screen(self):
# print the header
board.print_header()
# show the board
board.display()
def update_cell(self, cell_no, player):
if self.cells[cell_no] == " ":
self.cells[cell_no] = player
def who_is_winner(self, player):
for combo in [[1,2,3], [4,5,6], [7,8,9], [1,4,7], [2,5,8], [3,6,9], [3,5,7], [1,5,9]]:
self.result = True
for cell_no in combo:
if self.cells[cell_no] != player:
self.result = False
if self.result == True:
return True
return False
def tie_game(self):
used_cells = 0
for cell in self.cells:
if cell != " ":
used_cells +=1
if used_cells == 9:
print("45줄")
return True
else:
return False
def reset_board(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def game_start(self):
while True:
board.refresh_screen() # 스크린 새로 고치기
######### 플레이 입력 ##########
# get x input
x_choice = int(input("\nx) please choose 1-9. > "))
# updata board
board.update_cell(x_choice, "x")
board.refresh_screen() # 스크린 새로 고치기
# check for an x win
if board.who_is_winner("x") == True:
print("\nx wins!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
# check for a tie game
if board.tie_game():
print("\ntie game!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
# get o input
o_choice = int(input("\no) please choose 1-9. > "))
# updata board
board.update_cell(o_choice, "o")
# check for an o win
if board.who_is_winner("o") == True:
print("\no wins!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
if __name__ == "__main__":
board = Board()
board.game_start()
27줄~37줄 : 승리방식을 정의한다.
28줄 : 위에서도 설명하였으만, 틱택톡(tic-tac-toe)의 승리 요건 8가지 중 1가지에 해당하면 승리한다.
- 가로축 : [1, 2, 3], [4,5,6], [7,8,9],
- 세로축 : [1,4,7], [2,5,8], [3,6,9],
- 대각선 : [1, 5,9], [3,5,7]
29줄 : 결과가 true이면 게임의 승리/무승부를 결정한다. 최초에는 self.result = True로 선언한다.
30줄 : 승리방식(1,2,3 등)에서 숫자를 하나씩 추출한다.
31줄~32줄 : 예를 들어 [1,2,3]에서 같은 결과(o, o, o)가 아닌 다른 결과(o, o, x)이면, 결과는 거짓(False)이다.
34줄~35줄 : 30줄~32줄이 거짓(False)이 아닌 진실(True)이면 65줄(x 승) 및 81줄(o 승)에 True를 반환한다.
37줄 : 28줄~35줄이 모두 거짓이면, 65줄(x 승) 및 81줄(o 승)에 False를 반환한다.
39줄~47줄 : 무승부를 정의한다.
40줄 : 셀에 내용이 추가되었는지 확인하기 위해 임의로 0을 선언한다.
41줄 : 3 x 3공간(리스트)에 입력된 내용을 for 문으로 돌려서 확인한다.
42줄~43줄 : 여기서 약간 어렵게 느껴진다. 3 x 3공간(리스트)의 셀이 빈칸이 아니면, 41줄의 셀에 1씩 더한다. 바꾸어 이야기하면, x,o플레이어 1개씩 입력하면, 빈칸이 없어지면서, used_cells가 1씩 증가한다.
44줄~45줄 : 41줄~43줄의 for문에 의해 used_cells가 9이면(빈칸이 없으면=승패가 안 났으면), 92줄로 무승부(tie_game)를 True로 반환한다.
49줄~50줄 : 게임을 새로 시작(69줄, 85줄)할 경우 리스트(3줄, 40줄)을 초기화한다.
66줄~67줄 : x플레이어의 결과(27줄~37줄)가 True이면, x wins를 출력하라.
68줄 : 게임을 다시 시작할지 묻는다. (upper는 소문자를 대문자로 변환)
69줄~71 : Y를 입력하면, 50줄(reset_board)의 리스트(3x3 공간)을 초기화하과, 게임을 재개한다.
72~73줄 : Y가 아닌 경우, 멈춘다.(break)
75줄~83줄 : 39줄~48줄의 tie_game 함수에 의해 무승부가 반환(True)되면, 92줄에서 무승부로 출력되고, 재게임할지 결정한다.
※ 여기서 중요한건, 65줄~73줄(x플레이어 승리) 및 85줄~99줄(o플레이어 승리) 사이에 무승부를 규정한 것이다. 여기서 정의한 이유는? 틱택톡은 총 9개 칸에 9수(手)를 3 x 3공간에 둔다. x플레이어가 시작하면, 교대로 수(手)를 두다가 마지막에 x플레이어가 한번더 둔다. 무승부 결정은 x플레이어 9번째 수를 두고 나서 결정난다.
바꾸어 이야기하면, 85줄~99줄 밑에 무승부를 정의하면, o플레이어가 10번째 수(실제는 3x3 공간을 다 채웠다)를 두고나서 무승부가 결정되는 결과를 가져오기 때문에, 85줄~99줄 앞에 무승부(tie_game)를 정의하고, 실행한다.
85줄~99줄 : 66줄~70줄과 동일하게 o플레이어의 결과 및 게임을 재개할지 입력한다.
102줄 : 1줄의 Board() 클래스를 board 변수에 인스턴스한다.(=변수화한다)
104줄 : 53줄의 함수를 실행한다. while문이 true일때 게임은 계속 진행된다.
4. 전체코드
틱택톡 전체코드는 아래와 같다. 여유있을 때 실행을 해보고, 코드 진행현황을 알아보는 것도 좋아보인다.
class Board():
def __init__(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def display(self):
print()
print(" %s | %s | %s " %(self.cells[1], self.cells[2], self.cells[3]))
print("-----------")
print(" %s | %s | %s " %(self.cells[4], self.cells[5], self.cells[6]))
print("-----------")
print(" %s | %s | %s " %(self.cells[7], self.cells[8], self.cells[9]))
def print_header(self):
print("Welcome to Tic-Tac-Toe")
def refresh_screen(self):
# print the header
board.print_header()
# show the board
board.display()
def update_cell(self, cell_no, player):
if self.cells[cell_no] == " ":
self.cells[cell_no] = player
def who_is_winner(self, player):
for combo in [[1,2,3], [4,5,6], [7,8,9], [1,4,7], [2,5,8], [3,6,9], [3,5,7], [1,5,9]]:
self.result = True
for cell_no in combo:
if self.cells[cell_no] != player:
self.result = False
if self.result == True:
return True
return False
def tie_game(self):
used_cells = 0
for cell in self.cells:
if cell != " ":
used_cells +=1
if used_cells == 9:
print("45줄")
return True
else:
return False
def reset_board(self):
self.cells = [" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
def game_start(self):
while True:
board.refresh_screen() # 스크린 새로 고치기
######### 플레이 입력 ##########
# get x input
x_choice = int(input("\nx) please choose 1-9. > "))
# updata board
board.update_cell(x_choice, "x")
board.refresh_screen() # 스크린 새로 고치기
# check for an x win
if board.who_is_winner("x") == True:
print("\nx wins!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
# check for a tie game
if board.tie_game():
print("\ntie game!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
# get o input
o_choice = int(input("\no) please choose 1-9. > "))
# updata board
board.update_cell(o_choice, "o")
# check for an o win
if board.who_is_winner("o") == True:
print("\no wins!\n")
play_again = input("would you like to play again? (Y/N)").upper()
if play_again == "Y":
board.reset_board()
continue
else:
break
if __name__ == "__main__":
board = Board()
board.game_start()
5. 마치며
틱택톡(tic tac toe) 게임의 코드를 작성하는 방법을 알아보았다. 100줄 정도되는 코드이지만, 생각보다 알차게 작성한 느낌이다. 위의 코드는 2인이 서로 번갈아가며 3 x 3공간에 최상의 수(手)를 두면서 게임을 진행한다.
다음시간에는 1인(나) vs 컴퓨터(pc)의 게임을 구현할 것이다. 컴퓨터(pc)는 ai가 아닌, random 함수를 통해 임의로 수(手)를 두는 형태로 코드를 작성할 예정이다.
'2. 해외선물 > 2-2. 해외선물 알고리즘 연구' 카테고리의 다른 글
(해외선물 자동매매 알고리즘) (2) 선형회귀분석 설명 (경사하강법) (2) | 2024.01.30 |
---|---|
(해외선물 자동매매 알고리즘) (1) 선형회귀분석 설명 (개념설명) (2) | 2024.01.29 |
(해외선물 자동매매 알고리즘) (3) MCTS를 활용하여 틱택톡 만들기 (2) | 2024.01.22 |
(해외선물 자동매매 알고리즘) (2) 틱택톡 만들기 (컴퓨터와 대결) (2) | 2024.01.01 |
(해외선물 자동매매 알고리즘) (2) rsi 70이상, 30이하 넓이 구하기 (2) | 2023.12.24 |
(해외선물 자동매매 알고리즘) (1) rsi 70이상, 30이하 넓이 개념 설명 (0) | 2023.12.23 |
(해외선물 자동매매 알고리즘) (2) rsi 보조지표의 알고리즘 관련 (2) | 2023.11.07 |
(해외선물 자동매매 알고리즘) (1) 매매 알고리즘 개념 설명 (0) | 2023.11.06 |