Permainan
Anda akan memainkan (hampir) permainan standar Connect-4 . Sayangnya, ini adalah permainan korespondensi dan seseorang telah menempatkan pita hitam di setiap baris kedua mulai dari bawah, sehingga Anda tidak dapat melihat gerakan lawan Anda di dalam baris ini.
Setiap gerakan dalam kolom yang sudah penuh akan dihitung sebagai melewati giliran Anda, dan jika permainan berjalan lebih lama dari 6 * 7
putaran itu akan diputuskan sebagai undian.
Spesifikasi Tantangan
Program Anda harus diimplementasikan sebagai fungsi Python 3. Argumen pertama adalah 'tampilan' papan, yang mewakili status papan yang dikenal sebagai daftar 2D baris dari bawah ke atas di mana 1
adalah gerakan oleh pemain pertama, 2
gerakan oleh pemain kedua, dan 0
posisi kosong atau tersembunyi bergerak oleh lawanmu.
Argumen kedua adalah nomor giliran yang diindeks 0
, dan paritasnya memberi tahu Anda pemain mana Anda.
Argumen terakhir adalah status arbitrer, yang diinisialisasi None
pada awal setiap pertandingan, yang dapat Anda gunakan untuk mempertahankan status di antara belokan.
Anda harus mengembalikan 2-tupel dari indeks kolom yang ingin Anda mainkan, dan status baru untuk dikembalikan kepada Anda giliran berikutnya.
Mencetak gol
Kemenangan dihitung sebagai +1
, imbang sebagai 0
, dan kalah sebagai -1
. Tujuan Anda adalah untuk mencapai skor rata-rata tertinggi dalam turnamen round-robin. Saya akan mencoba menjalankan pertandingan sebanyak yang diperlukan untuk mengidentifikasi pemenang yang jelas.
Aturan
Pesaing mana pun harus memiliki paling banyak satu bot yang bersaing pada satu waktu, tetapi tidak masalah untuk memperbarui entri Anda jika Anda melakukan peningkatan. Silakan coba batasi bot Anda hingga ~ 1 detik dari waktu berfikir per giliran.
Pengujian
Berikut adalah kode sumber untuk pengontrol, bersama dengan beberapa bot contoh yang tidak bersaing untuk referensi:
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)
Selamat KoTHing!
Hasil Sementara
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
sumber
Jawaban:
Bot ini mengambil semua kemenangan pasti, dan jatuh kembali untuk memblokir saingan, tebak kedua secara vertikal dan horizontal atau membuat gerakan acak.
Terima kasih telah memperbaiki run_game!
Changelog:
sumber
normalBot bermain dengan asumsi bahwa bintik-bintik di tengah lebih berharga daripada bintik-bintik di ujungnya. Dengan demikian, ia menggunakan distribusi normal yang berpusat di tengah untuk menentukan pilihannya.
sumber
Ini jelas non-bersaing, tapi tetap sangat berguna untuk debugging ... dan sangat menyenangkan, jika Anda tahu bot Anda cukup baik untuk menipu: D jadi saya memposting dengan harapan menginspirasi lebih banyak kiriman:
Kotak terbalik (baris paling bawah). Untuk mendapatkan pengumuman pemenang, Anda harus menambal pengontrol permainan, menambahkan pernyataan cetak sebelum mengembalikan kemenangan:
sumber