Puoi vincere con altre due mosse al Three Men's Morris?


16

bounties

N. 1 ( assegnato )

Lancerò 50 ripetitori per la prima risposta valida

N. 2 ( assegnato )

Lancerò un altro 100 rappresentanti per la risposta valida più breve.

N. 3 ( aperto per le presentazioni )

Lancerò 200 rappresentanti per il primo con una risposta valida più breve e significativa. Significativo essere al massimo il 45% della risposta attualmente più breve ( 564 byte x 0,45 = max 254 byte ).


Il gioco

Ricordi il classico gioco " Nine Men's Morris " o semplicemente " Mill "? C'è una variante chiamata Three Men's Morris che è un po 'come un mutevole tic-tac-toe.

Regole

Questo è il tabellone vuoto del gioco:

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

[ ]è un campo e |–/\rappresenta percorsi tra tali campi.

La partita è giocata da due giocatori 1e 2ognuno piazza 3 gettoni sul tabellone. Questo in realtà è già successo e siamo nel gioco. Il gioco si vince se un giocatore può formare una millfila verticale o orizzontale dei 3 gettoni del giocatore.

I token possono essere spostati sulla scheda lungo le linee di connessione, secondo questa regola:

In qualsiasi posizione vuota adiacente (ovvero da una posizione del bordo al centro, o dal centro a una posizione del bordo, o da una posizione del bordo a una posizione del bordo adiacente

Un giocatore deve fare una mossa a meno che non ci sia una posizione vuota adiacente, nel qual caso la mossa viene saltata.

La sfida

Sei un giocatore 1e la tua mossa è la prossima. Scrivi un programma o una funzione, che determina se:

  • puoi forzare una vittoria con 2 o meno mosse ( vittoria definitiva )
  • puoi vincere con 2 o meno mosse, se il tuo avversario commette un errore ( possibile vittoria )
  • non puoi vincere con 2 o meno mosse, perché avrai bisogno di più mosse o perché le mosse forzate portano il tuo avversario a vincere ( impossibile vincere )

Requisiti

  • Anche se vincerai sicuramente quando avrai annoiato il tuo avversario a morte, il tuo programma dovrà terminare a tempo finito.
  • È possibile scrivere un programma o una funzione.

Ingresso

I giocatori sono rappresentati da 1e 2. 0definisce un campo libero. È possibile accettare input come matrice o matrice.

Definito

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]

Possibile

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]

Impossibile

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]

Produzione

Il tuo programma dovrebbe generare / restituire un emoticon:

  • Vittoria definitiva: :)
  • Possibile vittoria: :|
  • Impossibile vincere: :(

Esempi

Vittoria definitiva in due mosse:

[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]

Possibile vittoria in due mosse:

[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][ ][ ]

Impossibile vincere in due mosse:

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

indennità

Nel caso in cui sia possibile una vincita definita e il tuo programma fornisca le mosse di una via al successo, come a1:a2(1 mossa) o a1:a2,a3:b2(2 mosse), puoi ritirare il 30% del conteggio dei byte.


Questo è il golf del codice - quindi vince la risposta più breve in byte. Le scappatoie standard non sono ammesse.


Grazie a Peter Taylor che ha corretto alcuni difetti e migliorato la formulazione nella Sandbox .



1
Mi piacciono quelle tabelle ascii / graphics =)
flawr

1
Cosa succede se un giocatore non è in grado di muoversi? ad es[1,0,0,2,1,0,2,2,1] , il giocatore 2 non può muoversi - è una vittoria per il giocatore 1?
VisualMelon,

1
@LeifWillerts Potrei fraintendere cosa intendi, ma in tal caso, nessun giocatore è in uno stato vincente - vincono solo avendo una linea orizzontale o verticale (non diagonale).
VisualMelon,

3
Bene, ci sono solo 1680 posizioni valide della scheda, quindi l'hardcoding può dare poco più di 210 byte. (meno se si considera la simmetria)
lirtosiast

Risposte:


1

Haskell, 580 564 441 byte

Questo è quanto posso giocare a golf per ora. Non sono sicuro che le altre lingue possano batterlo.

Chiama mun elenco di elenchi come [[2,1,0],[2,1,2],[0,0,1]](Definito 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

Codice di prova:

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 ritorna:

:)
:)
:)
:)
:|
:|
:|
:(
:(

1
Corretto, penso. Doublecheck e correttamente giocheranno a golf la sera (che è qui prima che finisca il periodo di grazia)
Leif Willerts

5

C # - 739 663 byte

Programma completo, legge input da argv e sembra funzionare. Eseguilo come

ThreeMill 1 2 1 1 2 0 0 0 2

Se questo metodo di input è inaccettabile, sarò felice di cambiarlo (mai come usare 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))]);}}

