nをd tic tac toe win-checkerに作成します


13

n d tic tac toeゲームで誰が勝ったかを確認する最短のプログラムを作成します。

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

n∈[3,6]∩ℕ  ie a number from this list: 3,4,5,6
d∈[2,5]∩ℕ  ie a number from this list: 2,3,4,5

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):

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

等々。

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

勝つためには、一人のプレイヤーがラインに沿ってすべての隣接する正方形を持っている必要があります。つまり、そのプレイヤーは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>

入力

入力は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番目の次元などを表す場合のようになります。最初の座標はX最初のターン、2番目はあるOsの最初のターン、...

入力の後に改行が続きます。

出力

出力はSTDOUTになります。誰かが勝った場合、または同点の場合、誰が勝ったかを単に示してください。同点でも勝利でもない場合は、何も出力しません。

さらに、移動の衝突があるかどうか、つまり、同じ場所に少なくとも2つの移動があるかどうかを示します。

入力が終了する前に勝ち/引き分けがあった場合、プログラムは何でもできます。

テストケース(他に提案したい人はいますか?):

入力:

4,3
0,0,0;1,1,1;1,0,1;2,0,2;0,0,1;2,0,0;2,0,1;3,0,2;3,0,1

出力例:

X wins

別の可能な出力(説明が必要):

1

対角線に沿った直線が何であるかを決定するために、n> 3の次元のトポロジをどのように定義しますか?たとえば、3つの隣接する頂点を通るラインは、3⁵ボードでの勝利を構成しますか?各3²平面の中央の正方形は、nキューブ上でエッジを共有する別の平面のすべてのポイントに接続されていますか?
コミンテルン14

1
@Cominternそれはどうですか(おそらく説明を殺した。間違いなくもっと簡単かもしれない)。
ジャスティン14

注:隣接するタイルに指定した定義は同等ではありません(つまり、マンハッタン距離が1に等しいわけではありません)。
ハワード14

さらにn、勝者になるにはライン上の動きが必要だと定義する必要があります。(これらの発言をサンドボックスに投稿しないで申し訳ありませんが、サンドボックス後すぐに投稿されたので、私はそれを見る時間すらありませんでした。)
ハワード14

1
プロローグでは非常に短いソリューション...があるはずような気がします
ネイト・エルドリッジ

回答:


3

Python、745 578文字

import sys
x=[]
o=[]
t=1
b=","
k=map
def m(c):
 m=x if t else o
 c=k(int,c.split(b))
 if c in o+x:
  print b
  sys.exit()
 m.append(c)
 r=0
 for p in m:
  r=w(p,m)
 return r
def w(p,m):
 for q in m:
  d=max(k(lambda x,y:abs(x-y),p,q))
  if d==u:
   if e(p,q,m):
    return 1
 return 0
def e(p,q,m):
 v=k(lambda p,q:(p-q)/u,q,p)
 l=p
 for i in range(1,n):
  y=k(lambda j,h:j+h,l,v)
  if y not in m:
   return 0
  l=y
 if not l==q:
  return 0
 return 1
q=sys.stdin.readline
d=q()
v=q()
z=d.split(b)
(n,d)=k(int,z)
a=v.split(";")
u=n-1
for c in a:
 r=m(c)
 if r:
  print t
 t=not t

いくつかの変更を加え、かなり縮小しました。Trueが返されるとxが勝ち、Falseがyが勝ち、が無効な移動が行われたことを意味することに注意してください。


いくつかのこと:に変更import *import*ます。1Trueおよび0Falseに使用します(削除TおよびF)。return -1ことができますreturn-1(スペースを削除チェックしてください)。メソッドの名前を単一のcharメソッドに変更します。さらに最適化するためのヒントをご覧ください。
ジャスティン14年

ああ、ありがとう、私はあなたがそれらのことのいくつかを行うことができるとは知りませんでした(つまり、リターンと-1の間のスペースを削除します)
foota 14年

私はあなたのコードで少しゴルフをしました(すべてが有効ではないかもしれません)。結果はこちら:ideone.com/Ld2jAH。回答をもう一度確認して、できるだけコードを短くしてください。python のヒントの質問は非常に便利です
ジャスティン14年

@footaのif l<>q:代わりに行うことができますif not l==q:
mbomb007

3

答えではない-Java

与えられたn、dで勝つ方法がいくつあるか知りたいので、それらをすべてリストするためにこのコードを書きました。

import java.util.*;

public class MultiDTTT {
    static Set<Win> wins = new HashSet<Win>();
    static final int d = 3;
    static final int n = 3;
    static final char maxChar = (char)(n-1) + '0'; 

    public static void main(String[] args) throws Exception {
        String pad = "";
        for(int i=0; i<d; i++) pad = pad + "0";
        for(int i=0; i<Math.pow(n,d); i++) {
            String s = Integer.toString(i,n);
            s = pad.substring(s.length()) + s;
            buildWin(s,"",0);
        } 
        System.out.println(wins.size());
        for(Win w : wins) System.out.println(w.toString());
    }

