三目並べゲーム


15

遊びnに決定論的なプログラムを作成してD他の競技者との三目並べ。

n(幅)とd(次元数)が次の範囲にある場合、プログラムは動作するはずです。

n∈[3,∞)∩ℕ  ie a natural number greater than 2
d∈[2,∞)∩ℕ  ie a natural number greater than 1

n = 3; d = 2(3 2すなわち3 x 3):

[][][]
[][][]
[][][]

n = 3; d = 3(3 3すなわち3 x 3 x 3):

[][][]
[][][]
[][][]

[][][]
[][][]
[][][]

[][][]
[][][]
[][][]

n = 6; d = 2(6 2すなわち6 x 6):

[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]

等々。

入力:

入力はSTDINになります。入力の最初の行は、形式の2つの数値にnなります。dn,d

この後、行われた移動を指定する座標で構成される線になります。座標は次の形式でリストされます1,1;2,2;3,3。左上隅が原点です(2Dの場合は0,0)。一般的な場合、このリストは1,2,...,1,4;4,0,...,6,0;...、最初の数字が左右、2番目の上下、3番目から3番目の次元などを表すようなものになります。最初の座標はX1番目のターン、2番目はあるOsの最初のターン、...

これが最初の動きである場合、入力は数字の後に1行の空白行が続きます。

一貫性を保つため、入力は常に改行で終わります。サンプル入力(\ nは改行):

10,10\n0,0,0,0,0,0,0,0,0,0;0,2,3,4,5,6,7,8,9,0;0,1,2,3,4,5,6,7,8,9\n

最初の動き:

10,10\n\n

どこ\n改行文字です。

出力:

入力と同じ形式(コンマ区切りのリスト)で、作成する移動を出力します。無効な移動(つまり、既に行われた移動)は、ゲームの損失につながります。

注:同じ条件で各実行が同一になるような値をシードする限り、乱数ジェネレーターを使用できます。言い換えれば、プログラムは決定論的でなければなりません。

注:有効な移動のみが許可されます。

勝利ゲーム(十分な多次元の三目並べをプレイした場合、これは同じです。)

勝つためには、一人のプレイヤーがラインに沿ってすべての隣接する正方形を持っている必要があります。つまり、そのプレイヤーはn勝者になるためにライン上で動きを持たなければなりません。

隣接:

  • 各タイルはポイントです。たとえば、(0,0,0,0,0)はd=5
  • 隣接するタイルは、同じユニットdキューブ上の両方のポイントであるようなタイルです。つまり、タイル間のチェビシェフ距離は1です。
  • 言い換えれば、ポイントpがポイントに隣接している場合、対応する座標内のqすべての座標は、1つだけ異なる。また、少なくとも1つの座標ペアは1つだけ異なります。pq

行:

  • 線はベクトルとタイルで定義されます。線は、方程式によってヒットした各タイルです。p0 + t<some vector with the same number of coordinates as p0>

シミュレーションと勝利条件:

  • 採点の準備ができている場合は、回答に記載してください。つまり、回答が完了したかどうかを明確に示します。

  • 回答に完了マークが付いている場合、最後にコードを編集してから少なくとも24時間後まで採点されません。

  • プログラムはオフラインで動作する必要があります。プログラムが不正行為であることが判明した場合、プログラムは自動的にのスコアを受け取り、それ-1以上スコアリングされません。(プログラムの不正行為はどうなるでしょうか?)

  • プログラムが無効な出力を生成した場合、ゲームの損失として直ちにカウントされます

  • プログラムが1分後に出力を生成できない場合、ゲームの損失として直ちにカウントされます。必要に応じて、速度を最適化します。別のプログラムをテストするために1時間待つ必要はありません。

  • 各プログラムは、2回のために他のプログラムに対して実行されるn範囲内で[3,6]、それぞれのd範囲内で[2,5]一回として、Xそして一度としてO。これは1ラウンドです。

  • プログラムが勝つゲームごと+3に、そのスコアに到達します。プログラムが同点の場合(1ラウンドで1勝1敗、または両方のゲームで同点)、それはを獲得し+1ます。プログラムが失われた場合、取得されます+0(つまり、変更はありません)。

  • 最高スコアのプログラムが勝ちます。同点の場合は、負けたゲームの数が最も少ないプログラム(同点の出場者のうち)が勝ちます。

