Connect 4: Spot the Fake!


34

La banque a été cambriolée et tous les voyous de la mafia locaux ont un alibi inhabituel: ils étaient chez eux en train de jouer à Connect 4! Afin de faciliter l’enquête, il vous est demandé de rédiger un programme validant toutes les cartes Connect 4 saisies afin de vérifier que les positions sont bien des positions d’un jeu Connect 4 valide et qu’elles n’ont pas été assemblées à la hâte. dès que la police a frappé à la porte.

Les règles pour connecter 4: les joueurs Ret les joueurs Ydéposent à tour de rôle les carreaux de leur couleur dans les colonnes d’une grille 7x6. Lorsqu'un joueur lâche une tuile dans la colonne, il tombe pour occuper la position non remplie la plus basse de cette colonne. Si un joueur réussit à obtenir une série horizontale, verticale ou diagonale de quatre tuiles de sa couleur sur le tableau, il gagne et la partie se termine immédiatement.

Par exemple (avec Rdémarrage), voici une position impossible pour Connect 4.

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R| | | | |
| | |Y| | | | |
|R| |Y| | | | |

Votre programme ou fonction doit intégrer une carte Connect 4 et renvoyer soit

  • Une valeur de fausseté, indiquant que la position est impossible ou
  • Une chaîne de nombres de 1 à 7, ce qui indique une séquence de coups menant à cette position (les colonnes sont numérotées 1à 7partir de gauche à droite, et ainsi de la séquence 112, par exemple, indique un mouvement rouge dans la colonne 1, suivi d'un mouvement jaune dans la colonne 1, suivi d'un mouvement rouge dans la colonne 2). Vous pouvez choisir une numérotation de colonne autre que 1234567 si vous le souhaitez, dans la mesure où vous le spécifiez dans votre solution. Si vous souhaitez renvoyer la liste dans un autre format; Par exemple, en tant que tableau, [2, 4, 3, 1, 1, 3]c'est très bien aussi, tant qu'il est facile de voir quels sont les déplacements.

Vous pouvez choisir de lire la carte dans dans tout format raisonnable , y compris en utilisant des lettres autres que Ret Ypour les joueurs, mais vous devez spécifier quel joueur commence. Vous pouvez supposer que le plateau sera toujours 6x7, avec deux joueurs.

Vous pouvez supposer que les postes que vous recevez sont au moins physiquement possibles à créer sur une carte Connect 4 standard; c'est-à-dire qu'il n'y aura pas de pièces "flottantes". Vous pouvez supposer que le tableau sera non vide.

C'est le code de golf, donc la réponse la plus courte gagne. Les failles standard s'appliquent.

Exemples

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | --> 1234567 (one possible answer)
| | | | | | | |
|R|Y|R|Y|R|Y|R|

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R| | | | | --> false
| | |Y| | | | |
|R| |Y| | | | |

| | | | | | | |
| | |Y| | | | |
| | |R| | | | |
| | |Y| | | | | --> 323333 (only possible answer)
| | |R| | | | |
| |Y|R| | | | |

| | | | | | | |
| | | | | | | |
| | | | | | | |     
| | | | | | | | --> false (this is the position arising after
| |Y|Y|Y|Y| | |     the moves 11223344, but using those moves
| |R|R|R|R| | |     the game would have ended once R made a 4)

| | | | | | | |
| | | | | | | |
|Y| | | | | | |     
|R|Y| | | | | | --> 2134231211 (among other possibilities)
|R|R|Y| | | | |
|Y|R|R|Y| | | |

| | | | | | | |
| | | | | | | |
|Y| | | | | | |     
|R|Y| | | | | | --> false (for example, 21342312117 does not
|R|R|Y| | | | |     work, because Y has already made a diagonal 4)
|Y|R|R|Y| | |R|

| | | | | | | |
| | | | | | | |
| | | | | | | |     
| | | | | | | | --> 112244553 or similar
|Y|Y| |Y|Y| | |
|R|R|R|R|R| | |

John, par curiosité, savez-vous s'il existe un algorithme sans force brute?
Jonah

Réponses:


9

Gelée , 57 octets

ŒṪŒ!µ0ịŒṬ¬a³ZU,Ɗ;ŒD$€Ẏṡ€4Ḅo1%15;Ḋ€ṢṚ$Ƒƙ$Ȧȧœị³$2R¤ṁ$ƑµƇṪṪ€

Prend une matrice où 0est non rempli, 1joué en premier et 2joué en second. Donne une liste de colonnes indexées 1, vides si un faux est identifié.

