-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConnect4.py
More file actions
137 lines (102 loc) · 4.11 KB
/
Copy pathConnect4.py
File metadata and controls
137 lines (102 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import time
from typing import List
import helpers
from copy import deepcopy
from mpi4py import MPI
from Board import Board, Mover, Winner
from helpers import Message, EVENT
comm = MPI.COMM_WORLD
RANK = comm.Get_rank()
SIZE = comm.Get_size()
MASTER_PID = 0
DEPTH = 4
BOARD = Board()
def CPU_move():
board = deepcopy(BOARD) # make copy of original board to simulate plays
message = Message(EVENT.SEND_BOARD, board)
comm.bcast(message.to_dict(), root=MASTER_PID)
tasks = helpers.generate_tasks(BOARD.total_columns, DEPTH)
results = dict()
for i in range(1, BOARD.total_columns + 1):
results[i] = list()
while len(tasks):
status = MPI.Status()
# wait on message from any worker
data = comm.recv(source=MPI.ANY_SOURCE, status=status)
# parse message
message = Message.from_dict(data)
# get ready worker ID
from_pid = status.Get_source()
if message.type == EVENT.SEND_TASK:
# if message was request for task
send_task_msg = Message(EVENT.SEND_TASK, tasks.pop())
# send that worker next task
helpers.send_msg_to_worker(send_task_msg, from_pid)
if message.type == EVENT.SEND_RESULT:
data = message.payload # [result, column]
results[data[1]].append(data[0])
message_board_complete = Message(EVENT.BOARD_COMPLETE)
for pid in range(1, SIZE): helpers.send_msg_to_worker(message_board_complete, pid)
return helpers.calculate_best_move(results)
def game_over(mover: Mover):
mvr = 'CPU' if mover == Mover.CPU else 'PLAYER'
print('GAME OVER, ' + mvr + ' WINN!!!', flush=True)
MPI.Finalize()
exit(0)
def master_process():
# setup board and screen
BOARD.load()
BOARD.render()
while True:
column = int(input("Select column: "))
if not BOARD.is_move_legal(column):
BOARD.render('Illegal move')
continue
BOARD.move(column, Mover.PLAYER, log=True) # move player
BOARD.render()
if BOARD.is_game_over(): game_over(Mover.PLAYER)
print('CPU is thinking...', flush=True)
BOARD.move(CPU_move(), Mover.CPU, log=True) # move CPU
BOARD.render()
if BOARD.is_game_over(): game_over(Mover.CPU)
def worker_process():
while True:
data = comm.bcast(None, root=0)
board_message = Message.from_dict(data)
if board_message.type == EVENT.SEND_BOARD:
# get board copy from payload
board: Board = board_message.payload
while True:
# send request for task
helpers.send_msg_to_master(Message(EVENT.SEND_TASK))
# receive task
task_message = helpers.recv_msg(MASTER_PID)
# if current move is calculated, go request new board
if task_message.type == EVENT.BOARD_COMPLETE:
break
moves_made = 0
last_mover = Mover.CPU
tasks: List = task_message.payload
for i, move in enumerate(tasks):
# play moves from task and check if move leeds to game over
mover = Mover.CPU if i % 2 == 0 else Mover.PLAYER
if board.is_move_legal(move):
board.move(move, mover)
moves_made += 1
last_mover = mover
if board.is_game_over():
send_result = Winner.CPU if mover == Mover.CPU else Winner.PLAYER
helpers.send_msg_to_master(Message(EVENT.SEND_RESULT, (send_result, tasks[0])))
break
result = board.evaluate(last_mover, DEPTH - len(tasks))
helpers.send_msg_to_master(Message(EVENT.SEND_RESULT, (result, tasks[0])))
for _ in range(moves_made): board.undo_move() # clean moves
time.sleep(1) # only while waiting for board
def main():
if RANK == MASTER_PID:
master_process()
else:
worker_process()
if __name__ == '__main__':
comm.barrier()
main()