Pouvez-vous gagner avec deux coups supplémentaires à Three Men's Morris?

16

Bounties

N ° 1 ( attribué )

Je jetterai 50 répétitions pour la première réponse valide

N ° 2 ( attribué )

Je vais ajouter 100 autres représentants pour la réponse valide la plus courte.

N ° 3 ( ouvert aux soumissions )

Je jetterai 200 rep pour le premier avec une réponse valide plus courte significative. Significatif représentant au plus 45% de la réponse actuellement la plus courte ( 564 octets x 0,45 = max 254 octets ).


Le jeu

Vous vous souvenez du jeu classique " Nine Men's Morris " ou simplement " Mill "? Il y a une variation appelée Three Men's Morris qui est un peu comme un tic-tac-toe mutable.

Règles

Voici le tableau blanc du jeu:

   a   b   c
1 [ ]–[ ]–[ ]
   | \ | / |
2 [ ]–[ ]–[ ]
   | / | \ |
3 [ ]–[ ]–[ ]

[ ]est un champ et |–/\représente les routes entre ces champs.

Le jeu est joué par deux joueurs 1et 2qui placent chacun 3 jetons sur le plateau. Cela s'est déjà produit et nous sommes dans le coup. La partie est gagnée si un joueur peut former une millqui est une rangée verticale ou horizontale des 3 jetons du joueur.

Les jetons peuvent être déplacés sur le plateau le long des lignes de connexion, selon cette règle:

Vers toute position vide adjacente (c'est-à-dire d'une position de bord au centre, ou du centre à une position de bord, ou d'une position de bord à une position de bord adjacente

Un joueur doit effectuer un mouvement à moins qu'il n'y ait aucune position vide adjacente, auquel cas le mouvement est ignoré.

Le défi

Vous êtes joueur 1et votre coup est le suivant. Écrivez un programme ou une fonction qui détermine si:

  • vous pouvez forcer une victoire avec 2 coups ou moins ( victoire définitive )
  • vous pouvez gagner avec 2 coups ou moins, si votre adversaire fait une erreur ( victoire possible )
  • vous ne pouvez pas gagner avec 2 coups ou moins, car vous aurez besoin de plus de coups ou parce que les coups forcés conduisent votre adversaire à gagner ( impossible de gagner )

Exigences

  • Même si vous gagnez définitivement lorsque vous ennuyez votre adversaire à mort, votre programme doit se terminer dans un temps fini.
  • Vous pouvez écrire un programme ou une fonction.

Contribution

Les joueurs sont représentés par 1et 2. 0définit un champ libre. Vous pouvez prendre l'entrée comme une matrice ou un tableau.

Précis

A         B         C         D
2 1 0  |  2 1 0  |  1 0 1  |  1 2 2
2 1 2  |  0 1 0  |  1 0 2  |  2 1 O
0 0 1  |  2 2 1  |  0 2 2  |  O O 1

A: [2,1,0,2,1,2,0,0,1]
B: [2,1,0,0,1,0,2,2,1]
C: [1,0,1,1,0,2,0,2,2]
D: [1,2,2,2,1,0,0,0,1]

Possible

A         B         C
1 0 1  |  1 0 1  |  1 2 2
1 2 2  |  1 2 0  |  0 0 1
2 0 0  |  2 0 2  |  2 1 0

A: [1,0,1,1,2,2,2,0,0]
B: [1,0,1,1,2,0,2,0,2]
C: [1,2,2,0,0,1,2,1,0]

Impossible

A         B    
1 0 0  |  1 2 0
1 2 2  |  2 1 0
2 0 1  |  1 2 0

A: [1,0,0,1,2,2,2,0,1]
B: [1,2,0,2,1,0,1,2,0]

Production

Votre programme devrait afficher / renvoyer un smiley:

  • Victoire définitive: :)
  • Victoire possible: :|
  • Impossible de gagner: :(

Exemples

Victoire définitive en deux coups:

[2][1][ ] 1. [2][1][ ]
[2][1][2] -> [2][1][2]
[ ][ ][1]    [ ][1][ ]

[2][1][ ] 1. [2][1][ ]    [ ][1][ ] 2. [ ][ ][1]
[ ][1][ ] -> [ ][ ][1] -> [2][ ][1] -> [2][ ][1]
[2][2][1]    [2][2][1]    [2][2][1]    [2][2][1]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][ ][2] -> [1][ ][2] -> [1][ ][2] -> [ ][ ][2]
[ ][2][2]    [ ][2][2]    [2][ ][2]    [2][ ][2]

Victoire possible en deux coups:

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][2][2] 1. [ ][2][2]    [2][ ][2] 2. [1][2][2]
[ ][ ][1] -> [1][ ][1] -> [1][ ][1] -> [1][1][1]
[2][1][ ]    [2][1][ ]    [2][1][ ]    [2][ ][ ]

