Buat n ke dac tic toe win-checker

13

Buat program terpendek untuk memeriksa yang telah memenangkan dalam sebuah n d tic tac toe game.

Program Anda harus bekerja ketika n(lebar) dan d(nomor dimensi) berada dalam rentang ini:

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 yaitu 3 oleh 3):

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

n = 3; d = 3(3 3 yaitu 3 oleh 3 oleh 3):

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

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

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

n = 6; d = 2(6 2 yaitu 6 oleh 6):

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

Dan seterusnya.

Menang (Jika Anda telah memainkan cukup banyak tac toe tic multi-dimensi, ini sama.)

Agar menang, satu pemain harus memiliki semua kotak yang berdekatan di sepanjang garis. Artinya, pemain itu harus nbergerak pada garis untuk menjadi pemenang.

Berdekatan:

  • setiap ubin adalah sebuah titik; misalnya (0,0,0,0,0) adalah titik did=5
  • ubin yang berdekatan adalah ubin sedemikian rupa sehingga keduanya merupakan titik pada unit d-cube yang sama. Dengan kata lain, jarak Chebyshev antara ubin adalah 1.
  • dengan kata lain, jika suatu titik pberbatasan dengan suatu titik q, maka setiap koordinat dalam pkoordinat yang sesuai qberbeda darinya dengan tidak lebih dari satu. Selain itu, setidaknya pada pasangan koordinat berbeda dengan tepat satu.

Garis:

  • Garis ditentukan oleh vektor dan ubin. Garis adalah setiap ubin yang terkena persamaan:p0 + t<some vector with the same number of coordinates as p0>

Memasukkan :

Masukan akan ke STDIN. Baris input pertama adalah dua angka, ndand dalam bentuk n,d.

Setelah ini akan menjadi garis yang terdiri dari koordinat yang menentukan gerakan yang telah dilakukan. Koordinat akan terdaftar dalam bentuk: 1,1;2,2;3,3. Pojok kiri atas adalah asal (0,0 untuk 2D). Dalam kasus umum, daftar ini akan seperti di 1,2,...,1,4;4,0,...,6,0;...mana angka pertama mewakili kiri-kanan, kedua naik ke atas, ketiga melalui dimensi ke-3, dll. Perhatikan bahwa koordinat pertama adalah Xgiliran pertama, yang kedua adalah Ogiliran pertama, ....

Input akan diikuti oleh baris baru.

Keluaran :

Output akan ke STDOUT. Cukup tunjukkan siapa yang menang jika seseorang menang, atau apakah itu seri. Jika ini bukan seri atau kemenangan, jangan hasilkan apa pun.

Selain itu, tunjukkan jika ada bentrokan gerakan, yaitu, jika ada setidaknya dua gerakan di lokasi yang sama.

Jika ada win / draw sebelum input berakhir, program Anda dapat melakukan apa pun yang diinginkan.

Test case (ada yang mau menyarankan lagi?):

Memasukkan:

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

Contoh Output:

X wins

Output lain yang mungkin (memerlukan penjelasan):

1
Justin
sumber
Bagaimana Anda mendefinisikan topologi dimensi n> 3 untuk menentukan garis lurus diagonal? Misalnya, apakah garis apa pun melalui 3 simpul yang berdekatan merupakan kemenangan di papan 3⁵? Apakah kotak tengah dari setiap bidang 3² terhubung ke setiap titik dari bidang lain yang berbagi keunggulan dengannya di n-cube?
Comintern
1
@Comintern Bagaimana itu (saya mungkin membantai penjelasan. Pasti bisa lebih sederhana).
Justin
Catatan: definisi yang Anda berikan untuk ubin yang berdekatan tidak setara (artinya, jarak manhattan tidak sama dengan satu).
Howard
Selain itu, Anda harus menentukan bahwa dibutuhkan nlangkah untuk menjadi pemenang. (Maaf karena tidak memposting komentar ini di kotak pasir tetapi saya bahkan tidak punya waktu untuk melihatnya di sana karena itu diposting begitu cepat setelah sandboxing.)
Howard
1
Saya merasa harus ada solusi yang sangat singkat di Prolog ...
Nate Eldredge

Jawaban:

3

Python, 745 578 Karakter

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

