Können Sie mit zwei weiteren Zügen bei Three Men's Morris gewinnen?

16

Kopfgelder

Nr. 1 ( ausgezeichnet )

Ich werde 50 Wiederholungen für die erste gültige Antwort geben

Nr. 2 ( ausgezeichnet )

Ich werde weitere 100 Wiederholungen einwerfen, um die kürzeste gültige Antwort zu erhalten.

Nr. 3 ( offen für Einreichungen )

Ich werde 200 Wiederholungen für die erste mit einer deutlich kürzeren gültigen Antwort einwerfen. Signifikant sind höchstens 45% der aktuell kürzesten Antwort ( 564 Bytes x 0,45 = maximal 254 Bytes ).


Das Spiel

Erinnerst du dich an den Klassiker " Nine Men's Morris " oder einfach " Mill "? Es gibt eine Variante namens Three Men's Morris, die einem veränderlichen Tic-Tac-Toe ähnelt.

Regeln

Dies ist die leere Tafel des Spiels:

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

[ ]ist ein Feld und |–/\repräsentiert Routen zwischen diesen Feldern.

Das Spiel wird von zwei Spielern gespielt 1und 2den jedem Platz 3 Token auf dem Brett. Das ist eigentlich schon passiert und wir sind im Spiel. Das Spiel ist gewonnen, wenn ein Spieler milleine vertikale oder horizontale Reihe der 3 Spielsteine ​​des Spielers bilden kann .

Spielmarken können auf dem Spielfeld entlang der Verbindungslinien verschoben werden. Dabei gilt folgende Regel:

Zu jeder benachbarten leeren Position (dh von einer Kantenposition zur Mitte oder von der Mitte zu einer Kantenposition oder von einer Kantenposition zu einer benachbarten Kantenposition

Ein Spieler muss einen Zug machen, es sei denn, es gibt keine angrenzende leere Position. In diesem Fall wird der Zug übersprungen.

Die Herausforderung

Du bist ein Spieler 1und dein Zug ist der nächste. Schreiben Sie ein Programm oder eine Funktion, die bestimmt, ob:

  • Sie können einen Gewinn mit 2 oder weniger Zügen erzwingen ( definitiver Gewinn )
  • Sie können mit 2 oder weniger Zügen gewinnen, wenn Ihr Gegner einen Fehler macht ( möglicher Gewinn )
  • Sie können nicht mit 2 oder weniger Zügen gewinnen, weil Sie mehr Züge benötigen oder weil erzwungene Züge Ihren Gegner zum Sieg führen ( unmöglich zu gewinnen ).

Bedarf

  • Auch wenn Sie definitiv gewinnen, wenn Sie Ihren Gegner zu Tode langweilen, muss Ihr Programm in endlicher Zeit abgeschlossen sein.
  • Sie können ein Programm oder eine Funktion schreiben.

Eingang

Die Spieler werden von 1und vertreten 2. 0definiert ein freies Feld. Sie können Eingaben als Matrix oder Array übernehmen.

Auf jeden Fall

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]

Möglich

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]

Unmöglich

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]

Ausgabe

Ihr Programm sollte einen Smiley ausgeben / zurückgeben:

  • Definitiver Gewinn: :)
  • Möglicher Gewinn: :|
  • Unmöglich zu gewinnen: :(

Beispiele

Definitiver Gewinn in zwei Zügen:

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

Möglicher Gewinn in zwei Zügen:

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

In zwei Zügen nicht zu gewinnen:

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

Bonus

Falls ein definitiver Gewinn möglich ist und Ihr Programm die Züge eines Weges zum Erfolg ausgibt, wie zum Beispiel a1:a2(1 Zug) oder a1:a2,a3:b2(2 Züge), können Sie 30% Ihrer Byteanzahl abziehen .


Das ist Code Golf - also gewinnt die kürzeste Antwort in Bytes. Standardlücken sind nicht zulässig.


Vielen Dank an Peter Taylor, der einige Fehler behoben und die Formulierung in der Sandbox verbessert hat .

insertusernamehere
quelle
Verwandte .
insertusernamehere
1
Ich mag diese ASCII-Tabellen / Grafiken =)
flawr
1
Was passiert, wenn sich ein Spieler nicht bewegen kann? zB [1,0,0,2,1,0,2,2,1]kann sich Spieler 2 nicht bewegen - ist dies ein Gewinn für Spieler 1?
VisualMelon
1
@LeifWillerts Ich verstehe vielleicht falsch, was Sie meinen, aber in diesem Fall befindet sich kein Spieler in einem Gewinnzustand - sie gewinnen nur durch eine horizontale oder vertikale Linie (nicht diagonal).
VisualMelon
3
Nun, es gibt nur 1680 gültige Kartenpositionen, so dass die Hardcodierung etwas mehr als 210 Bytes ergeben kann. (weniger, wenn Symmetrie berücksichtigt wird)
Lirtosiast

Antworten:

1

Haskell, 580 564 441 Bytes

So weit kann ich jetzt noch Golf spielen. Nicht sicher, ob die anderen Sprachen es schlagen können.

Rufen Sie meine Liste von Listen wie [[2,1,0],[2,1,2],[0,0,1]](Definite A) auf.

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

Testcode:

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 kehrt zurück:

