Tro choi
Bạn sẽ chơi một trò chơi tiêu chuẩn (gần như) của Connect-4 . Thật không may, đây là một trò chơi tương ứng và ai đó đã đặt băng đen trên mỗi hàng thứ hai bắt đầu từ phía dưới, do đó bạn không thể thấy bất kỳ động thái nào của đối thủ trong các hàng này.
Bất kỳ di chuyển nào trong các cột đã đầy sẽ được tính là vượt qua lượt của bạn và nếu trò chơi diễn ra lâu hơn 6 * 7
lượt, nó sẽ được coi là một trận hòa.
Đặc tả thử thách
Chương trình của bạn nên được thực hiện dưới dạng hàm Python 3. Đối số đầu tiên là 'chế độ xem' của bảng, biểu thị trạng thái bảng đã biết dưới dạng danh sách 2D các hàng từ dưới lên trên, trong đó 1
di chuyển bởi người chơi thứ nhất, 2
di chuyển bởi người chơi thứ hai và 0
vị trí trống hoặc ẩn di chuyển bởi đối thủ của bạn.
Đối số thứ hai là số lần lượt được lập chỉ mục từ 0
và tính chẵn lẻ của nó cho bạn biết bạn là người chơi nào.
Đối số cuối cùng là một trạng thái tùy ý, được khởi tạo None
ở đầu mỗi trò chơi, bạn có thể sử dụng để duy trì trạng thái giữa các lượt.
Bạn nên trả về 2-tuple của chỉ mục cột bạn muốn chơi và trạng thái mới sẽ được trả lại cho bạn vào lượt tiếp theo.
Chấm điểm
Một chiến thắng được tính là +1
, một trận hòa 0
và một trận thua là -1
. Mục tiêu của bạn là đạt được số điểm trung bình cao nhất trong một giải đấu vòng tròn. Tôi sẽ cố gắng chạy nhiều trận theo yêu cầu để xác định người chiến thắng rõ ràng.
Quy tắc
Bất kỳ đối thủ cạnh tranh nào cũng nên có nhiều nhất một bot cạnh tranh tại một thời điểm, nhưng bạn có thể cập nhật mục nhập của mình nếu bạn tiến bộ. Hãy cố gắng giới hạn bot của bạn trong ~ 1 giây thời gian suy nghĩ mỗi lượt.
Kiểm tra
Dưới đây là mã nguồn cho bộ điều khiển, cùng với một vài bot ví dụ không cạnh tranh để tham khảo:
import itertools
import random
def get_strides(board, i, j):
yield ((i, k) for k in range(j + 1, 7))
yield ((i, k) for k in range(j - 1, -1, -1))
yield ((k, j) for k in range(i + 1, 6))
yield ((k, j) for k in range(i - 1, -1, -1))
directions = [(1, 1), (-1, -1), (1, -1), (-1, 1)]
def diag(di, dj):
i1 = i
j1 = j
while True:
i1 += di
if i1 < 0 or i1 >= 6:
break
j1 += dj
if j1 < 0 or j1 >= 7:
break
yield (i1, j1)
for d in directions:
yield diag(*d)
DRAWN = 0
LOST = 1
WON = 2
UNDECIDED = 3
def get_outcome(board, i, j):
if all(board[-1]):
return DRAWN
player = board[i][j]
strides = get_strides(board, i, j)
for _ in range(4):
s0 = next(strides)
s1 = next(strides)
n = 1
for s in (s0, s1):
for i1, j1 in s:
if board[i1][j1] == player:
n += 1
if n >= 4:
return WON
else:
break
return UNDECIDED
def apply_move(board, player, move):
for i, row in enumerate(board):
if board[i][move] == 0:
board[i][move] = player
outcome = get_outcome(board, i, move)
return outcome
if all(board[-1]):
return DRAWN
return UNDECIDED
def get_view(board, player):
view = [list(row) for row in board]
for i, row in enumerate(view):
if i % 2:
continue
for j, x in enumerate(row):
if x == 3 - player:
row[j] = 0
return view
def run_game(player1, player2):
players = {1 : player1, 2 : player2}
board = [[0] * 7 for _ in range(6)]
states = {1 : None, 2 : None}
for turn in range(6 * 7):
p = (turn % 2) + 1
player = players[p]
view = get_view(board, p)
move, state = player(view, turn, states[p])
outcome = apply_move(board, p, move)
if outcome == DRAWN:
return DRAWN
elif outcome == WON:
return p
else:
states[p] = state
return DRAWN
def get_score(counts):
return (counts[WON] - counts[LOST]) / float(sum(counts))
def run_tournament(players, rounds=10000):
counts = [[0] * 3 for _ in players]
for r in range(rounds):
for i, player1 in enumerate(players):
for j, player2 in enumerate(players):
if i == j:
continue
outcome = run_game(player1, player2)
if outcome == DRAWN:
for k in i, j:
counts[k][DRAWN] += 1
else:
if outcome == 1:
w, l = i, j
else:
w, l = j, i
counts[w][WON] += 1
counts[l][LOST] += 1
ranks = sorted(range(len(players)), key = lambda i: get_score(counts[i]), reverse=True)
print("Round %d of %d\n" % (r + 1, rounds))
rows = [("Name", "Draws", "Losses", "Wins", "Score")]
for i in ranks:
name = players[i].__name__
score = get_score(counts[i])
rows.append([name + ":"] + [str(n) for n in counts[i]] + ["%6.3f" % score])
lengths = [max(len(s) for s in col) + 1 for col in zip(*rows)]
for i, row in enumerate(rows):
padding = ((n - len(s)) * ' ' for s, n in zip(row, lengths))
print(''.join(s + p for s, p in zip(row, padding)))
if i == 0:
print()
print()
def random_player(view, turn, state):
return random.randrange(0, 7), state
def constant_player(view, turn, state):
return 0, state
def better_random_player(view, turn, state):
while True:
j = random.randrange(0, 7)
if view[-1][j] == 0:
return j, state
def better_constant_player(view, turn, state):
for j in range(7):
if view[-1][j] == 0:
return j, state
players = [random_player, constant_player, better_random_player, better_constant_player]
run_tournament(players)
Chúc bạn vui vẻ!
Kết quả tạm thời
Name Draws Losses Wins Score
zsani_bot: 40 5377 94583 0.892
better_constant_player: 0 28665 71335 0.427
constant_player: 3 53961 46036 -0.079
normalBot: 38 64903 35059 -0.298
better_random_player: 192 71447 28361 -0.431
random_player: 199 75411 24390 -0.510