Saya membuat beberapa perubahan dan sedikit menyusut. Perhatikan bahwa kembalinya True berarti x telah menang, Salah berarti y menang, dan, berarti bahwa langkah yang tidak valid telah dibuat.

Foota
sumber
Beberapa hal: ubah import *ke import*. Gunakan 1untuk Benar, dan 0untuk Salah (hapus Tdan F). return -1bisa return-1(lihat menghapus spasi). Ubah nama metode Anda menjadi metode char tunggal. Lihatlah kiat untuk optimisasi lebih lanjut.
Justin
Oh, terima kasih, saya tidak tahu Anda bisa melakukan beberapa hal (yaitu, menghapus ruang antara kembali dan -1)
foota
Saya melakukan sedikit golf pada kode Anda (yang mungkin tidak semuanya valid). Hasilnya ada di sini: ideone.com/Ld2jAH . Silakan jawab kembali jawaban Anda dan persingkat kode semampu Anda. Pertanyaan tip untuk python sangat berguna
Justin
@foota Anda dapat melakukan if l<>q:bukan if not l==q:.
mbomb007
3

Bukan jawaban - Jawa

Saya ingin tahu berapa banyak cara yang berbeda untuk menang untuk suatu n, d jadi saya menulis kode ini untuk mendaftar semuanya.

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();
        }
    }
}

Saya mengujinya secara langsung pada n, d = 2..3,2..3 dan tampaknya berfungsi ... setelah itu jumlah cara yang mungkin untuk menang tumbuh dengan cepat seperti yang ditunjukkan di bawah ini:

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

Setelah menghasilkan semua set kemenangan, saya dapat memperluas program untuk memeriksa input yang diberikan terhadap set kemenangan, tetapi, tentu saja, metode itu tidak akan pernah memenangkan golf. Jadi saya puas untuk berhenti di sini - kecuali sepertinya saya bisa menemukan solusi bentuk tertutup untuk jumlah cara untuk menang sebagai fungsi dari n dan d ... Ini adalah Jumlah cara untuk menang = 0,5 ((n + 2) ^ d - n ^ d).

Wally
sumber
2

C ++ 794 849 karakter

#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;}

Outputnya adalah: "X" (X menang), "O" (O menang), atau "!" (upaya langkah ilegal).

Ini hanya memetakan titik-titik ke dalam array linier dan memeriksa semua himpunan bagian yang mungkin dari ukuran n, pertama untuk menjadi konstan pada X atau O, dan kemudian untuk berada dalam garis. Untuk memeriksa apakah ada dalam suatu garis, koordinat titik-titik dalam setiap subset diperiksa satu per satu; masing-masing harus meningkat dari 0 ke n-1, menurun dari n-1 ke 0, atau konstan. Poin secara alami dipesan dalam array linier, jadi masuk akal untuk memanggil koordinat yang bertambah atau berkurang untuk set poin yang diberikan.

Terima kasih kepada Howard karena telah menunjukkan kesalahan serius pada versi pertama.

Dalam solidaritas dengan Quincunx, saya harus menunjukkan bahwa itu akan menjadi parodi jika jawaban C ++ menang

Eric Tressler
sumber
1
Saya berpikir bahwa sementara Anda dapat mengatakan bahwa menjadi sejalan menyiratkan perkembangan aritmatika, itu tidak berlaku sebaliknya (misalnya 0,2,4 tidak akan menjadi solusi untuk standar 3,2 tic tac toe).
Howard
@ Howard, terima kasih. Saya sudah melakukan koreksi. Sudah terlambat bagi saya untuk menyelesaikan golf, tapi saya bisa memperbaikinya (saya pikir).
Eric Tressler
Anda dapat golf lebih jauh dengan menggunakan output yang berbeda. Anda tidak harus mengatakan dengan tepat X winsatau O wins. Sangat sah untuk menghasilkan 1atau 2(atau variasi lainnya) selama Anda menjelaskan dalam jawaban Anda apa yang mereka perjuangkan. Seperti yang saya katakan (penekanan ditambahkan): " menunjukkan siapa yang menang".
Justin
Selesai Dan jika saya dapat mempelajari cara kerja operator ternary, saya dapat menyimpan beberapa karakter.
Eric Tressler
Bagaimana dengan ikatan?
Justin