Tic-tac-toe con solo croci


32

introduzione

Tutti conoscono il gioco tic-tac-toe, ma in questa sfida introdurremo una piccola svolta. Useremo solo croci . La prima persona che piazza tre croci di fila perde. Un fatto interessante è che la quantità massima di croci prima che qualcuno perda, è pari a 6 :

X X -
X - X
- X X

Ciò significa che per una scheda 3 x 3, l'importo massimo è 6 . Quindi per N = 3, dobbiamo produrre 6.

Un altro esempio, per N = 4, o una scheda 4 x 4:

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

Questa è una soluzione ottimale, puoi vedere che la quantità massima di croci è pari a 9 . Una soluzione ottimale per una scheda 12 x 12 è:

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

Ciò si traduce in 74 .

L'obiettivo

L'attività è semplice, dato un numero intero maggiore di 0, genera la massima quantità di croci che possono essere posizionate senza tre X adiacenti in una linea lungo una riga, colonna o in diagonale.

Casi test

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

Ulteriori informazioni sono disponibili all'indirizzo https://oeis.org/A181018 .

Regole

  • Questo è , quindi vince l'invio con il minor numero di byte!
  • È possibile fornire una funzione o un programma.

7
Quindi la domanda si riduce all'utilizzo delle formule nella pagina che hai collegato ...
nicael,


7
@nicael Per quanto posso vedere, l'articolo sull'OEIS contiene solo limiti inferiori.
Martin Ender,

6
Sarebbe bello vederlo come una sfida di codice più veloce.
Luca,

4
Non è una soluzione codegolf, ma ho giocato con un risolutore "visivo" negli ultimi giorni. Puoi accedere a jsfiddle qui: jsfiddle.net/V92Gn/3899 Tenta di trovare soluzioni tramite mutazioni casuali. Non si fermerà se trova la risposta "corretta", ma può arrivare a molte delle soluzioni corrette molto più rapidamente di quelle seguenti.
Styletron,

Risposte:


11

Pyth, 57 51 49 byte

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

Come la soluzione CJam di @ PeterTaylor, questa è forza bruta, quindi funziona in tempo O (n 2 2 n 2 ). L'interprete online non termina entro un minuto per n = 4.

Provalo qui per N <4.

Prova la funzione diagonali .

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

13

CJam ( 58 56 byte)

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

Questo è incredibilmente lento e utilizza molta memoria, ma questo è per te.

Dissezione

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

Θ(un'X)un'1.83928675...Θ(un'X2)Θ(un'X4)


O(Xun'3X)

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;
    }
}

In che cosa consiste l'approccio efficiente?
lirtosiast,

@ThomasKwa, oh, è ancora esponenziale, ma penso che sia giustificato definirlo efficiente perché mi ha permesso di estendere la sequenza OEIS di 3 termini.
Peter Taylor,

@ThomasKwa, per la precisione, è O(n a^n)dove a ~= 5.518.
Peter Taylor,

4

C, 460 456 410 407 362 351 318 byte

Questa è una risposta davvero negativa. È un approccio alla forza bruta incredibilmente lento.Sto cercando di giocare a golf un po 'di più combinando i forcircuiti.

#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));}

Casi 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 */
}

Modifica: dichiara le variabili int come parametri inutilizzati; rimuovere le coordinate y, basta usare l'indice; sposta la variabile nella lista parametri anziché globale, correggi i parametri non necessari passati s(); combinare per gli anelli, rimuovere le parentesi non necessarie; sostituire &&con *, ||con +; macro-ify il controllo 3 in una riga


Quanto è lento?
Loovjo,

@Loovjo ha provato sul mio PC con alcune piccole modifiche per renderlo più veloce, 15 ms per n = 5, 12 sec per n = 6 (input +1, tempo * 800)!
edc65,

@ edc65 Questa è stata la mia esperienza. Qualunque cosa superiore a 5 la performance è stata notevolmente più lenta. Non mi sono preoccupato di provare input superiori a 6.
Cole Cameron

