Crea un controllo di vincita n to the d tic tac toe


13

Creare il programma più breve per controllare chi ha vinto in un n d tic tac toe gioco.

Il programma dovrebbe funzionare quando n(larghezza) e d(numero dimensione) rientrano in questi intervalli:

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 ovvero 3 per 3):

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

n = 3; d = 3(3 3 vale a dire 3 per 3 per 3):

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

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

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

n = 6; d = 2(6 2 ovvero 6 per 6):

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

E così via.

Vincere (se hai giocato abbastanza tic tac toe multidimensionale, questo è lo stesso.)

Affinché ci sia una vittoria, un giocatore deve avere tutti i quadrati adiacenti lungo una linea. Cioè, quel giocatore deve avere delle nmosse su una linea per essere un vincitore.

Adiacente:

  • ogni tessera è un punto; per esempio (0,0,0,0,0) è un punto ind=5
  • le tessere adiacenti sono tessere tali da essere entrambi punti sulla stessa unità d-cubo. In altre parole, la distanza di Chebyshev tra le tessere è 1.
  • in altre parole, se un punto pè adiacente a un punto q, allora ogni coordinata in pcoordinata corrispondente qdifferisce da essa per non più di una. Inoltre, almeno sulla coppia di coordinate differisce esattamente di uno.

Linee:

  • Le linee sono definite da vettori e una tessera. Una linea è ogni piastrella colpita dall'equazione:p0 + t<some vector with the same number of coordinates as p0>

Input :

L'ingresso sarà su STDIN. La prima riga di input sarà composta da due numeri ne dnel modulo n,d.

Dopo questo sarà una linea composta da coordinate che specificano le mosse che sono state fatte. Le coordinate saranno elencati nella forma: 1,1;2,2;3,3. L'angolo in alto a sinistra è l'origine (0,0 per 2D). Nel caso generale, questo elenco sarà simile a quello in 1,2,...,1,4;4,0,...,6,0;...cui il primo numero rappresenta la destra-sinistra, la seconda su-giù, la terza attraverso la terza dimensione, ecc. Nota che la prima coordinata è Xla prima svolta, la seconda è Oil primo turno, ....

L'input sarà seguito da una nuova riga.

Uscita :

L'output sarà su STDOUT. Indica semplicemente chi ha vinto se qualcuno ha vinto o se è un pareggio. Se non è né un pareggio né una vittoria, non produrre nulla.

Inoltre, indica se c'è uno scontro di mosse, ovvero se ci sono almeno due mosse nella stessa posizione.

Se c'è stata una vittoria / pareggio prima della fine dell'input, il tuo programma può fare quello che vuole.

Casi di test (qualcuno vuole suggerire di più?):

Ingresso:

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

Esempio di output:

X wins

Un altro possibile output (richiede una spiegazione):

1

Come si definisce la topologia delle dimensioni n> 3 per determinare cos'è una retta lungo una diagonale? Ad esempio, una linea attraverso 3 vertici adiacenti costituisce una vittoria su una tavola 3⁵? I quadrati medi di ciascun piano 3² sono collegati ad ogni punto di un altro piano che condivide un bordo con esso sul cubo n?
Comintern,

1
@Comintern Come va (probabilmente ho macellato la spiegazione. Potrebbe sicuramente essere più semplice).
Giustino, il

Nota: le definizioni fornite per le tessere adiacenti non sono equivalenti (ovvero non è la distanza di Manhattan uguale a una).
Howard,

Inoltre, dovresti definire che ci vogliono delle nmosse su una linea per essere vincenti. (Mi dispiace per non aver pubblicato queste osservazioni nella sandbox, ma non ho nemmeno avuto il tempo di vederlo lì perché è stato pubblicato così presto dopo il sandbox.)
Howard,

1
Sento che dovrebbe esserci una soluzione molto breve in Prolog ...
Nate Eldredge

Risposte:


3

Python, 745 578 personaggi

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

Ho apportato alcune modifiche e l'ho ridotto un po '. Nota che un ritorno di True significa che x ha vinto, False significa che y ha vinto e che significa che è stata effettuata una mossa non valida.


Alcune cose: cambia import *in import*. Utilizzare 1per True e 0per False (rimuovi Te F). return -1può essere return-1(controlla la rimozione degli spazi). Rinomina i tuoi metodi in metodi a carattere singolo. Dai un'occhiata ai suggerimenti per ulteriori ottimizzazioni.
Giustino,

Oh, grazie, non sapevo che potresti fare alcune di queste cose (vale a dire, rimuovere lo spazio tra return e -1)
foota

Ho fatto un po 'di golf sul tuo codice (che potrebbe non essere tutto valido). Il risultato è qui: ideone.com/Ld2jAH . Ricontrolla la risposta e abbrevia il codice il più possibile. La domanda di suggerimenti per Python è molto utile
Justin

@foota Puoi fare if l<>q:invece di if not l==q:.
mbomb007,

3

Non una risposta - Java

Ero curioso di vedere quanti modi diversi ci fossero per vincere per un dato n, d quindi ho scritto questo codice per elencarli tutti.

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

L'ho testato a mano su n, d = 2..3,2..3 e sembra funzionare ... dopo che il numero di possibili modi per vincere cresce rapidamente come mostrato di seguito:

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

Avendo generato tutti i set vincenti, ho potuto estendere il programma per verificare l'input dato rispetto ai set vincenti ma, ovviamente, quel metodo non avrebbe mai vinto il golf. Quindi ero contento di fermarmi qui - tranne per il fatto che potevo trovare una soluzione a forma chiusa per il numero di modi per vincere in funzione di n e d ... È il numero di modi per vincere = 0,5 ((n + 2) ^ d - n ^ d).


2

C ++ 794 849 caratteri

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

L'output è: "X" (X vince), "O" (O vince) o "!" (tentativo di mossa illegale).

Questo mappa semplicemente i punti in un array lineare e controlla tutti i possibili sottoinsiemi di dimensione n, prima per essere costanti in X o O, e poi per essere in una linea. Per verificare la presenza di una linea, le coordinate dei punti in ciascun sottoinsieme vengono esaminate una alla volta; ognuno deve aumentare da 0 a n-1, diminuire da n-1 a 0 o costante. I punti sono naturalmente ordinati nella matrice lineare, quindi ha senso chiamare una coordinata crescente o decrescente per un determinato insieme di punti.

Grazie a Howard per aver segnalato un grave errore nella prima versione.

In solidarietà con Quincunx, devo sottolineare che sarebbe una parodia se una risposta in C ++ vince


1
Penso che mentre si può dire che essere in linea implica una progressione aritmetica, non regge il contrario (ad es. 0,2,4 non sarà una soluzione per la punta standard da 3,2 tic tac).
Howard,

@Ciao, grazie. Ho apportato le correzioni. Adesso è troppo tardi perché io finisca di giocare a golf, ma sono stato in grado di risolverlo (credo).
Eric Tressler,

È possibile giocare a golf ulteriormente utilizzando diversi output. Non devi dire esattamente X winso O wins. È perfettamente legittimo produrre 1o 2(o qualche altra variante) fintanto che nella tua risposta spieghi che cosa rappresentano. Come ho detto (enfasi aggiunta): " indica chi ha vinto".
Giustino, il

Fatto. E se posso imparare come funziona l'operatore ternario, posso salvare alcuni caratteri.
Eric Tressler

E i legami?
Giustino,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.