Impossible de gagner en deux coups:

[1][ ][ ]
[1][2][2]
[2][ ][1]

Prime

Dans le cas où une victoire définitive est possible et que votre programme génère les mouvements d'une manière vers le succès ainsi que a1:a2(1 mouvement) ou a1:a2,a3:b2(2 mouvements), vous pouvez retirer 30% de votre nombre d'octets.


C'est le golf de code - donc la réponse la plus courte en octets l'emporte. Les failles standard ne sont pas autorisées.


Merci à Peter Taylor qui a corrigé quelques défauts et amélioré la formulation dans le bac à sable .

insertusernamehere
la source
Connexes .
insertusernamehere
1
J'aime ces tableaux / graphiques ascii =)
flawr
1
Que se passe-t-il si un joueur est incapable de bouger? par exemple dans [1,0,0,2,1,0,2,2,1], le joueur 2 ne peut pas bouger - est-ce une victoire pour le joueur 1?
VisualMelon
1
@LeifWillerts Je peux me méprendre sur ce que vous voulez dire, mais dans ce cas, aucun joueur n'est dans un état gagnant - il ne gagne qu'en ayant une ligne horizontale ou verticale (pas diagonale).
VisualMelon
3
Eh bien, il n'y a que 1680 positions de carte valides, donc le codage en dur peut donner un peu plus de 210 octets. (moins si la symétrie est considérée)
lirtosiast

Réponses:

1

Haskell, 580 564 441 octets

C'est jusqu'où je peux jouer au golf pour l'instant. Je ne sais pas si les autres langues peuvent le battre.

Appelez msur une liste de listes comme [[2,1,0],[2,1,2],[0,0,1]](Definite A).

import Data.Array
r=[0..2]
p?f=[(x,y)|x<-r,y<-r,f!y!x==p]
p%f=all(==x)xs||all(==y)ys where(x:xs,y:ys)=unzip$p?f
s p x y f=f//[(y,f!y//[(x,p)])]
p#f=[s 0 x y$s p u v f|a@(x,y)<-p?f,b@(u,v)<-0?f,((x-u)*(y-v)==0&&abs(x+y-u-v)==1)||elem(1,1)[a,b]]
p&f|p#f>[]=p#f|0<1=[f]
e=any
i a p f=e(a$e(p%))(map(map(p&))(map((3-p)&)$p&f))||e(p%)(p&f)
l=listArray(0,2)
f(True,_)=":)"
f(False,True)=":|"
f _=":("
m=putStrLn.f.(\f->(i all 1 f,i e 1 f)).l.map l

Code de test:

da = [[2,1,0],[2,1,2],[0,0,1]]
db = [[2,1,0],[0,1,0],[2,2,1]]
dc = [[1,0,1],[1,0,2],[0,2,2]]
dd = [[1,2,2],[2,1,0],[0,0,1]]
pa = [[1,0,1],[1,2,2],[2,0,0]]
pb = [[1,0,1],[1,2,0],[2,0,2]]
pc = [[1,2,2],[0,0,1],[2,1,0]]
ia = [[1,0,0],[1,2,2],[2,0,1]]
ib = [[1,2,0],[2,1,0],[1,2,0]]
al = [da,db,dc,dd,pa,pb,pc,ia,ib]

mapM_ m al Retour:

:)
:)
:)
:)
:|
:|
:|
:(
:(
Leif Willerts
la source
1
Corrigé, je pense. Va vérifier et bien jouer le soir (ce qui est avant la fin du délai de grâce)
Leif Willerts
5

C # - 739 663 octets

Programme complet, lit les entrées de argv et semble fonctionner. Exécutez-le comme

ThreeMill 1 2 1 1 2 0 0 0 2

Si cette méthode de saisie est inacceptable, je serai heureux de la changer (jamais comme utiliser argv).

using System;using System.Linq;class P{static void Main(string[]A){var I=new[]{0,3,6,1,4,7,2,5,8};Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" ";Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0;Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I.Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))).Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;})).DefaultIfEmpty(B).ToArray();int h,G;Console.WriteLine(":"+"(|))"[V(A,"1").Max(z=>((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0)+(h>G?W(z,"1")*2:2))]);}}

