Tic-Tac-Toe-Gewinner bestimmen (rundenbasiert)

26

Lass uns Code-Golf spielen!

Die Herausforderung besteht darin, den Gewinner einer Partie Tic-Tac-Toe zu finden.

Dies wurde oft getan, indem ein Board mit einem eindeutigen Gewinner angegeben wurde. Hier ist jedoch die Wendung:

Die Zellen sind folgendermaßen nummeriert:

1|2|3
-+-+-
4|5|6
-+-+-
7|8|9

Sie erhalten eine Reihe von genau 9 Zügen wie folgt:

{3, 5, 6, 7, 9, 8, 1, 2, 3}

Dies wird wie folgt analysiert:

  • Spieler 1 markiert Zelle 3
  • Spieler 2 markiert Zelle 5
  • Spieler 1 markiert Zelle 6
  • Spieler 2 markiert Zelle 7
  • Spieler 1 markiert Zelle 9
  • Spieler 1 hat gewonnen

Hinweis: Das Spiel wird nicht unterbrochen, nachdem ein Spieler gewonnen hat. Es kann vorkommen, dass der unterlegene Spieler drei Mal hintereinander nach dem gewinnenden Spieler gewinnt, aber nur der erste Gewinn zählt.

Ihre Aufgabe ist es nun, 9 Zahlen als Eingabe und Ausgabe des Gewinners und der Runde, in der der Gewinn stattgefunden hat, zu erhalten. Wenn niemand gewinnt, geben Sie eine Konstante Ihrer Wahl aus. Sie können Eingaben empfangen und Ausgaben über jedes Standardmittel / -format bereitstellen.

Habe Spaß!

Einige weitere Beispiele auf Anfrage:

{2,3,4,5,6,7,1,8,9} => Player 2 wins in round 6
{1,2,4,5,6,7,3,8,9} => Player 2 wins in round 8
{1,2,3,5,4,7,6,8,9} => Player 2 wins in round 8
Grünzwanzling
quelle
11
Willkommen bei PPCG! Dies ist ein netter erster Beitrag, aber normalerweise mögen wir keine sehr restriktiven Eingabe- / Ausgabeformate . Würden Sie in Betracht ziehen, die "Spieler X gewinnt in Runde Y" zu entfernen und uns in einem angemessenen Format wie einer Liste ausgeben zu lassen [X, Y]? Können wir im Falle eines Gleichstands stattdessen einen anderen konsistenten Wert ausgeben? Ich empfehle dies, da das Drucken dieser exakten Zeichenfolgen nicht unbedingt zum Golfen gehört. Für zukünftige Herausforderungen empfehle ich die Verwendung der Sandbox . :-)
Mr. Xcoder
Entschuldigung, mein fehler. Ich denke es ist jetzt richtig.
Grünzwanzling
Lesen Sie die Herausforderung bis zum Ende, ich sage, dass es ein Unentschieden geben kann und dass Sie etwas Ihrer Wahl ausgeben können, wenn es passiert. Ich gebe {2,6} zurück, wenn Spieler 2 in Runde 6 gewinnt, und {0,0}, wenn niemand gewinnt.
Grünzwanzling
Können wir alles mit 0-Index verwenden? (Zellen, Spieler, Runden)
Arnauld
1
"Sie erhalten eine Reihe von genau 9 Zügen wie folgt: {3, 5, 6, 7, 9, 8, 1, 2, 3}" - sollte 3wirklich zweimal erscheinen?
Jonathan Allan

Antworten:

8

Netzhaut , 114 Bytes