注:回答の数によっては、テストの実行に支援が必要な場合があります。

幸運を!そして、あなたの好意でシミュレーションが実行されますように!


Win-checkerチャレンジ。<----この課題は、特定のゲームに勝ったかどうかを確認するプログラムを作成することです。これは、この課題と非常に関連しています。
ジャスティン14年

作成した自己完結型のタグは、タグの分類に何も追加しません。削除する必要があると思います。
ハワード14年

@ハワードわかりました。多くの質問にその制限があることに気づいたので、タグが適切だと思いました。
ジャスティン14年

4
奇妙なゲーム。勝つ唯一の動きはプレーしないことです。
german_guy 14

(w、x、y、z)は有効な出力形式ですか?
アレクサンダーブレット14

回答:


2

Python 3

import random as rand
import re

def generateMoves(width, dim):
    l = [0] * dim
    while existsNotX(l, width - 1):
        yield l[:]
        for i in range(dim):
            if l[i] < width - 1:
                l[i] += 1
                break
            else:
                l[i] = 0
    yield l

def existsNotX(l, x):
    for i in l:
        if i != x:
            return True
    return False

input_s = input()
dims, moves = None, None
#this is to allow input as a single paste, instead of ENTER inputting.
try:
    dims, moves = input_s.splitlines()
except ValueError:
    dims = input_s
    moves = input()

rand.seed(moves + dims)

dims = eval(dims) #change into tuple

moves = moves.split(';')
if len(moves[0]):
    moves = [eval(m) for m in moves] #change into tuples

output =[x for x in generateMoves(dims[0], dims[1]) if x not in moves]
print(re.sub('[^\\d,]', '', str(output[rand.randint(0, len(output))])))

これは単純にランダムなaiです。まだ利用可能な動きからランダムに動きを選択します。


2

Python 2.7

これは、他の回答者にスケルトン/インスピレーションを与えるために提供している進行中の提出物です。可能なすべての勝利ラインをリストし、そのヒューリスティックを適用して、そのラインの価値に応じてそのラインをスコアリングします。現在、ヒューリスティックは空白です(極秘の仕組み)。また、WinおよびClashのエラー処理も追加しました。

問題に関する注意

勝利ラインはいくつありますか?1次元の場合を考えます。2つの頂点、1つのエッジ、1つのラインがあります。2次元では、2つの線で結合された4つの頂点と、2 * nの線で結合された4つのエッジがあります。3次元では、4つの線で結合された8つの頂点、6 * nの線で結合された12のエッジ、および線で結合された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

I / O

現時点では、入力は次のように入力する必要があります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にロジックを追加。これでマークする準備ができたと思う

このコメントは最初はプレースホルダーであり、私が削除および削除解除したことに注意してください。


1

Python 2

import re
import itertools

input_s = raw_input()
dims, moves = None, None
#this is to allow input as a single paste, instead of ENTER inputting.
try:
    dims, moves = input_s.splitlines()
except ValueError:
    dims = input_s
    moves = raw_input()

dims = eval(dims) #change into tuple

moves = moves.split(';')
if len(moves[0]):
    moves = [eval(m) for m in moves] #change into tuples

allSpaces = [x for x in itertools.product(range(dims[0]), repeat=dims[1])]
move = None
for space in allSpaces:
    if space not in moves:
        move = space
        break
print(re.sub('[^\\d,]', '', str(move)))

コードのほとんどは、QuincunxのランダムAIとまったく同じです。移動をランダムに選択する代わりに、最初に使用可能な移動を辞書式に選択します(つまり(0,0、... 0)、次に(0,0、... 1)、次に(0,0、... 2)など)。

これはかなりゴミの多い戦略ですが、ほとんどの場合、ランダムにプレイするよりも勝っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.