Python 2 3, 141-15 = 126
def win(x,y):w([y]*x)
w=lambda b,f=print:not[f(r+1,c+1)for r,p in enumerate(b)for c in range(p)if(r+c)*w(b[:r]+[min(i,c)for i in b[r:]],max)]
Pencarian minimax dengan paksa. Untuk setiap gerakan yang mungkin, kami secara rekursif melihat apakah lawan bisa menang setelah kami melakukan gerakan itu. Golfnya cukup lemah; orang lain harus bisa berbuat lebih baik. Ini terasa seperti pekerjaan untuk APL.
winadalah antarmuka publik. Dibutuhkan dimensi papan, mengubahnya menjadi representasi papan, dan meneruskannya kew .
wadalah algoritma minimax. Dibutuhkan status papan, mencoba semua gerakan, membuat daftar yang unsur-unsurnya terkait dengan gerakan menang, dan mengembalikan True jika daftar kosong. Dengan default f=print, membangun daftar memiliki efek samping untuk mencetak gerakan yang menang. Nama fungsi yang digunakan lebih masuk akal ketika mengembalikan daftar langkah yang menang, tapi kemudian saya memindahkannot di depan daftar untuk menghemat tempat.
for r,p in enumerate(b)for c in xrange(p) if(r+c): Ulangi semua kemungkinan gerakan. 1 1diperlakukan sebagai bukan langkah hukum, menyederhanakan kasus dasar sedikit.
b[:r]+[min(i,c)for i in b[r:]]: Bangun status dewan setelah langkah diwakili oleh koordinat r dan c.
w(b[:r]+[min(i,c)for i in b[r:]],max): Kambuh untuk melihat apakah negara baru adalah negara yang kalah. maxadalah fungsi terpendek yang bisa saya temukan yang akan mengambil dua argumen integer dan tidak mengeluh.
f(r+1,c+1): Jika f dicetak, cetak langkahnya. Apa pun fitu, ia menghasilkan nilai untuk mengisi daftar panjang.
not [...]: notpengembalian Trueuntuk daftar kosong dan Falseuntuk kosong.
Kode Python 2 asli, sepenuhnya ungolfed, termasuk memoisasi untuk menangani input yang jauh lebih besar:
def win(x, y):
for row, column in _win(Board([y]*x)):
print row+1, column+1
class MemoDict(dict):
def __init__(self, func):
self.memofunc = func
def __missing__(self, key):
self[key] = retval = self.memofunc(key)
return retval
def memoize(func):
return MemoDict(func).__getitem__
def _normalize(state):
state = tuple(state)
if 0 in state:
state = state[:state.index(0)]
return state
class Board(object):
def __init__(self, state):
self.state = _normalize(state)
def __eq__(self, other):
if not isinstance(other, Board):
return NotImplemented
return self.state == other.state
def __hash__(self):
return hash(self.state)
def after(self, move):
row, column = move
newstate = list(self.state)
for i in xrange(row, len(newstate)):
newstate[i] = min(newstate[i], column)
return Board(newstate)
def moves(self):
for row, pieces in enumerate(self.state):
for column in xrange(pieces):
if (row, column) != (0, 0):
yield row, column
def lost(self):
return self.state == (1,)
@memoize
def _win(board):
return [move for move in board.moves() if not _win(board.after(move))]
Demo:
>>> for i in xrange(7, 11):
... for j in xrange(7, 11):
... print 'Dimensions: {} by {}'.format(i, j)
... win(i, j)
...
Dimensions: 7 by 7
2 2
Dimensions: 7 by 8
3 3
Dimensions: 7 by 9
3 4
Dimensions: 7 by 10
2 3
Dimensions: 8 by 7
3 3
Dimensions: 8 by 8
2 2
Dimensions: 8 by 9
6 7
Dimensions: 8 by 10
4 9
5 6
Dimensions: 9 by 7
4 3
Dimensions: 9 by 8
7 6
Dimensions: 9 by 9
2 2
Dimensions: 9 by 10
7 8
9 5
Dimensions: 10 by 7
3 2
Dimensions: 10 by 8
6 5
9 4
Dimensions: 10 by 9
5 9
8 7
Dimensions: 10 by 10
2 2