Tic-tac-toe avec seulement des croix

32

introduction

Tout le monde connaît le jeu tic-tac-toe, mais dans ce défi, nous allons introduire un petit twist. Nous n'utiliserons que des croix . La première personne qui place trois croix d'affilée perd. Un fait intéressant est que le nombre maximum de croix avant que quelqu'un ne perde, est égal à 6 :

X X -
X - X
- X X

Cela signifie que pour une carte 3 x 3, le montant maximum est de 6 . Donc, pour N = 3, nous devons produire 6.

Un autre exemple, pour N = 4, ou une carte 4 x 4:

X X - X
X X - X
- - - -
X X - X

C'est une solution optimale, vous pouvez voir que le nombre maximum de croix est égal à 9 . Une solution optimale pour une carte 12 x 12 est:

X - X - X - X X - X X -
X X - X X - - - X X - X
- X - X - X X - - - X X
X - - - X X - X X - X -
- X X - - - X - - - - X
X X - X X - X - X X - -
- - X X - X - X X - X X
X - - - - X - - - X X -
- X - X X - X X - - - X
X X - - - X X - X - X -
X - X X - - - X X - X X
- X X - X X - X - X - X

Il en résulte 74 .

La tâche

La tâche est simple, étant donné un entier supérieur à 0, affichez le nombre maximum de croix qui peuvent être placées sans trois X adjacents sur une ligne le long d'une ligne, d'une colonne ou en diagonale.

Cas de test

N     Output
1     1
2     4
3     6
4     9
5     16
6     20
7     26
8     36
9     42

Plus d'informations peuvent être trouvées sur https://oeis.org/A181018 .

Règles

  • C'est du , donc la soumission avec le moins d'octets gagne!
  • Vous pouvez fournir une fonction ou un programme.
Adnan
la source
7
Donc, la question se résume à utiliser les formules dans la page que vous avez liée ...
nicael
2
Article connexe sur Math.
AdmBorkBork
7
@nicael Pour autant que je sache, l'article OEIS ne contient que des limites inférieures.
Martin Ender
6
Ce serait cool de voir cela comme un défi de code le plus rapide.
Luke
4
Pas une solution de codegolf, mais j'ai joué avec un solveur "visuel" ces derniers jours. Vous pouvez accéder au jsfiddle ici: jsfiddle.net/V92Gn/3899 Il essaie de trouver des solutions via des mutations aléatoires. Elle ne s'arrêtera pas si elle trouve la réponse «correcte», mais elle peut obtenir beaucoup de solutions correctes beaucoup plus rapidement que ces réponses ci-dessous.
styletron

Réponses:

11

Pyth, 57 51 49 octets

L.T.e+*]Ykbbsef!s.AMs.:R3ssmyBdsm_BdCBcTQsD^U2^Q2

Comme la solution CJam de @ PeterTaylor, il s'agit d'une force brute, donc elle s'exécute en temps O (n 2 2 n 2 ). L'interprète en ligne ne termine pas dans une minute pour n = 4.

Essayez-le ici pour N <4.

Essayez la fonction diagonales .

L.T.e+*]Ykbb         y(b): diagonals of b (with some trailing [])
s e                  sum of the last (with most ones) array such that
f                    filter lambda T:
 ! s .AM                none of the 3 element sublists are all ones               
   s .:R3               all 3 element sublists
   s s                  flatten
   myBd                 add the diagonals
   sm_B d               add the vertically flipped array and transpose
   CBcTQ                array shaped into Q by Q square, and its transpose
 sD ^U2 ^Q2             all binary arrays of length Q^2 sorted by sum
lirtosiast
la source
13

CJam ( 58 56 octets)