J'étais peu enclin à publier cela hier, parce que je n'ai pas pu le faire beaucoup (pas beaucoup de temps, et je pourrais être hors de l'entraînement), mais comme il n'y a pas encore eu de réponse, je ' Je le posterai de toute façon, je ne m'attends certainement pas à la prime, je préfère qu'il soit remis à quelqu'un qui a mis un peu plus d'effort dans le leur avant de poster!

Edit: a remplacé tous les bools par des ints, ce qui m'a permis de mieux utiliser Linq et a réussi à réduire les deux boucles foreach, ce qui a permis de réaliser de grosses économies. Je suis légèrement étonné que le hcompteur fonctionne ... ++ est un utilitaire si subtil.

Le programme est très simple, il explore simplement tous les mouvements possibles (stocke l'état de la carte dans une chaîne []). Il itère sur tous nos mouvements possibles (les planches qui en résultent), et compte le nombre de réponses de notre adversaire que nous pouvons battre avec succès ( G) (c'est-à-dire celles que nous gagnons, et il ne le fait pas). Il compte également le nombre de réponses possibles (h). Si nous pouvons en gagner, alors c'est possible, et nous ajoutons 1 à la somme, si nous pouvons tous les gagner, c'est un certain, et nous ajoutons 2 à la somme. Le maximum est donc notre meilleur résultat possible, et nous indexons dans la chaîne "(|))" pour retourner le visage approprié. Notez que nous avons besoin de l'extra ")" car la somme peut être de 2 ou 3 si c'est un certain (il est possible que nous ne semblions pas pouvoir battre les réponses ayant déjà gagné au premier coup, donc le contrôle possible est un peu trompeur).

Le programme recherche une victoire en produisant une chaîne à partir du tableau, c'est-à-dire des lignes et des colonnes séparées par des espaces, et recherche simplement une chaîne de 3 caractères du joueur dans cette chaîne (par exemple "201 201 021 220 002 111" est un gagner pour nous)

using System;
using System.Linq; // all important

class P
{
    static void Main(string[]A) // transform to int?
    {
        var I=new[]{0,3,6,1,4,7,2,5,8}; // vertical indexes
        Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" "; // joins the strings up, so that there is a space separating each group of three (including at end)
        Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0; // checks if a particular player wins
        Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I // for each imagineable move
            .Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))) // where it's legal
            .Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;}) // select the resulting board
        ).DefaultIfEmpty(B) // allow not-moving
        .ToArray();

        int h, // h stores the number of responses the opponent has to each move
        G; // G stores the number of responses by the opponent we can beat

        Console.WriteLine(":"+"(|))"[ // we index into this to decide which smiley
            V(A,"1").Max(z=>
                    ((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0) // if there is atleast 1 reponse by the opponent we can beat, we can possibly win
                    +(h>G?W(z,"1")*2:2) // if there are moves which we can't win, then if we have already won (one-move), else, we can definitely win
                   ) // sum is therefore 0 if impossible, 1 if possible, >2 (no more than 3) if definite 
            ]);

    }
}

Voici mon script de test:

ThreeMill 2 1 0 2 1 2 0 0 1
ThreeMill 2 1 0 0 1 0 2 2 1
ThreeMill 1 0 1 1 0 2 0 2 2
ThreeMill 1 2 2 2 1 0 0 0 1

ThreeMill 1 0 1 1 2 2 2 0 0
ThreeMill 1 0 1 1 2 0 2 0 2
ThreeMill 1 2 2 0 0 1 2 1 0

ThreeMill 1 0 0 1 2 2 2 0 1
ThreeMill 1 2 1 1 2 0 0 0 2
ThreeMill 1 0 1 2 0 2 1 0 2

Quelles sorties

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
VisualMelon
la source
Agréable. Merci d'être le premier. :) Si ça va, j'attribuerai la prime après le week-end, pour la garder encore quelques jours dans l'onglet vedette.
insertusernamehere
@insertusernamehere C'est très bien pour moi, si je ne peux pas être dérangé pour faire un vrai travail, je pourrais faire un peu plus de travail là-dessus demain.
VisualMelon
1
Cela me rappelle ce commentaire: " Je n'ai pas pu répondre à une question pendant QUARANTE MINUTES. C'est critique! Envoyez simplement les détails de la base de données et je vais insérer mes réponses SQL. J'ai tellement de travail à éviter et aucune raison pour l'éviter !! "sur Pourquoi Stack Overflow ne fonctionne pas? . :)
insertusernamehere
1

PowerShell 576 550 octets

Je ne serai pas si facilement dissuadé - si je ne peux pas obtenir un C # inférieur à 631 octets, je devrai utiliser un autre langage à la place! J'espère que Leif Willerts supprimera 5 octets de sa réponse, parce que j'ai décidé que je n'aimais pas trop PowerShell, peut-être que je dois le regarder objectivement en termes de nombre d'octets ...

Ceci est un script, vous l'exécutez . .\mill.ps1 "201102021". C'est plutôt une copie de ma réponse C #, uniquement dans un langage avec lequel j'ai peu d'expérience. Je n'ai pas fait trop d'efforts pour jouer au golf, car il a fallu si longtemps pour commencer à travailler, et il est déjà raisonnablement compact.

Edit: ne pouvait pas simplement laisser ces [Math]::Floorappels là-dedans