:)
:)
:)
:)
:|
:|
:|
:(
:(
Leif Willerts
quelle
1
Korrigiert, denke ich. Wird Doublecheck und richtig Golf am Abend (die hier ist, bevor die Kulanzfrist endet)
Leif Willerts
5

C # - 739 663 Bytes

Komplettes Programm, liest Eingaben von argv und scheint zu funktionieren. Führen Sie es wie

ThreeMill 1 2 1 1 2 0 0 0 2

Wenn diese Eingabemethode nicht akzeptabel ist, werde ich sie gerne ändern (nie wie bei Verwendung von 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))]);}}

Ich war nicht geneigt, dies gestern zu posten, weil ich nicht viel Golf spielen konnte (ich hatte nicht so viel Zeit und könnte aus dem Training geraten sein), aber da es noch keine Antwort gab, habe ich Ich werde es trotzdem posten, ich erwarte mit Sicherheit kein Kopfgeld. Ich würde es lieber jemandem überlassen, der sich vor dem Posten ein bisschen mehr Mühe gibt!

Bearbeiten: Ersetzte alle Bools durch Ints, was bedeutete, dass ich Linq besser nutzen konnte, und schaffte es, beide foreach-Schleifen zusammenzubrechen, was zu großen Einsparungen führte. Ich bin etwas erstaunt, dass der hZähler funktioniert ... ++ ist so ein subtiles Dienstprogramm.

Das Programm ist sehr einfach, es untersucht nur alle möglichen Züge (speichert den Board-Status in einem String []). Es durchläuft alle unsere möglichen Züge (die daraus resultierenden Bretter) und zählt die Anzahl der Antworten unseres Gegners, die wir erfolgreich schlagen können ( G) (dh diejenigen, die wir gewinnen, und er nicht). Es zählt auch die Anzahl der möglichen Antworten (h). Wenn wir eines gewinnen können, ist es möglich, und wir addieren 1 zu der Summe. Wenn wir alle gewinnen können, ist es eine bestimmte Summe, und wir addieren 2 zu der Summe. Das Maximum some ist daher unser bestmögliches Ergebnis, und wir indizieren die Zeichenfolge "(|))", um die entsprechende Fläche zurückzugeben. Beachten Sie, dass wir das zusätzliche ")" benötigen, da die Summe 2 oder 3 sein kann, wenn es sich um eine bestimmte handelt (es ist möglich, dass wir keine Antworten schlagen können, die bereits auf Anhieb gewonnen wurden, daher ist die mögliche Überprüfung ein bisschen irreführend).

Das Programm prüft auf einen Sieg, indem es eine Zeichenfolge aus dem Spielplan erzeugt, dh durch Leerzeichen getrennte Zeilen und Spalten, und sucht in dieser Zeichenfolge nach einer Zeichenfolge mit 3 Zeichen des Spielers (z. B. "201 201 021 220 002 111" ist a gewinnen für uns)

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

    }
}

Hier ist mein Testskript:

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

Welche Ausgänge

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
VisualMelon
quelle
Nett. Danke, dass du der Erste bist. :) Wenn es in Ordnung ist, werde ich das Kopfgeld nach dem Wochenende vergeben, um es noch ein paar Tage in der ausgewählten Registerkarte zu behalten.
insertusernamehere
@insertusernamehere Das ist in Ordnung für mich. Wenn ich nicht die Mühe habe, echte Arbeit zu leisten, werde ich vielleicht morgen noch mehr daran arbeiten.
VisualMelon
1
Dies erinnert mich an diesen Kommentar: " Ich konnte eine Frage für FORTY MINUTES nicht beantworten. Dies ist kritisch! Senden Sie einfach die Datenbankdetails und ich werde SQL meine Antworten einfügen. Ich habe so viel Arbeit zu vermeiden und keinen Grund um es zu vermeiden !! "auf Warum funktioniert Stack - Überlauf nicht? . :)
insertusernamehere
1

PowerShell 576 550 Bytes

Ich werde mich nicht so leicht abschrecken lassen - wenn ich C # nicht unter 631 Bytes bekomme, muss ich stattdessen eine andere Sprache verwenden! Ich hoffe, dass Leif Willerts seine Antwort um 5 Bytes verkürzt, weil ich entschieden habe, dass ich PowerShell nicht sonderlich mag. Vielleicht muss ich es nur objektiv in Byte-Zahlen betrachten ...

Dies ist ein Skript, mit dem Sie es ausführen . .\mill.ps1 "201102021". Es ist ziemlich gut eine Kopie meiner C # -Antwort, nur in einer Sprache, mit der ich wenig Erfahrung habe. Ich habe mir nicht allzu viel Mühe gegeben, um Golf zu spielen, weil es in erster Linie so lange gedauert hat, bis ich meine Arbeit aufgenommen habe, und weil es schon einigermaßen kompakt ist.

Bearbeiten: konnte diese [Math]::FloorAnrufe nicht einfach dort belassen

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]

Wenn Sie eine Beschreibung der Funktionsweise haben, ist die C # -Antwort genau das Richtige für Sie. Die Semikolons stimmen möglicherweise nicht perfekt mit dem einzeiligen Befehl überein. Ich bin mir noch nicht sicher, wo sie benötigt werden und wo nicht. Ich habe sie nicht zurückkopiert, als ich das Ganze in eine Zeile geschrieben habe.

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

Testskript (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"

Ausgabe davon:

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
:(
:(
VisualMelon
quelle
1

Python 3, 566 557 Bytes

Ich werde sehen müssen, ob ich weiter Golf spielen kann oder ob ich den 30% -Bonus bekomme, aber nach langem Hin und Her ist hier meine Antwort.

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
Sherlock9
quelle