2q~:Xm*{7Yb#W=}:F,Xm*{ee{~0a@*\+}%zS*F},_Wf%:z&Mf*1fb:e>

C'est incroyablement lent et utilise beaucoup de mémoire, mais c'est du pour vous.

Dissection

2q~:Xm*        e# Read input into X and find Cartesian product {0,1}^X
{7Yb#W=}:F,    e# Filter with a predicate F which rejects arrays with a 111
Xm*            e# Take the Cartesian product possible_rows^X to get possible grids
{              e# Filter out grids with an anti-diagonal 111 by...
  ee{~0a@*\+}% e#   prepending [0]*i to the ith row
  zS*F         e#   transposing, joining on a non-1, and applying F
},
_Wf%:z         e# Copy the filtered arrays and map a 90 degree rotation
&              e# Intersect. The rotation maps horizontal to vertical and
               e# anti-diagonal to diagonal, so this gets down to valid grids
Mf*            e# Flatten each grid
1fb            e# Count its 1s
:e>            e# Select the maximum

Θ(uneX)une1.83928675Θ(uneX2)Θ(uneX4)


O(Xune3X)

public class A181018 {
    public static void main(String[] args) {
        for (int i = 1; i < 14; i++) {
            System.out.format("%d:\t%d\n", i, calc(i));
        }
    }

    private static int calc(int n) {
        if (n < 0) throw new IllegalArgumentException("n");
        if (n < 3) return n * n;

        // Dynamic programming approach: given two rows, we can enumerate the possible third row.
        // sc[i + rows.length * j] is the greatest score achievable with a board ending in rows[i], rows[j].
        int[] rows = buildRows(n);
        byte[] sc = new byte[rows.length * rows.length];
        for (int j = 0, k = 0; j < rows.length; j++) {
            int qsc = Integer.bitCount(rows[j]);
            for (int i = 0; i < rows.length; i++) sc[k++] = (byte)(qsc + Integer.bitCount(rows[i]));
        }

        int max = 0;
        for (int h = 2; h < n; h++) {
            byte[] nsc = new byte[rows.length * rows.length];
            for (int i = 0; i < rows.length; i++) {
                int p = rows[i];
                for (int j = 0; j < rows.length; j++) {
                    int q = rows[j];
                    // The rows which follow p,q cannot intersect with a certain mask.
                    int mask = (p & q) | ((p << 2) & (q << 1)) | ((p >> 2) & (q >> 1));
                    for (int k = 0; k < rows.length; k++) {
                        int r = rows[k];
                        if ((r & mask) != 0) continue;

                        int pqrsc = (sc[i + rows.length * j] & 0xff) + Integer.bitCount(r);
                        int off = j + rows.length * k;
                        if (pqrsc > nsc[off]) nsc[off] = (byte)pqrsc;
                        if (pqrsc > max) max = pqrsc;
                    }
                }
            }

            sc = nsc;
        }

        return max;
    }

    private static int[] buildRows(int n) {
        // Array length is a tribonacci number.
        int c = 1;
        for (int a = 0, b = 1, i = 0; i < n; i++) c = a + (a = b) + (b = c);

        int[] rows = new int[c];
        int i = 0, j = 1, val;
        while ((val = rows[i]) < (1 << (n - 1))) {
            if (val > 0) rows[j++] = val * 2;
            if ((val & 3) != 3) rows[j++] = val * 2 + 1;
            i++;
        }

        return rows;
    }
}
Peter Taylor
la source
En quoi consiste l'approche efficace?
lirtosiast
@ThomasKwa, oh, c'est toujours exponentiel, mais je pense qu'il est justifié de l'appeler efficace car cela m'a permis d'étendre la séquence OEIS de 3 termes.
Peter Taylor
@ThomasKwa, pour être précis, c'est O(n a^n)a ~= 5.518.
Peter Taylor
4

C 460 456 410 407 362 351 318 octets

C'est une très mauvaise réponse. C'est incroyablement approche de force brute lente.J'essaie de jouer un peu plus au golf en combinant les forboucles.

#define r return
#define d(x,y)b[x]*b[x+y]*b[x+2*(y)]
n,*b;s(i){for(;i<n*(n-2);++i)if(d(i%(n-2)+i/(n-2)*n,1)+d(i,n)+(i%n<n-2&&d(i,n+1)+d(i+2,n-1)))r 1;r 0;}t(x,c,l,f){if(s(0))r 0;b[x]++;if(x==n*n-1)r c+!s(0);l=t(x+1,c+1);b[x]--;f=t(x+1,c);r l>f?l:f;}main(c,v)char**v;{n=atol(v[1]);b=calloc(n*n,4);printf("%d",t(0,0));}

Cas de test

$ ./a.out 1
1$ ./a.out 2
4$ ./a.out 3
6$ ./a.out 4
9$ ./a.out 5
16$

Ungolfed

n,*b; /* board size, board */

s(i) /* Is the board solved? */
{
    for(;i<n*(n-2);++i) /* Iterate through the board */
            if(b[i%(n-2)+i/(n-2)*n]&&b[i%(n-2)+i/(n-2)*n+1]&&b[i%(n-2)+i/(n-2)*n+2] /* Check for horizontal tic-tac-toe */
                    || b[i] && b[i+n] && b[i+2*n] /* Check for vertical tic-tac-toe */
                    || (i%n<n-2
                            && (b[i] &&b [i+n+1] && b[i+2*n+2] /* Check for diagonal tic-tac-toe */
                                    || b[i+2*n] && b[i+n+1] && b[i+2]))) /* Check for reverse diagonal tic-tac-toe */
                    return 1;
    return 0;
}

t(x,c,l,f) /* Try a move at the given index */
{
    if(s(0)) /* If board is solved, this is not a viable path */
            return 0;
    b[x]++;
    if(x==n*n-1) /* If we've reached the last square, return the count */
            return c+!s(0);

    /* Try it with the cross */
    l=t(x+1,c+1);

    /* And try it without */
    b[x]--;
    f=t(x+1,c);

    /* Return the better result of the two */
    return l>f?l:f;
}

main(c,v)
char**v;
{
    n=atol(v[1]); /* Get the board size */
    b=calloc(n*n,4); /* Allocate a board */
    printf("%d",t(0,0)); /* Print the result */
}

Edit: Déclarez les variables int comme paramètres inutilisés; supprimer la coordonnée y, utilisez simplement l'index; déplacer la variable vers la liste des paramètres plutôt que global, corriger les paramètres inutiles passés à s(); combiner pour les boucles, supprimer les parenthèses inutiles; remplacer &&par *, ||par +; macro-ify la vérification 3 en ligne

Cole Cameron
la source
Est-ce lent?
Loovjo
@Loovjo a essayé sur mon PC avec quelques petites modifications pour le rendre plus rapide, 15 ms pour n = 5, 12 sec pour n = 6 (entrée +1, temps * 800)!
edc65
@ edc65 Ce fut mon expérience. Tout ce qui était supérieur à 5, les performances étaient considérablement plus lentes. Je n'ai pas pris la peine d'essayer des entrées supérieures à 6.
Cole Cameron
J'ai commencé avec 7 lorsque j'ai posté mon commentaire. Nous verrons
edc65
Vous pouvez extraire quelques autres caractères avec #define d(x,y)b[x]*b[x+y]*b[x+y+y]; en changeant le début de sla s(i,m){for(m=n-2;et de remplacer toutes les instances de n-2; et en changeant b[x]++à b[x++]++et en remplaçant x==n*n-1avec x==n*n, x+1avec xet xavec x-1.
Peter Taylor
4

C 263 264 283 309

Modifier Quelques octets ont sauvé thx @Peter Taylor - moins que ce que j'espérais. Ensuite, 2 octets étaient utilisés pour allouer un peu plus de mémoire, maintenant je peux essayer une plus grande taille, mais cela prend beaucoup de temps.

Remarque En ajoutant l'explication, j'ai découvert que je gaspille des octets en gardant la grille dans le tableau R - pour que vous puissiez voir la solution trouvée ... ce n'est pas demandé pour ce défi !!
Je l'ai supprimé dans la version golf

Un programme de golf C qui peut réellement trouver la réponse pour n = 1..10 dans un délai raisonnable.

s,k,n,V[9999],B[9999],i,b;K(l,w,u,t,i){for(t=u&t|u*2&t*4|u/2&t/4,--l; i--;)V[i]&t||(b=B[i]+w,l?b+(n+2)/3*2*l>s&&K(l,b,V[i],u,k):b>s?s=b:0);}main(v){for(scanf("%d",&n);(v=V[i]*2)<1<<n;v%8<6?B[V[k]=v+1,k++]=b+1:0)V[k]=v,b=B[k++]=B[i++];K(n,0,0,0,k);printf("%d",s);}

Mon test:

7 -> 26 en 10 s
8 -> 36 en 18 s
9 -> 42 en 1162 s

Moins de golf et essayant d'expliquer

#include <stdio.h>

int n, // the grid size
    s, // the result
    k, // the number of valid rows 
    V[9999], // the list of valid rows (0..to k-1) as bitmasks
    B[9999], // the list of 'weight' for each valid rows (number of set bits)
    R[99],  // the grid as an array of indices pointing to bitmask in V
    b,i; // int globals set to 0, to avoid int declaration inside functions

// recursive function to fill the grid
int K(
  int l, // number of rows filled so far == index of row to add
  int w, // number of crosses so far
  int u, // bit mask of the preceding line (V[r[l-1]])
  int t, // bit mask of the preceding preceding line (V[r[l-2]])
  int i) // the loop variables, init to k at each call, will go down to 0
{
  // build a bit mask to check the next line 
  // with the limit of 3 crosses we need to check the 2 preceding rows
  t = u&t | u*2 & t*4 | u/2 & t/4; 
  for (; i--; )// loop on the k possibile values in V
  {
    R[l] = i; // store current row in R
    b = B[i] + w; // new number of crosses if this row is accepted
    if ((V[i] & t) == 0) // check if there are not 3 adjacent crosses
      // then check if the score that we can reach from this point
      // adding the missing rows can eventually be greater
      // than the current max score stored in s
      if (b + (n + 2) / 3 * 2 * (n - l - 1) > s)
        if (l > n-2) // if at last row
          s = b > s ? b : s; // update the max score
        else  // not the last row
          K(l + 1, b, V[i], u, k); // recursive call, try to add another row
  }
}

int main(int j)
{
  scanf("%d", &n);

  // find all valid rows - not having more than 2 adjacent crosses
  // put valid rows in array V
  // for each valid row found, store the cross number in array B
  // the number of valid rows will be in k
  for (; i<1 << n; V[k] = i++, k += !b) // i is global and start at 0
    for (b = B[k] = 0, j = i; j; j /= 2) 
      b = ~(j | -8) ? b : 1, B[k] += j & 1;
  K(0,0,0,0,k); // call recursive function to find the max score
  printf("%d\n", s);
}
edc65
la source
C'est essentiellement le même que mon programme Java mais en profondeur d'abord plutôt qu'en largeur. Je pense que vous devriez pouvoir enregistrer au moins une douzaine de caractères en portant ma buildRowsméthode; peut-être jusqu'à 20 si for(scanf("%d",&n);(v=2*V[i++])<1<<n;v%8<6&&V[++j]=v+1)v&&V[++j]=v;est valide. (Je n'ai pas accès à un compilateur C pour le moment).
Peter Taylor
1
@PeterTaylor je vais lui donner un coup d'oeil ... juste le mot tribonacci me fait peur
edc65
Votre code dur 999signifie que vous voudriez ignorer cette partie. Bien que vous deviez peut-être vraiment ne pas le coder en dur, de sorte qu'en principe, vous pouvez attaquer des entrées plus grandes que 11 ou 12.
Peter Taylor
@PeterTaylor cela fonctionnerait très bien si j'avais une méthode .bitCount en C pour compter les bits. Mais dans cette phase initiale, je compute le nombre de bits en B, pas seulement les masques de bits en V
edc65
2

Rubis, 263 octets

C'est également une solution de force brute et fait face aux mêmes problèmes que la réponse C de Cole Cameron, mais est encore plus lente car c'est du rubis et non du C. Mais bon, c'est plus court.

c=->(b){b.transpose.all?{|a|/111/!~a*''}}
m=->(b,j=0){b[j/N][j%N]=1
x,*o=b.map.with_index,0
c[b]&&c[b.transpose]&&c[x.map{|a,i|o*(N-i)+a+o*i}]&&c[x.map{|a,i|o*i+a+o*(N-i)}]?(((j+1)...N*N).map{|i|m[b.map(&:dup),i]}.max||0)+1:0}
N=$*[0].to_i
p m[N.times.map{[0]*N}]

Cas de test

$ ruby A181018.rb 1
1
$ ruby A181018.rb 2
4
$ ruby A181018.rb 3
6
$ ruby A181018.rb 4
9
$ ruby A181018.rb 5
16

Ungolfed

def check_columns(board)
  board.transpose.all? do |column|
    !column.join('').match(/111/)
  end
end

def check_if_unsolved(board)
  check_columns(board) && # check columns
    check_columns(board.transpose) && # check rows
    check_columns(board.map.with_index.map { |row, i| [0] * (N - i) + row + [0] * i }) && # check decending diagonals
    check_columns(board.map.with_index.map { |row, i| [0] * i + row + [0] * (N - i) }) # check ascending diagonals
end

def maximum_crosses_to_place(board, index=0)
  board[index / N][index % N] = 1 # set cross at index
  if check_if_unsolved(board)
    crosses = ((index + 1)...(N*N)).map do |i|
      maximum_crosses_to_place(board.map(&:dup), i)
    end
    maximum_crosses = crosses.max || 0
    maximum_crosses + 1
  else
    0
  end
end

N = ARGV[0].to_i
matrix_of_zeros = N.times.map{ [0]*N }

puts maximum_crosses_to_place(matrix_of_zeros)
Siim Liiser
la source
1

Haskell, 143 octets

À certains égards, cela ne se fait pas, mais je me suis amusé alors voici:

  • Étant donné que la vérification du motif horizontal "gagnant" n'est pas valide s'il est appliqué sur différentes lignes, la saisie de N <3 renvoie 0
  • Les "tableaux" sont des entiers décompressés en bits, si facilement énumérables
  • ((i! x) y) donne le ième bit de x fois y, où les indices négatifs renvoient 0 pour que la plage puisse être constante (pas de vérification des limites) et moins de parenthèses lorsqu'elle est enchaînée
  • Parce que les limites ne sont pas vérifiées, il vérifie 81 * 4 = 324 modèles pour chaque maximum possible, conduisant à N = 3 à prendre mon ordinateur portable 9 secondes et N = 5 à prendre trop de temps pour que je le laisse finir
  • La logique booléenne sur 1/0 est utilisée pour T / F pour économiser de l'espace, par exemple (*) est &&, (1-x) est (pas x), etc.
  • Parce qu'il vérifie les entiers au lieu des tableaux, (div p1 L) == (div p2 L) est nécessaire pour s'assurer qu'un modèle n'est pas vérifié sur différentes lignes, où L est la longueur de la ligne et p1, p2 sont les positions
  • La valeur d'un maximum possible est son poids de Hamming

Voici le code:

r=[0..81]
(%)=div
s=sum
i!x|i<0=(*0)|0<1=(*mod(x%(2^i))2)
f l=maximum[s[i!x$1-s[s[1#2,l#(l+l),(l+1)#(l+l+2),(1-l)#(2-l-l)]|p<-r,let  a#b=p!x$(p+a)!x$(p+b)!x$s[1|p%l==(p+mod b l)%l]]|i<-r]|x<-[0..2^l^2]]
Michael Klein
la source