Tic-tac-toe with only crosses
CJam (58 56 bytes)
2q~:Xm*{7Yb#W=}:F,Xm*{ee{~0a@*\+}%zS*F},_Wf%:z&Mf*1fb:e>
This is incredibly slow and uses a lot of memory, but that's code-golf for you.
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
The number of valid rows is a tribonacci number and is \$\Theta(a^X)\$ where \$a\$ is the tribonacci constant, \$1.83928675\ldots\$. The number of grids generated in the Cartesian product is \$\Theta(a^{X^2})\$; the second filter will reduce the number somewhat, but the intersection is still probably \$\Theta(a^{X^4})\$.
An "efficient" approach ("merely" \$O(X a^{3X})\$) uses dynamic programming. Ungolfed in Java:
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;
}
}
Pyth, 57 51 49 bytes
L.T.e+*]Ykbbsef!s.AMs.:R3ssmyBdsm_BdCBcTQsD^U2^Q2
Like @PeterTaylor's CJam solution, this is brute-force, so it runs in O(n22n2) time. The online interpreter doesn't finish within a minute for n=4.
Try it here for N<4.
Try the diagonals function.
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
C, 460 456 410 407 362 351 318 bytes
This is a really bad answer. It's an incredibly slow brute force approach. I'm trying to golf it a bit more by combining the for
loops.
#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));}
Test Cases
$ ./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: Declare int variables as unused parameters; remove y coordinate, just use index; move variable to parameter list rather than global, fix unnecessary parameters passed to s()
; combine for loops, remove unnecessary parentheses; replace &&
with *
, ||
with +
; macro-ify the 3-in-a-row check