param($U);$I=0,3,6,1,4,7,2,5,8;function J($S){($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}function W($D,$p){(J $D)-or(J $D[$I])}function V($Q,$C){$I|%{$a=$_;$I|?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}|%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}|%{$n=1}{$n=0;$_}{if($n){$Q}}}$e=$f=0;V $U "1"|%{$h=0;$x=$_;V $x "2"|%{$k=0;(V $_ "1"|%{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k};if($h-eq0-or(W $x "1")){$f=2}};":"+"(|))"[$e+$f]

Si vous avez une description de la façon dont cela fonctionne ... la réponse C # est pour vous, mais j'espère que les commentaires la rendent suffisamment claire. Les points-virgules peuvent ne pas correspondre parfaitement à la commande sur une seule ligne, je ne sais pas encore où ils sont nécessaires et ne le sont pas, et je ne les ai pas recopiés lorsque j'ai mis le tout sur une seule ligne.

param($U); # take input as argument

$I=0,3,6,1,4,7,2,5,8; # cols

function J($S){ # checks if this is a winning string
($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}

function W($D,$p){ # checks if this is a winning board
(J $D)-or(J $D[$I])} # $D[$I] reorganises into columns

function V($Q,$C){ # yields all valid moves from position $Q for player $C
$I|%{$a=$_;$I| # for each possible move
?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}| # where legal
%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}| # make the move (copy $Q to an array, modify, join into a string)
%{$n=1}{$n=0;$_}{if($n){$Q}}} # if empty, return $Q - I am confident this can be achieved with commas, and [0], and maybe a +, but I don't want to think about it

$e=$f=0; # possible, definite

V $U "1"|%{ # for all our possible moves
$h=0;$x=$_; # $k is whether we win all of these
  V $x "2"| # for all opponent's responses
  %{$k=0;(V $_ "1"| # for all our responses
  %{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k}; # if we can win and he can't, then things are looking good, set $e to 1 (possible win)

  if($h-eq0-or(W $x "1")){$f=2} # if we win every move, or we have already won, it's a definite
};

":"+"(|))"[$e+$f] # smile, it's all over

Script de test (PowerShell):

. .\mill.ps1 "210212001"
. .\mill.ps1 "210010221"
. .\mill.ps1 "101102022"
. .\mill.ps1 "122210001"

. .\mill.ps1 "101122200"
. .\mill.ps1 "101120202"
. .\mill.ps1 "122001210"

. .\mill.ps1 "100122201"
. .\mill.ps1 "121120002"
. .\mill.ps1 "101202102"

. .\mill.ps1 "100122201"
. .\mill.ps1 "120210120"

Sortie de celui-ci:

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
:(
:(
3 tours
la source
1

Python 3, 566 557 octets

Je vais devoir voir si je peux jouer plus loin, ou si je peux obtenir le bonus de 30%, mais après beaucoup de procrastination, voici ma réponse.

def t(g,x=1,r=0,z=0):
 m=[[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]];a=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];z=z or[[],[],[],[]];s=0
 if r>3:return z
 for i in a:
  if g[i[0]]==g[i[1]]==g[i[2]]>0:s=g[i[0]];break
 z[r]+=s,
 for q in range(9):
  i=g[q]
  if i==x:
   for p in m[q]:
    if g[p]<1:n=g[:];n[q],n[p]=n[p],n[q];z=t(n,3-x,r+1,z)
 if r:return z
 else:
  w=l=0
  for j in range(4):w=w or 1in z[j];l=l or 2in z[j]
  if l<1and w:return":)"
  elif w<1and l:return":("
  else:return":|"

Non golfé:

def three_mens_morris(grid, player=1, rec=0, w_l=0, p=0):
    moves = [[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]]
    w_l = w_l or [[],[],[],[]]
    if rec == 4: return w_l
    result = check_grid(grid)
    w_l[rec].append(result)
    for sq_1 in range(len(grid)):
        piece = grid[sq_1]
        if piece == player:
            for sq_2 in moves[sq_1]:
                if grid[sq_2] == 0:
                    new_grid = grid.copy()
                    new_grid[sq_1],new_grid[sq_2]=new_grid[sq_2],new_grid[sq_1]
                    w_l = three_mens_morris(new_grid,3-player,rec+1,w_l)
    if p: print(w_l)
    if rec:
        return w_l
    else:
        win = loss = 0
        for i in range(4):
            if 1 in w_l[i]:
                win = 1
            elif 2 in w_l[i]:
                loss = 1
        if p:print(win,loss)
        if loss==0 and win:
            return ":)"
        elif loss and win==0:
            return ":("
        else:
            return ":|"

def check_grid(grid):
    rows = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
    for i in rows:
        if grid[i[0]]==grid[i[1]]==grid[i[2]] and grid[i[0]]:
            return grid[i[0]]
    return 0
Sherlock9
la source