Créer un n pour le vérificateur de gains d tic tac toe

13

Créez le programme le plus court pour vérifier qui a gagné dans un jeu n d tic tac toe.

Votre programme devrait fonctionner lorsque n(largeur) et d(numéro de dimension) se trouvent dans ces plages:

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 soit 3 par 3):

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

n = 3; d = 3(3 3 soit 3 par 3 par 3):

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

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

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

n = 6; d = 2(6 2 soit 6 par 6):

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

Etc.

Gagner (Si vous avez joué suffisamment de tic tac toe multidimensionnel, c'est la même chose.)

Pour qu'il y ait une victoire, un joueur doit avoir toutes les cases adjacentes le long d'une ligne. Autrement dit, ce joueur doit avoir des nmouvements sur une ligne pour être gagnant.

Adjacent:

  • chaque tuile est un point; par exemple (0,0,0,0,0) est un pointd=5
  • les tuiles adjacentes sont des tuiles telles qu'elles sont les deux points sur la même unité d-cube. En d'autres termes, la distance de Chebyshev entre les tuiles est de 1.
  • en d'autres termes, si un point pest adjacent à un point q, alors chaque coordonnée en ps coordonnée correspondante en ne qdiffère pas de plus d'un. De plus, au moins sur la paire de coordonnées diffère exactement d'un.

Lignes:

  • Les lignes sont définies par des vecteurs et une tuile. Une ligne est chaque tuile frappée par l'équation:p0 + t<some vector with the same number of coordinates as p0>

Entrée :

L'entrée sera vers STDIN. La première ligne de saisie sera composée de deux nombres net dsous la forme n,d.

Après cela sera une ligne composée de coordonnées spécifiant les mouvements qui ont été effectués. Les coordonnées seront listés sous la forme: 1,1;2,2;3,3. Le coin supérieur gauche est l'origine (0,0 pour 2D). Dans le cas général, cette liste sera comme 1,2,...,1,4;4,0,...,6,0;...où le premier nombre représente la gauche-droite-ness, la deuxième haut-bas-ness, la troisième à la 3ème dimension, etc. Notez que la première coordonnée est Xs premier tour, la seconde c'est Ole premier tour, ....

L'entrée sera suivie d'une nouvelle ligne.

Sortie :

La sortie sera vers STDOUT. Indiquez simplement qui a gagné si quelqu'un a gagné ou s'il s'agit d'une égalité. Si ce n'est ni une égalité ni une victoire, ne produisez rien.

De plus, indiquez s'il y a un conflit de mouvements, c'est-à-dire s'il y a au moins deux mouvements au même endroit.

S'il y a eu une victoire / match nul avant la fin de la saisie, votre programme peut faire ce qu'il veut.

Cas de test (quelqu'un veut-il suggérer plus?):

Contribution:

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

Exemple de sortie:

X wins

Une autre sortie possible (nécessite une explication):

1
Justin
la source
Comment définissez-vous la topologie des dimensions n> 3 pour déterminer ce qu'est une ligne droite le long d'une diagonale? Par exemple, une ligne passant par 3 sommets adjacents constitue-t-elle une victoire sur un plateau de 3⁵? Les carrés du milieu de chaque plan de 3² sont-ils connectés à chaque point d'un autre plan qui partage une arête avec lui sur le n-cube?
Comintern
1
@Comintern Comment ça (j'ai probablement détruit l'explication. Cela pourrait certainement être plus simple).
Justin
Remarque: les définitions que vous avez données pour les tuiles adjacentes ne sont pas équivalentes (c'est-à-dire que la distance manhattan n'est pas égale à une).
Howard
De plus, vous devez définir qu'il faut des nmouvements sur une ligne pour gagner. (Désolé de ne pas avoir posté ces remarques dans le bac à sable, mais je n'ai même pas eu le temps de le voir là-bas car il a été publié si peu de temps après le bac à sable.)
Howard
1
Je pense qu'il devrait y avoir une solution très courte dans Prolog ...
Nate Eldredge

Réponses:

3

Python, 745 578 caractères

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

J'ai fait quelques changements et je l'ai réduit un peu. Notez qu'un retour de True signifie que x a gagné, False signifie y a gagné et signifie qu'un mouvement invalide a été effectué.

foota
la source
Certaines choses: changer import *pour import*. Utilisez 1pour True et 0pour False (supprimer Tet F). return -1peut être return-1(consultez la suppression des espaces). Renommez vos méthodes en méthodes à caractère unique. Consultez les conseils pour plus d'optimisations.
Justin
Oh, merci, je ne savais pas que vous pouviez faire certaines de ces choses (à savoir, supprimer l'espace entre le retour et -1)
foota
J'ai fait un peu de golf sur votre code (qui n'est peut-être pas tous valides). Le résultat est ici: ideone.com/Ld2jAH . Veuillez répéter votre réponse et raccourcir le code autant que possible. La question des astuces pour python est très utile
Justin
@foota Vous pouvez faire à la if l<>q:place de if not l==q:.
mbomb007
3

Pas une réponse - Java

J'étais curieux de voir combien de façons différentes de gagner pour un n, d donc j'ai écrit ce code pour les énumérer toutes.

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

Je l'ai testé à la main sur n, d = 2..3,2..3 et cela semble fonctionner ... après cela, le nombre de façons possibles de gagner augmente rapidement, comme indiqué ci-dessous:

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

Après avoir généré tous les sets gagnants, j'ai pu étendre le programme pour vérifier l'entrée donnée par rapport aux sets gagnants mais, bien sûr, cette méthode ne gagnerait jamais le golf. Je me suis donc contenté de m'arrêter ici - sauf qu'il semblait que je pouvais trouver une solution de forme fermée pour le nombre de façons de gagner en fonction de n et d ... C'est Nombre de façons de gagner = 0,5 ((n + 2) ^ d - n ^ d).

Wally
la source
2

C ++ 794 849 caractères

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

La sortie est: "X" (X gagne), "O" (O gagne) ou "!" (tentative de déplacement illégale).

Cela mappe simplement les points dans un tableau linéaire et vérifie tous les sous-ensembles possibles de taille n, d'abord pour être constant à X ou O, puis pour être dans une ligne. Pour vérifier leur alignement, les coordonnées des points de chaque sous-ensemble sont examinées une par une; ils doivent chacun soit augmenter de 0 à n-1, diminuer de n-1 à 0, soit être constants. Les points sont naturellement ordonnés dans le réseau linéaire, il est donc logique d'appeler une coordonnée croissante ou décroissante pour un ensemble de points donné.

Merci à Howard d'avoir signalé une grave erreur dans la première version.

En solidarité avec Quincunx, je dois souligner que ce serait une parodie si une réponse C ++ gagne

Eric Tressler
la source
1
Je pense que si vous pouvez dire qu'être en ligne implique une progression arithmétique, cela ne tient pas le contraire (par exemple 0,2,4 ne sera pas une solution pour le standard 3,2 tic tac toe).
Howard
@Comment, merci. J'ai fait les corrections. Il est trop tard maintenant pour que je finisse de jouer au golf, mais j'ai pu le réparer (je pense).
Eric Tressler
Vous pouvez jouer au golf plus loin en utilisant différentes sorties. Vous n'avez pas à dire exactement X winsou O wins. Il est parfaitement légitime de produire 1ou 2(ou une autre variante) tant que vous expliquez dans votre réponse ce qu'ils représentent. Comme je l'ai dit (je souligne): " indiquez qui a gagné".
Justin
Terminé. Et si je peux apprendre comment fonctionne l'opérateur ternaire, je pourrai enregistrer quelques caractères.
Eric Tressler
Et les liens?
Justin