(.)(.)
$1O$2X
^
123;;456;;789¶X
{`(.)(.*¶)(.)\1
$3$2
}`.*(.)(.)*\1(?<-2>.)*(?(2)(?!))\1.*¶(..)*
$1$#3
.*¶
T
T`d`Rd

Probieren Sie es online! Basierend auf meiner Antwort auf Tic-Tac-Toe - X oder O? . X<N>Wird ausgegeben, wenn der erste Spieler nach dem Zug gewinnt N, O<N>wenn der zweite Spieler gewinnt, Twenn keiner gewinnt. Erläuterung:

(.)(.)
$1O$2X
^
123;;456;;789¶X

Erstellt eine interne Tafel und markiert jeden Zug mit dem Spieler, dessen Zug es ist.

{`(.)(.*¶)(.)\1
$3$2

Wendet einen Zug an.

}`.*(.)(.)*\1(?<-2>.)*(?(2)(?!))\1.*¶(..)*
$1$#3

Sucht nach einem Gewinn. Wenn einer gefunden wird, wird das Spielbrett durch den Gewinner und die Anzahl der verbleibenden Züge ersetzt.

.*¶
T

Wenn die Züge erschöpft sind und niemand gewonnen hat, ist das Spiel ein Unentschieden.

T`d`Rd

Berechnen Sie die Anzahl der Runden aus der Anzahl der verbleibenden Züge.

Neil
quelle
4
Dies ist eine der üppigeren Antworten, die ich hier gesehen habe.
Lord Farquaad
6

MATL , 39 Bytes

3:g&+XIx"IX@oXK@(XIt!yXdyPXd&hK=Aa?KX@.

Ausgabe ist

  • 1und Rin getrennten Zeilen, wenn Benutzer 1 in Runde R gewinnt ;
  • 0und Rin getrennten Zeilen, wenn Benutzer 2 in Runde R gewinnt ;
  • leer, wenn niemand gewinnt.

Probieren Sie es online! Oder überprüfen Sie alle Testfälle .

Erläuterung

3:       % Push [1 2 3]
g        % Convert to logical. Gives [true true true]
&+       % Matrix of all pairs of additions. Gives a 3×3 matrix, which represents
         % the board in its initial state, namely all cells contain 2. This value
         % means "cell not used yet". 1 will represent "cell marked by user 1",
         % and 0 will represent "cell marked by user 2"
XI       % Copy into clipboard I
x        % Delete
"        % Implicit input: array with moves. For each move
  I      %   Push current board state
  X@     %   Push iteration index (starting at 1), that is, current round number
  o      %   Modulo 2: gives 1 or 0. This represents the current user
  XK     %   Copy into clipboard K
  @      %   Push current move ((that is, cell index)
  (      %   Write user identifier (1 or 0) into that cell. Cells are indexed
         %   linearly in column-major order. So the board is transposed compared
         %   to that in the challenge, but that is unimportant
  XI     %   Copy updated board into clipboard I
  t!     %   Duplicate and transpose
  y      %   Duplicate from below: push copy of board
  Xd     %   Extract main diagonal as a 3×1 vector
  y      %   Duplicate from below: push copy of transposed board
  PXd    %   Flip vertically and extract main diagonal. This is the anti-diagonal
         %   of the board
  &h     %   Concatenate stack horizontally. This concatenates the board (3×3),
         %   transposed board (3×3), main diagonal (3×1 vector) and anti-diagonal
         %   (3×1) into an 3×8 matrix
  K=     %   Push current user identifier. Test for equality with each entry of the
         %   3×8 matrix
  A      %   For each column, this gives true if all its entries are true. Note 
         %   that the first three columns in the 3×8 matrix are the board columns;
         %   the next three are the board rows; and the last two columns are the
         %   main diagonal and anti-diagonal. The result is a 1×8 vector
  a      %   True if any entry is true, meaning the current user has won
  ?      %   If true
    K    %     Push current user identifier
    X@   %     Push current round number
    .    %     Break for loop
         %   Implicit end
         % Implicit end
         % Implicit display
Luis Mendo
quelle
5

Javascript (ES6), 130 Byte

m=>m.reduce((l,n,i)=>l||(b[n-1]=p=i%2+1,"012,345,678,036,147,258,048,246".replace(/\d/g,m=>b[m]).match(""+p+p+p)&&[p,i+1]),0,b=[])

f=m=>m.reduce((l,n,i)=>l||(b[n-1]=p=i%2+1,"012,345,678,036,147,258,048,246".replace(/\d/g,m=>b[m]).match(""+p+p+p)&&[p,i+1]),0,b=[])
console.log(JSON.stringify(f([3,5,6,7,9,8,1,2,3])))
console.log(JSON.stringify(f([2,3,4,5,6,7,1,8,9])))
console.log(JSON.stringify(f([1,2,4,5,6,7,3,8,9])))
console.log(JSON.stringify(f([1,2,3,5,4,7,6,8,9])))

Erläuterung

m=>m.reduce((l,n,i)=>               // Reduce the input array with n as the current move
  l||(                              //  If there is already a winner, return it
  b[n-1]=p=i%2+1,                   //  Set the cell at b[n-1] to the current player p
  "012,345,678,036,147,258,048,246" //  For every digit in the list of possible rows:
    .replace(/\d/g,m=>b[m])         //   Replace it with the player at the cell
    .match(""+p+p+p)                //  If any of the rows is filled with p:
      &&[p,i+1]                     //   Return [p, current move]
),0,b=[])
Herman L
quelle
Würde es Ihnen etwas ausmachen, bitte eine Erklärung oder eine unbenutzte Version anzugeben? Ich bin daran interessiert, Ihre Lösung zu verstehen.
Jack
4

Java (OpenJDK 8) , 445 Byte

int[] t(int[]m){int[][]f=new int[3][3];boolean z=false;for(int i=0;i<9;i++){f[m[i]%3][m[i]/3]=z?2:1;if(f[m[i]%3][0]==(z?2:1)&&f[m[i]%3][1]==(z?2:1)&&f[m[i]%3][2]==(z?2:1)||f[0][m[i]/3]==(z?2:1)&&f[1][m[i]/3]==(z?2:1)&&f[2][m[i]/3]==(z?2:1)||m[i]%3+m[i]/3==2&&f[0][2]==(z?2:1)&&f[1][1]==(z?2:1)&&f[2][0]==(z?2:1)||m[i]%3==m[i]/3&&f[0][0]==(z?2:1)&&f[1][1]==(z?2:1)&&f[2][2]==(z?2:1)){return(new int[]{(z?2:1),++i});}z=!z;}return(new int[]{0,0});}

Probieren Sie es online!

Rückgabewert {1,8} bedeutet, dass Spieler 1 in Runde 8 gewonnen hat. Rückgabewert {0,0} bedeutet Unentschieden.

Grünzwanzling
quelle
5
Wenn Sie nicht alle unnötigen Abstände entfernen, wird diese Antwort aufgrund des fehlenden Golfaufwands als ungültig angesehen. Darüber hinaus wird es nicht wirklich empfohlen, Ihre eigene Herausforderung so schnell zu beantworten, und Sie möchten möglicherweise einen TIO- Link hinzufügen , damit wir Ihren Code testen können.
Mr. Xcoder
Verweise: Seriöser Anwärter ,
nimm
Es tut mir leid, ich habe das Falsche kopiert. Es ist in der Tat viel kürzer
Grünzwanzling
Sie können die Tipps zum Golfen in Java Frage sehen , um einige Bytes zu entfernen. Zum Beispiel falsekann durch ersetzt werden 1<0und das Leerzeichen nach dem ersten ]kann entfernt werden.
user202729
442 Bytes . Auch der Grund , warum die „Header“ und „Footer“ auf TIO vorhanden ist , dass Sie nicht zu kommentieren brauchen //Code that was submittedund //End of code.
user202729
2

Kotlin , 236 Bytes

i.foldIndexed(l()to l()){o,(a,b),p->fun f(i:(Int)->Int)=b.groupBy(i).any{(_,v)->v.size>2}
if(f{(it-1)/3}|| f{it%3}|| listOf(l(1,5,9),l(3,5,7)).any{b.containsAll(it)}){return p%2+1 to o}
b to a+p}.let{null}
fun l(vararg l:Int)=l.toList()

Verschönert

    i.foldIndexed(l() to l()) { o, (a, b), p ->
        fun f(i: (Int) -> Int) = b.groupBy(i).any { (_, v) -> v.size > 2 }
        if (f { (it - 1) / 3 } || f { it % 3 } || listOf(l(1, 5, 9), l(3, 5, 7)).any { b.containsAll(it) }) {
            return p % 2 + 1 to o
        }
        b to a + p
    }.let { null }
fun l(vararg l:Int)= l.toList()

Prüfung

fun f(i: List<Int>): Pair<Int, Int>? =
i.foldIndexed(l()to l()){o,(a,b),p->fun f(i:(Int)->Int)=b.groupBy(i).any{(_,v)->v.size>2}
if(f{(it-1)/3}|| f{it%3}|| listOf(l(1,5,9),l(3,5,7)).any{b.containsAll(it)}){return p%2+1 to o}
b to a+p}.let{null}
fun l(vararg l:Int)=l.toList()

data class Test(val moves: List<Int>, val winner: Int, val move: Int)

val tests = listOf(
        Test(listOf(3, 5, 6, 7, 9, 8, 1, 2, 3), 1, 5),
        Test(listOf(2, 3, 4, 5, 6, 7, 1, 8, 9), 2, 6),
        Test(listOf(1, 2, 4, 5, 6, 7, 3, 8, 9), 2, 8),
        Test(listOf(1, 2, 3, 5, 4, 7, 6, 8, 9), 2, 8)
)

fun main(args: Array<String>) {
    tests.forEach { (input, winner, move) ->
        val result = f(input)
        if (result != winner to move) {
            throw AssertionError("$input ${winner to move} $result")
        }
    }
}

TIO

TryItOnline

jrtapsell
quelle
1

Python 2 , 170 Bytes

q=map(input().index,range(1,10))
z=zip(*[iter(q)]*3)
o='',
for l in[q[2:7:2],q[::4]]+z+zip(*z):
 r=[n%2for n in l];y=all(r)*2+1-any(r)
 if y:o+=[max(l)+1,y],
print min(o)

Probieren Sie es online! oder Probieren Sie alle Testfälle aus

#swap cell number / turn
q=map(input().index,range(1,10))
#split in 3 parts (rows)
z=zip(*[iter(q)]*3)
#starting value for the list with the results
#since string are "greater" than lists, this will
#be the output value when there is a draw
o='',
#iterate over diagonals, rows and columns
for l in[q[2:7:2],q[::4]]+z+zip(*z):
 #use %2 to separate between player 1 and 2
 r=[n%2 for n in l]
 #store in y the value of the player if the trio is a valid win, 0 otherwise
 #it's a win if all moves are from the same player
 y=all(r)*2+1-any(r)
 #if y has a valid player, add the highest turn of the trio, and the player to o
 if y:o+=[max(l)+1,y],
#output the smaller turn of the valid winning trios
print min(o)
Stange
quelle
1

Jelly , 38 Bytes

;⁵s2ZṬḤ2¦SṖs3µ,ṚJị"$€;;ZEÐfṀḢµ$ƤµTḢ,ị¥

Probieren Sie es online!

Spieler 1 gewinnt: [round, 1]
Spieler 2 gewinnt: Unentschieden [round, 2]
:[0, 0]

Erik der Outgolfer
quelle
1

Python 3.6+, 137 Bytes

n=m=c=z=0
for a in input():m+=1<<~-int(a);c+=1;z=z or f'{c&1}:{c}'*any(m&t==t for t in[7,56,448,73,146,292,273,84]);n,m=m,n
print(z or-1)

Ausgabeformat ist winner number:roundoder -1für ein Unentschieden. Spieler 2 ist 0Spieler 1 ist 1. Eingabe in Form einer nicht getrennten Zeichenfolge von 1-indizierten quadratischen Zahlen.

mypetlion
quelle
1

Gelee , 35 Bytes

9s3,ZU$$;ŒD$€Ẏf€⁸L€3e
s2ZÇƤ€ZFTḢ;Ḃ$

Ein monadischer Link, der eine Liste der Züge aufnimmt und eine Liste zurückgibt, [move, player]in der die Spieler als 1(Erstes Handeln) und 0(Zweites Handeln) identifiziert werden .

Probieren Sie es online!

Wie?

9s3,ZU$$;ŒD$€Ẏf€⁸L€3e - Link 1: any winning play?: list of player's moves:
9s3                   - (range of) nine split into threes = [[1,2,3],[4,5,6],[7,8,9]]
       $              - last two links as a monad:
      $               -   last two links as a monad:
    Z                 -     transpose = [[1,4,7],[2,5,8],[3,6,9]]
     U                -     upend     = [[7,4,1],[8,5,2],[9,6,3]]
   ,                  -  pair = [[[1,2,3],[4,5,6],[7,8,9]],[[7,4,1],[8,5,2],[9,6,3]]]
           $€         - last two links as a monad for €ach:
         ŒD           -   diagonals = [[1,5,9],[2,6],[3],[7],[4,8]] or [[7,5,3],[4,2],[1],[9],[8,6]]
        ;             -  concatenate = [[1,2,3],[4,5,6],[7,8,9],[1,5,9],[2,6],[3],[7],[4,8]] or [[7,4,1],[8,5,2],[9,6,3],[7,5,3],[4,2],[1],[9],[8,6]]
             Ẏ        - tighten = [[1,2,3],[4,5,6],[7,8,9],[1,5,9],[2,6],[3],[7],[4,8],[7,4,1],[8,5,2],[9,6,3],[7,5,3],[4,2],[1],[9],[8,6]]
                      -    i.e.:    row1    row2    row3    diag\   x     x   x   x     col1    col2    col3    diag/   x     x   x   x
                      -    where x's are not long enough to matter for the rest...
                ⁸     - chain's left argument, list of player's moves
              f€      - filter to keep those moves for €ach of those lists to the left
                 L€   - length of €ach result
                   3e - 3 exists in that? (i.e. were any length 3 when filtered down to only moves made?)

s2ZÇƤ€ZFTḢ;Ḃ$ - Main link: list of the moves  e.g. [2,3,4,5,6,7,1,8,9]
s2            - split into twos                    [[2,3],[4,5],[6,7],[1,8],[9]]
  Z           - transpose                          [[2,4,6,1,9],[3,5,7,8]]
    Ƥ€        - for Ƥrefixes of €ach:
   Ç          -   call last link (1) as a monad     [0,0,0,0,0] [0,0,1,1]
      Z       - transpose                          [[0,0],[0,0],[0,1],[0,1],[0]]
       F      - flatten                            [0,0,0,0,0,1,0,1,0]
        T     - truthy indices                     [          6   8  ]
         Ḣ    - head (if empty yields 0)           6
            $ - last two links as a monad:
           Ḃ  -   modulo by 2 (evens are player 2) 0
          ;   -   concatenate                      [6,0]
Jonathan Allan
quelle
0

Python 2, 168 Bytes

import itertools as z
f=lambda g:next(([i%2+1,i+1]for i in range(9) if any(c for c in z.combinations([[0,6,1,8,7,5,3,2,9,4][j]for j in g[i%2:i+1:2]],3)if sum(c)==15)),0)

Ausgänge (Spieler, Runde) oder 0 für ein Unentschieden.

Ordnet das Spiel einem magischen 3-mal-3-Quadrat zu und sucht nach Sätzen mit 3 Os oder X, die zusammen 15 ergeben.

aPaulT
quelle
0

Sauber , 244 ... 220 Bytes

import StdEnv
f[a,b]i#k= \l=or[and[isMember(c+n)(take i l)\\c<-:"123147159357"%(j,j+2)]\\j<-[0,3..9]&h<-:"\0\0",n<-[h-h,h,h+h]]
|k a=(1,i*2-1)|i>4=(0,0)|k b=(2,i*2)=f[a,b](i+1)
@l=f(map(map((!!)l))[[0,2..8],[1,3..7]])1

Probieren Sie es online!

Die Zeichenfolge, in die iteriert wird, henthält nicht druckbare Elemente und ist äquivalent zu "\003\001\000\000".

Οurous
quelle
0

Python 2 , 140 136 134 Bytes

lambda a,i=0:i<9and(any(set(a[i%2:i+1:2])>=set(map(int,t))for t in'123 456 789 147 258 369 159 357'.split())and(i%2+1,i+1)or f(a,i+1))

Probieren Sie es online!

EDIT: 4 Bytes + 2 Bytes danke an Eric den Outgolfer.

Gibt ein Tupel (playerNumber, roundNumber) oder False aus, wenn es keinen Gewinner gibt.

Chas Brown
quelle
134 Bytes
Erik der Outgolfer
@ Erik - Yah, das hätte ich schon tun sollen; aber ich bekämpfe die grippe und meine augen tun weh :). Danke!
Chas Brown
Nun, gute Besserung. :)
Erik der Outgolfer