Essayez-le en ligne! (trop inefficace pour plus de 7 pièces à exécuter en moins d'une minute)

Remarque:

  1. Suppose qu'il n'y a pas de morceaux "flottants" (corrigez ceci en ajoutant ZṠṢ€Ƒȧdes préfixes pour +6 octets)
  2. Suppose que le plateau vide est un faux

11

JavaScript (ES6),  202 194 187  183 octets

Prend les entrées sous forme de matrice avec pour le rouge, pour le jaune et pour le vide. Retourne une chaîne de mouvements indexés 0 (ou une chaîne vide s'il n'y a pas de solution). Les rouges commencent la partie.240

m=>(p=[...'5555555'],g=(c,s=o='')=>/2|4/.test(m)?['',0,2,4].some(n=>m.join``.match(`(1|3)(.{1${n}}\\1){3}`))?o:p.map((y,x)=>m[m[y][x]--^c||p[g(c^6,s+x,p[x]--),x]++,y][x]++)&&o:o=s)(2)

Essayez-le en ligne!

Comment?

La fonction récursive tente de remplacer tous les et de la matrice d’entrée par et respectivement.g2413

Ce faisant, nous nous assurons que nous n’avons aucune séquence de quatre valeurs impaires consécutives tant que toutes les valeurs paires n’auront pas disparu (c’est-à-dire que si un camp gagne, ce doit être le dernier coup).

La ligne du prochain emplacement disponible pour chaque colonne est stockée dans .yxp[x]

Commenté

m => (                            // m[] = input matrix
  p = [...'5555555'],             // p[] = next row for each column
  g = (c,                         // g = recursive function taking c = color,
          s = o = '') =>          //     s = current solution, o = final output
    /2|4/.test(m) ?               // if the matrix still contains at least a 2 or a 4:
      ['', 0, 2, 4]               //   see if we have four consecutive 1's or 3's
      .some(n =>                  //   by testing the four possible directions
        m.join``                  //   on the joined matrix, using
        .match(                   //   a regular expression where the number of characters
          `(1|3)(.{1${n}}\\1){3}` //   between each occurrence is either 1, 10, 12 or 14
        )                         //   (horizontal, diagonal, vertical, anti-diagonal)
      ) ?                         //   if we have a match:
        o                         //     abort and just return the current value of o
      :                           //   else:
        p.map((y, x) =>           //     for each cell at (x, y = p[x]):
          m[                      // 
            m[y][x]--             //       decrement the value of the cell
            ^ c ||                //       compare the original value with c
            p[                    //       if they're equal:
              g(                  //         do a recursive call with:
                c ^ 6,            //           the other color
                s + x,            //           the updated solution
                p[x]--            //           the updated row for this column
              ),                  //         end of recursive call
              x                   //         then:
            ]++,                  //         restore p[x]
            y                     //         and restore m[y][x]
          ][x]++                  //         to their initial values
        ) && o                    //     end of map(); yield o
    :                             // else:
      o = s                       //   we've found a solution: copy s to o
)(2)                              // initial call to g() with c = 2

Remarque J'ai demandé "Peut-on supposer que le tableau vide ne sera pas donné en entrée?" - Si nous devons gérer cela, votre code devra être ajusté.
Jonathan Allan

Je ne sais pas pourquoi, se f([ [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,2,0,2,0,0], [0,2,2,0,2,2,0], [1,1,1,1,1,1,1] ])termine par 0 et f([ [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,2,0,2,0,0], [2,2,2,0,2,2,1], [1,1,1,1,1,1,1] ])devrait être vrai
Nahuel Fouilleul

@NahuelFouilleul Merci d'avoir signalé cette erreur. J'ai corrigé le code ajouté, ajouté ces cas de test.
Arnauld

2

Python 2 , 295 285 octets

def f(a):
 if 1-any(a):return[]
 p=sum(map(len,a))%2
 for i in R(7):
	if a[i][-1:]==`p`:
	 b=a[:];b[i]=b[i][:-1];L=f(b)
	 if L>1>(`1-p`*4in','.join([J((u[j]+' '*14)[n-j]for j in R(7))for n in R(12)for u in[b,b[::-1]]]+b+map(J,zip(*[r+' '*7for r in b])))):return L+[i]
R=range;J=''.join

Essayez-le en ligne!

-10 thx à Jo King .

L'entrée est une liste de chaînes représentant les colonnes; avec '1' pour le rouge et '0' pour le jaune. Les cordes ne sont pas capitonnées. Donc, le cas (falsey):

| | | | | | | |
| | | | | | | |
|Y| | | | | | |
|R|Y| | | | | |
|R|R|Y| | | | |
|Y|R|R|Y| | |R|

est entré comme:

[
  '0110',
  '110',
  '10',
  '0',
  '',
  '',
  '1'
]

La sortie est une liste d'index de colonnes, indexés sur 0, qui pourraient faire le tableau; ou Nonesi ce n'est pas valide.

Accepte le tableau vide comme valide (renvoie la liste vide à la []place de None).

Cette approche est récursive du dernier mouvement au premier mouvement: sur la base de la parité du nombre total de mouvements effectués, nous supprimons le dernier mouvement rouge ou le dernier mouvement jaune (ou échouons si cela n’est pas possible); vérifier le tableau résultant pour voir si l'adversaire a 4 rangées de suite (auquel cas échouer, car le jeu aurait déjà dû s'arrêter); sinon, recurse jusqu'à ce que le tableau soit vide (ce qui est valide).

Le code 4-in-a-row est la partie la plus floue. Toutes les chaînes diagonales de la matrice bsont générées par:

[
    ''.join(
        (u[j]+' '*14)[n-j] for j in range(7)
    )
    for u in[b,b[::-1]]for n in range(12) 
]

qui énumère d’abord les diagonales «en pente descendante», puis les diagonales «en pente descendante».

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.