    static void buildWin(String s, String p,int i) {
        if(i<d) {
            if(s.charAt(i) == '0') {
                buildWin(s,p+"u",i+1);
                buildWin(s,p+"s",i+1);
            }
            else if(s.charAt(i) == maxChar) {
                buildWin(s,p+"d",i+1);
                buildWin(s,p+"s",i+1);
            }
            else {
                buildWin(s,p+"s",i+1);
            }
        }
        else {
            if(p.contains("u") || p.contains("d")) wins.add(new Win(s,p));
        }
    }

    static class Win {
        String start;
        String pattern;
        Set<String> list = new HashSet<String>();

        Win(String s, String p) {
            start = s;
            pattern = p;
            char[] sc = s.toCharArray();
            for(int i=0; i<n; i++) {
                list.add(new String(sc));
                for(int j=0; j<d; j++) {
                    switch (p.charAt(j)) {
                        case 'u':
                            sc[j]++;
                            break;
                        case 'd':
                            sc[j]--;
                            break;
                        case 's':
                            break;
                    }
                }
            }
        }

        public String toString() {
            String s = ""; //start + ", " + pattern + "\n    ";
            for(String ss : list) s = s + ss + " ";
            return s;
        }

        public boolean equals(Object x) {
            return (x instanceof Win) && this.list.equals(((Win)x).list);
        }
        public int hashCode(){
            return list.hashCode();
        }
    }
}

私はn、d = 2..3,2..3でそれを手でテストしましたが、うまくいくようです...その後、以下に示すように、勝つための可能な方法の数は急速に増えました。

n       1       2       3       4       5       6
d                           
1       1       1       1       1       1       1
2       1       6       8       10      12      14
3       1       28      49      76      109     148
4       1       120     272     520     888     1400
5       1       496     1441    3376    6841    12496
6       1       2016    7448    21280   51012   107744

すべての勝ち組を生成したら、勝ち組に対して与えられた入力をチェックするようにプログラムを拡張できますが、もちろん、その方法はゴルフに勝つことはありません。だから私はここでやめることに満足しました-勝つ方法の数についてnとdの関数として閉形式の解決策を見つけることができるように見えた以外は…勝つ方法の数= 0.5((n + 2) ^ d-n ^ d)。


2

C ++ 794 849文字

#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
#define _ return
#define Y int
#define Z(a) cout<<#a
#define W(a,b,c) for(a=c;a++<b;)
using namespace std;Y n,d,A[5],P[6],T=1,x[7776]={},i,j,k,a,z,p=pow(n,d);char c;bool B;string s;Y K(){a=P[j];W(k,i,0)a/=n;_ a%n;}Y M(){j=0;z=K();W(j,n,1){if(K()!=z){_ 1;}}_ 0;}Y N(){W(j,n,0)if(K()!=n-1-j)_ 1;_ 0;}Y O(){W(j,n,0)if(K()!=j)_ 1;_ 0;}Y S(){z=0;W(i,d,0){z*=n;z+=A[i];}_ z;}Y C(){a=z=0;W(i,p,0){if(s[i]-'0'){P[z]=i;++z;if(a){if(x[i]!=a)_ 0;}else a=x[i];}}_ a;}Y L(){W(i,d,0)if(M()*N()*O())_ 0;_ 1;}Y main(){cin>>n>>c>>d;while(1){W(i,d,0)B=cin>>A[i]>>c;if(x[S()]){Z(!);_ 0;}x[S()]=T;T*=-1;if(!B)break;}W(i,p,0)i<n?s+="1":s+="0";do if(C()&&L()){C()==1?Z(X):Z(O);_ 0;}while(prev_permutation(s.begin(),s.end()));_ 0;}

出力は、「X」(X勝)、「O」(O勝)、または「!」です。(違法な移動の試み)。

これは、ポイントを線形配列にマッピングし、サイズnのすべての可能なサブセットを最初にチェックします。最初にXまたはOで一定であり、次にラインにあります。行内にあるかどうかを確認するために、各サブセットのポイントの座標が1つずつ検査されます。これらはそれぞれ、0からn-1に増加するか、n-1から0に減少するか、定数でなければなりません。点は線形配列で自然に順序付けられているため、指定された点のセットに対して座標を増加または減少させると意味があります。

最初のバージョンで重大な間違いを指摘してくれたハワードに感謝します。

Quincunxとの連帯において、C ++の答えが勝った場合、それは悲惨なものになることを指摘しなければなりません。


1
行に並んでいることは算術的進行を意味すると言うことができると思いますが、逆の方向には成り立たないと思います(たとえば、0,2,4は標準の3,2チックタクトーの解決策にはなりません)。
ハワード14

@Howard、ありがとう。修正しました。ゴルフを終えるのは遅すぎましたが、それを修正することができました(私は思う)。
エリックトレスラー14

さまざまな出力を使用して、さらにゴルフを楽しむことができます。X winsまたはを正確に言う必要はありませんO wins。回答の中でそれらが何を意味するのかを説明している限り、出力1すること2(または他のバリエーション)は完全に合法です。私が言ったように(強調を追加):「誰が勝ったかを示す」。
ジャスティン14

できた そして、三項演算子がどのように機能するかを学習できれば、いくつかの文字を保存できます。
エリックトレスラー14

ネクタイはどうですか?
ジャスティン14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.