Publiez votre code le plus court, par nombre de caractères, pour vérifier si un joueur a gagné, et si oui, lequel.
Supposons que vous ayez un tableau entier dans une variable b
(conseil), qui contient le tableau Tic Tac Toe, et les mouvements des joueurs où:
Donc, étant donné que le tableau b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ]
représenterait le tableau
X|O|X -+-+- |X|O -+-+- X| |O
Pour cette situation, votre code doit afficher 1
pour indiquer que le joueur 1 a gagné. Si personne n’a gagné, vous pouvez afficher 0
ou false
.
Ma propre solution (Ruby) sera bientôt disponible.
Edit : Désolé, j’ai oublié de le marquer comme wiki de la communauté. Vous pouvez supposer que l’entrée est bien formée et qu’il n’est pas nécessaire de vérifier les erreurs.
Mise à jour : Merci de poster votre solution sous la forme d’une fonction. La plupart des gens l’ont déjà fait, mais certains ne l’ont pas fait, ce qui n’est pas tout à fait juste. La carte est fournie à votre fonction comme paramètre. Le résultat doit être renvoyé par la fonction. La fonction peut avoir un nom de votre choix.
Ceci est une variante de la solution de dmckee , sauf que chaque paire de chiffres du Compact Coding est maintenant la base des 9 chiffres des caractères ASCII.
La version 77 -char ne fonctionne pas sur MSVC:
// "J)9\t8\r=,\0" == 82,45,63,10,62,14,67,48,00 in base 9. char*k="J)9 8\r=,",c;f(int*b){return(c=*k++)?b[c/9]&b[c%9]&b[*k--%9]|f(b):0;}
Cette version de 83 -char devrait fonctionner sur tous les compilateurs C:
f(int*b){char*k="J)9 8\r=,",s=0,c;while(c=*k++)s|=b[c%9]&b[c/9]&b[*k%9];return s;}
(Notez que les espaces entre le 9 et le 8 doivent être un onglet. StackOverflow convertit tous les tabs en espaces.)
Cas de test:
#include void check(int* b) { int h0 = b[0]&b[1]&b[2]; int h1 = b[3]&b[4]&b[5]; int h2 = b[6]&b[7]&b[8]; int h3 = b[0]&b[3]&b[6]; int h4 = b[1]&b[4]&b[7]; int h5 = b[2]&b[5]&b[8]; int h6 = b[0]&b[4]&b[8]; int h7 = b[2]&b[4]&b[6]; int res = h0|h1|h2|h3|h4|h5|h6|h7; int value = f(b); if (value != res) printf("Assuming f({%d,%d,%d, %d,%d,%d, %d,%d,%d}) == %d; got %d instead.\n", b[0],b[1],b[2], b[3],b[4],b[5], b[6],b[7],b[8], res, value); } #define MAKEFOR(i) for(b[(i)]=0;b[(i)]<=2;++b[(i)]) int main() { int b[9]; MAKEFOR(0) MAKEFOR(1) MAKEFOR(2) MAKEFOR(3) MAKEFOR(4) MAKEFOR(5) MAKEFOR(6) MAKEFOR(7) MAKEFOR(8) check(b); return 0; }
Solution Crazy Python – 79 caractères
max([b[x] for x in range(9) for y in range(x) for z in range(y) if x+y+z==12 and b[x]==b[y]==b[z]] + [0])
Cependant, cela suppose un ordre différent pour les postes du conseil dans b:
5 | 0 | 7 ---+---+--- 6 | 4 | 2 ---+---+--- 1 | 8 | 3
C’est-à-dire que b[5]
représente le coin supérieur gauche, et ainsi de suite.
Pour minimiser ce qui précède:
r=range max([b[x]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12and b[x]==b[y]==b[z]]+[0])
93 caractères et une nouvelle ligne.
Mise à jour: jusqu’à 79 caractères et une nouvelle ligne à l’aide de l’astuce ET:
r=range max([b[x]&b[y]&b[z]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12])
Ce n’est pas la solution Python la plus courte, mais j’aime la façon dont elle introduit “DICE” dans un jeu de tic-tac-toe:
W=lambda b:max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")])
69 caractères pour l’expression plus simple:
max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")])
Une fonction qui retourne 0, 1 ou 2, en utilisant une expression régulière, bien sûr (la nouvelle ligne est uniquement là pour éviter la barre de défilement):
sub V{$"='';$x='(1|2)';"@_"=~ /^(...)*$x\2\2|^..$x.\3.\3|$x..\4..\4|$x...\5...\5/?$^N:0}
Il peut être appelé comme V(@b)
, par exemple.
w=:3 : '{.>:I.+./"1*./"1]1 2=/y{~2 4 6,0 4 8,i,|:i=.i.3 3'
Je ne suis pas content de me répéter (horizontal / vertical et les diagonales), mais je pense que c’est un bon départ.
C # w / LINQ:
public static int GetVictor(int[] b) { var r = Enumerable.Range(0, 3); return r.Select(i => r.Aggregate(3, (s, j) => s & b[i * 3 + j])).Concat( r.Select(i => r.Aggregate(3, (s, j) => s & b[j * 3 + i]))).Aggregate( r.Aggregate(3, (s, i) => s & b[i * 3 + i]) | r.Aggregate(3, (s, i) => s & b[i * 3 + (2 - i)]), (s, i) => s | i); }
Stratégie: bit à bit AND
chaque élément d’une ligne / colonne / diagonale avec les autres éléments (avec 3 comme graine) pour obtenir un vainqueur pour ce sous-ensemble, et OR
tous ensemble à la fin.
Oups: D’une certaine manière, j’ai mal compté beaucoup. Ce sont en réalité 115 caractères, pas 79.
def t(b)[1,2].find{|p|[448,56,7,292,146,73,273,84].any?{|k|(k^b.inject(0){|m,i|m*2+((i==p)?1:0)})&k==0}}||false end # Usage: b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ] t(b) # => 1 b = [ 1, 1, 0, 2, 2, 2, 0, 2, 1 ] t(b) # => 2 b = [ 0, 0, 1, 2, 2, 0, 0, 1, 1 ] t(b) # => false
Et le code développé, à des fins éducatives:
def tic(board) # all the winning board positions for a player as bitmasks wins = [ 0b111_000_000, # 448 0b000_111_000, # 56 0b000_000_111, # 7 0b100_100_100, # 292 0b010_010_010, # 146 0b001_001_001, # 73 0b100_010_001, # 273 0b001_010_100 ] # 84 [1, 2].find do |player| # find the player who's won # for the winning player, one of the win positions will be true for : wins.any? do |win| # make a bitmask from the current player's moves moves = board.inject(0) { |acc, square| # shift it to the left and add one if this square matches the player number (acc * 2) + ((square == player) ? 1 : 0) } # some logic evaluates to 0 if the moves match the win mask (win ^ moves) & win == 0 end end || false # return false if the find returns nil (no winner) end
Je suis sûr que cela pourrait être raccourci, en particulier le grand tableau et peut-être le code pour obtenir un masque des mouvements des joueurs – ce ternaire m’inspire – mais je pense que c’est assez bon pour le moment.
sub W{$n=$u=0;map{$n++;$u|=$_[$_-$n]&$_[$_]&$_[$_+$n]for/./g}147,4,345,4;$u}
Il y a trois manières de gagner horizontalement:
0,1,2 ==> 1-1, 1, 1+1 3,4,5 ==> 4-1, 4, 4+1 6,7,8 ==> 7-1, 7, 7+1
Une façon de gagner en diagonale de gauche à droite:
2,4,6 ==> 4-2, 4, 4+2
Trois façons de gagner verticalement:
0,3,6 ==> 3-3, 3, 3+3 1,4,7 ==> 4-3, 4, 4+3 2,5,8 ==> 5-3, 5, 5+3
Une façon de gagner en diagonale de gauche à droite:
0,4,8 ==> 4-4, 4, 4+4
Lisez les colonnes du milieu pour obtenir les nombres magiques.
Octave / Matlab, 97 caractères, y compris les espaces et les nouvelles lignes. Affiche 0 si aucun gagnant, 1 si le joueur 1 a gagné, 2 si le joueur 2 a gagné et 2,0801 si les deux joueurs “ont gagné”:
function r=d(b) a=reshape(b,3,3) s=prod([diag(a) diag(fliplr(a)) a a']) r=sum(s(s==1|s==8))^(1/3)
Si nous modifions la spécification et passons b en tant que masortingce 3×3 dès le début, nous pouvons supprimer la ligne de remodelage, en l’atsortingbuant à 80 caractères.
parce que personne ne gagne à tictactoe quand correctement joué je pense que c’est le code le plus court
echo 0;
7 caractères
Mise à jour: Une meilleure entrée pour bash serait ceci:
86 caractères ou 81 excluant la définition de fonction (win ()).
win()for q in 1 28 55 3 12 21 4 20;{ [[ 3*w -eq B[f=q/8]+B[g=q%8]+B[g+gf] ]]&&break;}
Mais, c’est du code du programme tic-tac-toe en bash, donc il ne répond pas tout à fait aux spécifications.
# player is passed in caller's w variable. I use O=0 and X=2 and empty=8 or 9 # if a winner is found, last result is true (and loop halts) else false # since biggest test position is 7 I'll use base 8. could use 9 as well but 10 adds 2 characters to code length # test cases are integers made from first 2 positions of each row # eg. first row (0 1 2) is 0*8+1 = 1 # eg. diagonal (2 4 6) is 2*8+4 = 20 # to convert test cases to board positions use X/8, X%8, and X%8+(X%8-X/8) # for each test case, test that sum of each tuplet is 3*player value
def X(b) u=0 [2,6,7,8,9,13,21,-9].each do|c|u|=b[n=c/5+3]&b[n+c%5]&b[nc%5]end u end
Si l’entrée a les deux joueurs gagnants, par exemple
X | O | X --- + --- + --- X | O | O --- + --- + --- X | O | X
alors la sortie est 3.
77 exclut les importations et en définissant b.
import Data.Bits import Data.Array b = listArray (0,8) [2,1,0,1,1,1,2,2,0] wb = maximum[b!x.&.b!y.&.b!z|x<-[0..8],y<-[x+1..8],z<-[12-xy],z<8,z>=0,z/=y]
Ou 82 en supposant le classement normal:
{-# LANGUAGE NoMonomorphismRessortingction #-} import Data.Bits import Data.Array b = listArray (0,8) [1,2,1,0,1,2,1,0,2] wb = maximum[b!x.&.b!y.&.b!z|x<-[0..8],d<-[1..4],y<-[x+d],z<-[y+d],d/=2||x==2,z<9]
Pas un gagnant, mais peut-être y a-t-il place à l’amélioration. Jamais fait ça avant. Concept original, première ébauche.
#define lw|=*b&b[s]&b[2*s];b+=3/s;s f(int*b){int s=4,w=0;l=3;l;l;l=2;--b;l=1;b-=3;l;l;return l;}
Merci à KennyTM pour quelques idées et le harnais de test.
La “version de développement”:
#define lw|=*b&b[s]&b[2*s];b+=3/s;s // check one possible win f( int *b ) { int s=4,w=0; // s = ssortingde, w = winner l=3; // check ssortingde 4 and set to 3 l;l;l=2; // check ssortingde 3, set to 2 --b;l=1; // check ssortingde 2, set to 1 b-=3;l;l; return l; // check ssortingde 1 }
75 caractères pour une fonction complète
T=lambda a:max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37])
66 caractères si vous omettez la définition de la fonction comme certains l’ont fait
r=max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37])
Les 8 directions différentes sont représentées par la valeur de départ + incrémenteur, compressées en un nombre unique pouvant être extrait en utilisant la division et le modula. Par exemple 2,5,8 = 2 * 6 + 3 = 15.
La vérification qu’une ligne contient trois valeurs égales est effectuée à l’aide de l’opérateur &. (qui donne zéro si elles ne sont pas égales). max est utilisé pour trouver le gagnant possible.
Une solution en C (162 caractères):
Cela utilise le fait que la valeur du joueur 1 (1) et la valeur du lecteur 2 (2) ont des bits indépendants définis. Par conséquent, vous pouvez bit ensemble ET les valeurs des trois zones de test ensemble – si la valeur est différente de zéro, alors les trois valeurs doivent être identiques. En outre, la valeur résultante == le joueur qui a gagné.
Pas la solution la plus courte jusqu’ici, mais le mieux que je puisse faire:
void fn(){ int L[]={1,0,1,3,1,6,3,0,3,1,3,2,4,0,2,2,0}; int s,t,p,j,i=0; while (s=L[i++]){ p=L[i++],t=3; for(j=0;j<3;p+=s,j++)t&=b[p]; if(t)putc(t+'0',stdout);} }
Une version plus lisible:
void fn2(void) { // Lines[] defines the 8 lines that must be tested // The first value is the "Skip Count" for forming the line // The second value is the starting position for the line int Lines[] = { 1,0, 1,3, 1,6, 3,0, 3,1, 3,2, 4,0, 2,2, 0 }; int Skip, Test, Pos, j, i = 0; while (Skip = Lines[i++]) { Pos = Lines[i++]; // get starting position Test = 3; // pre-set to 0x03 (player 1 & 2 values bitwise OR'd together) // search each of the three boxes in this line for (j = 0; j < 3; Pos+= Skip, j++) { // Bitwise AND the square with the previous value // We make use of the fact that player 1 is 0x01 and 2 is 0x02 // Therefore, if any bits are set in the result, it must be all 1's or all 2's Test &= b[Pos]; } // All three squares same (and non-zero)? if (Test) putc(Test+'0',stdout); } }
Python, 102 caractères
Comme vous n’avez pas vraiment spécifié comment obtenir des entrées et des sorties, il s’agit de la version “brute” qu’il faudrait peut-être intégrer dans une fonction. b
est la liste d’entrée; r
est la sortie (0, 1 ou 2).
r=0 for a,c in zip("03601202","11133342"):s=set(b[int(a):9:int(c)][:3]);q=s.pop();r=r if s or r else q
Les 130 caractères correspondent uniquement à la taille de la fonction. La fonction ne retourne rien si aucune correspondance n’est trouvée, ce qui dans Lua est similaire à renvoyer false.
function f(t)z={7,1,4,1,1,3,2,3,3}for b=1,#z-1 do i=z[b]x=t[i]n=z[b+1]if 0
Visual Basic 275 254 (avec des caractères lâchés)
Function W(ByVal b()) Dim r For p = 1 To 2 If b(0) = b(1) = b(2) = p Then r = p If b(3) = b(4) = b(5) = p Then r = p If b(6) = b(7) = b(8) = p Then r = p If b(0) = b(3) = b(6) = p Then r = p If b(1) = b(4) = b(7) = p Then r = p If b(2) = b(5) = b(8) = p Then r = p If b(0) = b(4) = b(8) = p Then r = p If b(6) = b(4) = b(2) = p Then r = p Next Return r End Function
JavaScript – la fonction “w” ci-dessous contient 114 caractères
1+1 i.~,+./"2>>(0 4 8,2 4 6,(],|:)3 3$i.9)&(e.~)&.>&.>(]<@:#"1~[:#:[:i.2^#)&.>(I.@(1&=);I.@(2&=))
J’avais l’intention de poster une explication sur la façon dont cela fonctionne, mais c’était hier et maintenant je ne peux pas lire ce code.
L’idée est de créer une liste de tous les sortingples gagnants possibles (048, 246, 012, 345, 678, 036, 147, 258), puis de faire le jeu de puissance des carrés de chaque joueur, puis de croiser les deux listes. S’il y a un match, c’est le gagnant.
Je suis venu avec 2 expressions, chaque 64chars:
max(a[c/8]&a[c/8+c%8]&a[c/8-c%8]for c in map(ord,'\t\33$#"!+9'))
et
max(a[c/5]&a[c/5+c%5]&a[c/5+c%5*2]for c in[1,3,4,8,12,13,16,31])
Lorsque vous ajoutez “W = lambda b:” pour en faire une fonction, cela fait 75chars. Python le plus court jusqu’ici?
b,p,q,r=["."]*9,"1","2",range while"."in b: w=[b[i*3:i*3+3]for i in r(3)]+[b[i::3]for i in r(3)]+[b[::4],b[2:8:2]] for i in w[:3]:print i if["o"]*3 in w or["x"]*3 in w:exit(q) while 1: m=map(lambda x:x%3-x+x%3+7,r(9)).index(input()) if"."==b[m]:b[m]=".xo"[int(p)];p,q=q,p;break
… Oh, ce n’était pas ce que tu voulais dire quand tu as dit “Code Golf: Tic Tac Toe”? 😉 (entrez les numéros de pavé numérique pour placer les x ou les o, c.-à-d. 7 est le nord-ouest)
board = ["."]*9 # the board currentname = "1" # the current player othername = "2" # the other player numpad_dict = {7:0, 8:1, 9:2, # the lambda function really does this! 4:3, 5:4, 6:5, 1:6, 2:7, 3:8} while "." in board: # Create an array of possible wins: horizontal, vertical, diagonal wins = [board[i*3:i*3+3] for i in range(3)] + \ # horizontal [board[i::3] for i in range(3)] + \ # vertical [board[::4], board[2:8:2]] # diagonal for i in wins[:3]: # wins contains the horizontals first, print i # so we use it to print the current board if ["o"]*3 in wins or ["x"]*3 in wins: # somebody won! exit(othername) # print the name of the winner # (we changed player), and exit while True: # wait for the player to make a valid move position = numpad_dict[input()] if board[position] == ".": # still empty -> change board if currentname == "1": board[position] = "x" else: board[position] = "o" currentname, othername = othername, currentname # swap values
Je suis sûr qu’il y a un moyen plus court de le faire mais … Perl, 141 caractères (134 à l’intérieur de la fonction)
sub t{$r=0;@b=@_;@w=map{[split//]}split/,/,"012,345,678,036,147,258,048,246";for(@w){@z=map{$b[$_]}@$_;$r=$z[0]if!grep{!$_||$_!=$z[0]}@z;}$r;}
Minifié:
#define A(x) a[b[x%16]] int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2};int T(int*a){for(c=0;c<16;c+=2)if(A(c)&A(c+1)&A(c+2))return A(c);return 0;}
Les deux retours comptent (un nécessaire et l'autre nécessitant un espace).
Le tableau code pour les huit façons de gagner dans les sortingplets à partir des positions paires et du mod 16.
Bitwise et astuce volé à Eric Pi .
Forme plus lisible:
#define A(x) a[b[x%16]] // Compact coding of the ways to win. // // Each possible was starts a position N*2 and runs through N*2+2 all // taken mod 16 int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2}; int T(int*a){ // Loop over the ways to win for(c=0;c<16;c+=2) // Test for a win if(A(c)&A(c+1)&A(c+2))return A(c); return 0; }
Échafaudage de test:
#include #include int T(int*); int main(int argc, char**argv){ int input[9]={0}; int i, j; for (i=1; i
Cela pourrait probablement être amélioré, mais je ne me sens pas particulièrement intelligent en ce moment. C’est juste pour s’assurer que Haskell soit représenté …
En supposant que b
existe déjà, cela mettra le résultat en w
.
import List al=2*minimum l-maximum l z=take 3$unfoldr(Just .splitAt 3)b w=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]])
En supposant une entrée depuis stdin et une sortie vers stdout,
import List al=2*minimum l-maximum l wb=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]])where z=take 3$unfoldr(Just .splitAt 3)b main=interact$show.w.read
var s=new[]{0,0,0,1,2,2,3,6}; var t=new[]{1,3,4,3,2,3,1,1}; return(s.Select((p,i)=>new[]{g[p],g[p+t[i]],g[p+2*t[i]]}).FirstOrDefault(l=>l.Distinct().Count()==1)??new[]{0}).First();
( g
étant la grid)
Pourrait probablement être amélioré … J’y travaille encore;)
Mon premier code de golf, pesant un lourd 140 caractères (déclaration d’importation, je vous nie!):
import operator as o def c(t):return({1:1,8:2}.get(reduce(o.mul,t[:3]),0)) def g(t):return max([c(t[x::y]) for x,y in zip((0,0,0,1,2,2,3,6),(1,3,4,3,3,2,1,1))])
Légèrement moins obscure:
def g(t):return max([c(t[x::y]) for x,y in [[0,1],[0,3],[0,4],[1,3],[2,3],[2,2],[3,1],[6,1]]])
C # Solution.
Multipliez les valeurs dans chaque ligne, col et diagonale. Si résultat == 1, X gagne. Si résultat == 8, O gagne.
int v(int[] b) { var i = new[] { new[]{0,1,2}, new[]{3,4,5}, new[]{6,7,8}, new[]{0,3,6}, new[]{1,4,7}, new[]{2,5,8}, new[]{0,4,8}, new[]{2,4,6} }; foreach(var a in i) { var n = b[a[0]] * b[a[1]] * b[a[2]]; if(n==1) return 1; if(n==8) return 2; } return 0; }
Emprunter quelques techniques à partir d’autres soumissions. (Je ne savais pas que C # vous permettait de lancer des tableaux comme ça)
static int V(int[] b) { int[] a={0,1,3,1,6,1,0,3,1,3,2,3,0,4,2,2}; int r=0,i=-2; while((i+=2)<16&&(r|=b[a[i]]&b[a[i]+a[i+1]]&b[a[i]+a[i+1]*2])==0){} return r; }
f(int*b){char*s="012345678036147258048264\0";int r=0;while(!r&&*s){int q=r=3;while(q--)r&=b[*s++-'0'];}return r;}
Je pense que ça marche? Mon premier code de golf, soyez gentil.
Chaque 3 chiffres encode 3 cellules qui doivent correspondre. L’intérieur vérifie une sortingade. L’extérieur vérifie tous les 8.