Non sono stato propenso a pubblicare questo ieri, perché non sono stato in grado di giocarci molto (non ho avuto tutto il tempo e potrei essere fuori allenamento), ma dal momento che non c'è stata ancora una risposta, io ' Lo pubblicherò comunque, di certo non mi aspetto la generosità, preferirei che fosse andato a qualcuno che ha fatto un po 'più di sforzo prima di pubblicare!

Modifica: ha sostituito tutti i bool con ints, il che significava che avrei potuto fare un uso migliore di Linq e sono riuscito a far crollare entrambi i loop foreach, offrendo grandi risparmi. Sono leggermente sorpreso che ilh contatore funzioni ... ++ è un'utilità così sottile.

Il programma è molto semplice, esplora solo ogni possibile set di mosse (memorizza lo stato della scheda in una stringa []). Esamina tutte le nostre possibili mosse (le schede che ne risultano) e conta il numero di risposte del nostro avversario che possiamo battere con successo ( ). Se possiamo vincere qualsiasi, allora è possibile, e aggiungiamo 1 alla somma, se possiamo vincerli tutti, è un dato definitivo e aggiungiamo 2 alla somma. Il massimo è quindi il nostro miglior risultato possibile e ci indicizziamo nella stringa "(|))" per restituire la faccia appropriata. Nota che abbiamo bisogno di un extra ")" perché la somma può essere 2 o 3 se è definita (è possibile che non sembriamo in grado di battere le risposte che hanno già vinto al primo tentativo, quindi il controllo possibile è un po 'fuorviante).G ) (cioè quelle che vinciamo, e lui no). Conta anche il numero di possibili risposte (h

Il programma verifica la vittoria producendo una stringa dal tabellone, ovvero righe e colonne separate da spazi, e cerca solo una stringa di 3 caratteri del giocatore in questa stringa (es. "201 201 021 220 002 111" è un vinci per noi)

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 
            ]);

    }
}

Ecco il mio script di 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

Quali uscite

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)

Bello. Grazie per essere il primo. :) Se va bene, assegnerò il premio dopo il fine settimana, per mantenerlo ancora qualche giorno nella scheda in primo piano.
insertusernamehere

@inserireusernamehere Va bene per me, se non posso essere disturbato a fare un vero lavoro, potrei fare un po 'di più su questo domani.
VisualMelon,

1
Questo mi ricorda questo commento: " Non sono stato in grado di rispondere a una domanda per quaranta minuti. Questo è fondamentale! Basta inviare i dettagli del database e SQL inserirò le mie risposte. Ho così tanto lavoro da evitare e nessun motivo per evitarlo !! "su Perché Stack Overflow non funziona? . :)
inserireusernamehere

1

PowerShell 576 550 byte

Non mi scoraggerò così facilmente - se non riesco a ottenere C # al di sotto di 631 byte, dovrò invece usare una lingua diversa! Spero che Leif Willerts eliminerà 5 byte dalla sua risposta, perché ho deciso di non amare troppo PowerShell, forse ho solo bisogno di guardarlo oggettivamente in termini di conteggi di byte ...

Questo è uno script, tu lo esegui . .\mill.ps1 "201102021". È abbastanza bene una copia della mia risposta C #, solo in una lingua con cui ho poca esperienza. Non ho fatto uno sforzo eccessivo per giocare a golf, perché ci è voluto così tanto tempo per iniziare a lavorare in prima istanza, ed è già ragionevolmente compatto.

Modifica: non poteva semplicemente lasciare quelle [Math]::Floorchiamate lì dentro

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]

Se hai una descrizione di come funziona ... la risposta C # fa per te, ma speriamo che i commenti lo chiariscano abbastanza. I punti e virgola potrebbero non corrispondere perfettamente al comando a riga singola, non sono ancora sicuro di dove siano necessari e non lo sono, e non li ho copiati quando ho messo tutto su una riga.

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 di 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"

Uscita di ciò:

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
:(
:(

1

Python 3, 566 557 byte

Dovrò vedere se riesco a giocare a golf ulteriormente, o se posso ottenere il bonus del 30%, ma dopo molta procrastinazione, ecco la mia risposta.

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":|"

Ungolfed:

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
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.