Python 2.7
这是一个进行中的提交,我将提供给其他答复者一个框架/启发。它的工作原理是列出每条可能的获胜线,然后应用启发式方法根据该线的价值对其进行评分。当前,启发式方法是空白的(超级秘密工作)。我还添加了赢和冲突错误处理。
关于问题的说明
有几条中奖线?考虑一维情况;有2个顶点,1条边和1条线。在2维中,我们有2条直线连接的4个顶点和2 * n条直线连接的4个边。在3维中,我们有4条直线连接的8个顶点,6 * n条直线连接的12个边和6条直线连接的6个面3*n^2
。
通常,让我们将顶点称为0面,将边缘称为1面,等等。然后让我们N(i)
表示i面d
的数量,尺寸数和n
边长。则获胜线数为0.5*sum(N(i)*n^i,i=0..d-1)
。
根据维基百科,N(i)=2^(d-i)*d!/(i!*(n-1)!)
因此最终公式为:
sum(2^(d-i-1) n^i d! / (i! * (n-i)!),i=0..d-1)
Wolfram | alpha不太喜欢。这很快就变得非常大,因此我不希望我的程序在d> 8时具有可管理的运行时。
一些结果(对格式感到抱歉:
d\n 0 1 2 3 4 5 6 7 8 9
0 1 1 1 1 1 1 1 1 1 1
1 2 4 6 8 10 12 14 16 18 20
2 4 11 26 47 74 107 146 191 242 299
3 8 40 120 272 520 888 1400 2080 2952 4040
4 16 117 492 1437 3372 6837 12492 21117 33612 50997
5 32 364 2016 7448 21280 51012 107744 206896 368928 620060
6 64 1093 8128 37969 131776 372709 908608 1979713 3951424 7352101
7 128 3280 32640 192032 807040 2687088 7548800 18640960 41611392 85656080
8 256 9834 130809 966714 4907769 19200234 62070009 173533434 432891129 985263594
输入输出
目前,输入内容需要输入:tictactoe.py <ret> n,d <ret> move;move <ret>
-注意多行,没有最终;
。
输出看起来像 (x_1,x_2,x_3...)
,例如:
tictactoe.py <ret> 6,5 <ret> <ret>
=> 0, 0, 0, 0, 0
tictactoe.py <ret> 6,5 <ret> 0,0,0,0,0;0,0,0,0,5 <ret>
=> 0, 0, 0, 5, 0
# Notes on terminology:
#
# - A hypercube is the region [0,n]^d
# - An i-facet is an i-dimensional facet of a hypercube,
# which is to say, a 0-facet is a vertex, a 1-facet an
# edge, a 2-facet a face, and so on.
# - Any tuple {0,n}^i is a vertex of an i-hypercube
# which is why I've used vertex to describe such
# tuples
# - A winning line is a set of n coordinates which joins
# two opposite i-facets
# - i-facets are opposite if they differ in every co-
# ordinate which defines them
#
# Test Data:
#
import numpy
import itertools
def removeDuplicates(seq):
noDupes = []
[noDupes.append(i) for i in seq if not noDupes.count(i)]
return noDupes
def listPairedVertices (i,n):
"""
listPairedVertices returns a list L of elements of {0,n}^i which has the
property that for every l in L, there does not exist l' such that
l+l' = {n}^i.
"""
vertices = numpy.array([[b*(n-1) for b in a] for a in [
list(map(int,list(numpy.binary_repr(x,i)))) for x in range(2**i)
]])
result = []
while len(vertices)>1:
for j in range(len(vertices)):
if numpy.all(vertices[j] + vertices[0] == [n-1]*i):
result.append(vertices[0])
vertices=numpy.delete(vertices,[0,j],axis=0)
break
return result
def listSequences (d,l):
"""
listSequences returns the subset of {0,1}^d having precisely n 1s.
"""
return numpy.array([
r for r in itertools.product([0,1],repeat=d) if sum(r)==l
])
def listPaddedConstants (s,n):
"""
listPaddedConstants takes a sequence in {0,1}^d and returns a number in
{0..n}^sum(s) padded by s
"""
result = numpy.zeros([n**sum(s),len(s)],dtype=numpy.int)
for i,x in enumerate([list(z) for z in
itertools.product(range(n),repeat=sum(s))]):
for j in range(len(s)):
if s[j]: result[i][j] = x.pop()
return result
def listWinningVectorsForDimension(d,i,n):
"""
List the winning lines joining opposite i-facets of the hypercube.
An i-facet is defined by taking a vertex v and a sequence s, then forming
a co-ordinate C by padding v with zeroes in the positions indicated by s.
If we consider s = s_0.e_0 + s_1+e_1... where the e_j are the canonical
basis for R^d, then the formula of the i-facet is
C+x_0.s_0.e_0+x_1.s_1.e_1...
for all vectors x = (x_0,x_1...) in R^n
We know that winning lines only start at integral positions, and that the
value of a will only be needed when s_j is nonempty, so the start point S
of a winning line is in fact determined by:
+ vertex v in {0,n}^(d-i), padded by s
+ a in R^i, padded by the complement of s, s'
Having performed the following operations, the co-ordinates of the winning
lines are abs(S-k*s') for k in [0..n-1]
"""
vertices = listPairedVertices(d-i,n)
sequences = listSequences(d,i)
result = []
for s in sequences:
for v in vertices:
C = [0]*d
j = 0
for index in range(d):
if s[index]: C[index] = 0
else:
C[index] = v[j]
j+=1
result += [
[numpy.absolute(S-k*(numpy.absolute(s-1))) for k in range(n)]
for S in [C+a for a in listPaddedConstants(s,n)]
]
return result
def AllWinningLines (d,n):
"""
has the structure [[x_1,x_2,x_3],[y_1,y_2,y_3]] where each l_k is a
length-d co-ordinate
"""
result = []
for i in range(d):
result += listWinningVectorsForDimension(d,i,n)
return result
def movesAlreadyMade ():
"""
Returns a list of co-ordinates of moves already made read from STDIN
"""
parameters = raw_input()
moves = raw_input()
parameters = list(map(int,parameters.split(',')))
moves = [map(int,a.split(',')) for a in moves.split(';')] \
if moves != '' else []
return {'n':parameters[0], 'd':parameters[1], 'moves':moves}
def scoreLine (moves, line, scores, n):
"""
Gives each line a score based on whatever logic I choose
"""
myMoves = moves[0::2]
theirMoves = moves[1::2]
if len(moves)%2: myMoves, theirMoves = theirMoves, myMoves
lineHasMyMove = 0
lineHasTheirMove = 0
score = 0
for coord in line:
if coord.tolist() in myMoves:
lineHasMyMove += 1
if coord.tolist() in theirMoves: raise Exception('Move clash')
elif coord.tolist() in theirMoves: lineHasTheirMove += 1
if lineHasMyMove == len(line):
raise Exception('I have won')
elif lineHasTheirMove == len(line):
raise Exception('They have won')
elif lineHasMyMove and lineHasTheirMove:
pass
elif lineHasTheirMove == len(line)-1:
score = n**lineHasTheirMove
else:
score = n**lineHasMyMove
for coord in line:
if coord.tolist() not in moves:
scores[tuple(coord)]+=score
def main():
"""
Throw it all together
"""
data = movesAlreadyMade()
dimension = data['d']
length = data['n']
lines = AllWinningLines(dimension, length)
scores = numpy.zeros([length]*dimension, dtype=numpy.int)
try: [scoreLine(data['moves'], line, scores, length) for line in lines]
except Exception as E:
print 'ERROR: ' + E.args[0]
return
print ','.join(map(
str,numpy.unravel_index(numpy.argmax(scores),scores.shape)
))
if __name__ == "__main__": main()
编辑:对于I / O,添加了逻辑。我相信现在已经准备好纪念
请注意,此评论最初是一个占位符,我已将其删除并取消删除。