Ho iniziato con 7 quando ho pubblicato il mio commento. Vedremo
edc65

Puoi spremere qualche altro carattere con #define d(x,y)b[x]*b[x+y]*b[x+y+y]; cambiando l'inizio di sa s(i,m){for(m=n-2;e sostituendo tutte le istanze di n-2; e cambiando b[x]++in b[x++]++e quindi sostituendo x==n*n-1con x==n*n, x+1con xe xcon x-1.
Peter Taylor,

4

C 263 264 283 309

Modifica Alcuni byte salvati grazie a Peter Taylor - meno di quanto sperassi. Quindi 2 byte utilizzati per allocare un po 'più di memoria, ora posso provare dimensioni più grandi, ma sta diventando molto tempo.

Nota Durante l'aggiunta della spiegazione, ho scoperto che sto sprecando byte mantenendo la griglia nell'array R - in modo da poter vedere la soluzione trovata ... non è richiesta per questa sfida !!
L'ho rimosso nella versione golf

Un programma C golf che può effettivamente trovare la risposta per n = 1..10 in tempi ragionevoli.

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

Il mio test:

7 -> 26 in 10 sec
8 -> 36 in 18 sec
9 -> 42 in 1162 sec

Meno golfista e cercando di spiegare

#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);
}

Questo è essenzialmente lo stesso del mio programma Java, ma approfondisce prima di tutto. Penso che dovresti essere in grado di salvare almeno una dozzina di caratteri eseguendo il porting del mio buildRowsmetodo; forse fino a 20 se for(scanf("%d",&n);(v=2*V[i++])<1<<n;v%8<6&&V[++j]=v+1)v&&V[++j]=v;è valido. (Non ho accesso a un compilatore C in questo momento).
Peter Taylor,

1
@PeterTaylor darò un'occhiata ... solo la parola tribonacci mi sta spaventando
edc65

Il tuo hard code 999significa che vorresti ignorare quella parte. Anche se forse dovresti davvero renderlo non codificato, quindi in linea di principio puoi affrontare input più grandi di 11 o 12.
Peter Taylor,

@PeterTaylor funzionerebbe benissimo se avessi un metodo .bitCount in C per contare i bit. Ma in quella fase iniziale mi occupo del conteggio dei bit in B, non solo delle maschere di bit in V
edc65

2

Rubino, 263 byte

Questa è anche una soluzione di forza bruta e affronta gli stessi problemi della risposta C di Cole Cameron, ma è ancora più lenta poiché si tratta di un rubino e non di C. Ma, ehi, è più breve.

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

Casi 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)

1

Haskell, 143 byte

In un certo senso questo non è fatto, ma mi sono divertito così ecco qui:

  • Poiché il controllo del modello orizzontale "vincente" non è valido se applicato su righe diverse, l'input di N <3 restituisce 0
  • Gli "array" sono numeri interi decompressi in bit, quindi facilmente enumerabili
  • ((i! x) y) fornisce l'ith bit di x volte y, dove gli indici negativi restituiscono 0 in modo che l'intervallo possa essere costante (nessun controllo dei limiti) e meno parentesi quando incatenato
  • Poiché i limiti non sono controllati, controlla 81 * 4 = 324 modelli per ogni massimo possibile, portando a N = 3 che impiega il mio laptop 9 secondi e N = 5 che impiega troppo tempo a lasciarlo finire
  • La logica booleana su 1/0 viene utilizzata per T / F per risparmiare spazio, ad esempio (*) è &&, (1-x) è (non x), ecc.
  • Poiché controlla numeri interi anziché matrici, (div p1 L) == (div p2 L) è necessario per assicurarsi che un modello non sia controllato su righe diverse, dove L è la lunghezza della riga e p1, p2 sono posizioni
  • Il valore di un possibile massimo è il suo peso di Hamming

Ecco il codice:

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