| Bytes | Lang | Time | Link |
|---|---|---|---|
| 057 | Charcoal | 250205T213811Z | Neil |
| 037 | Jelly | 250204T194000Z | Jonathan |
| 043 | 05AB1E | 250205T101533Z | Kevin Cr |
| 202 | Maple | 250205T023141Z | dharr |
| 141 | JavaScript V8 | 250204T131020Z | l4m2 |
| 144 | JavaScript V8 | 250204T080530Z | Arnauld |
| 099 | Retina 0.8.2 | 250204T100047Z | Neil |
Charcoal, 57 bytes
≔FOXθΦEX⁹¦⁸⭆¹⁶§θ÷ιX³λ›⬤θ‹№ιλ⁻⁷↔⊖μ⊙145№E¹⁶⭆³§ι⁺ν×⁻Iλ&⊗λνπθ
Don't Try it online! - far too slow. Instead, Attempt This Online! output the first few rows (and also tweaked for speed at a cost another byte so that it will complete in under a minute). Outputs a list of flattened grids. Explanation:
≔FOXθ
Save the string FOX as it gets used thrice.
ΦEX⁹¦⁸⭆¹⁶§θ÷ιX³λ
Filter on all 43046721 flattened grids of F, O and X that...
›⬤θ‹№ιλ⁻⁷↔⊖μ
... contain fewer than 6 Fs and Xs and 7 Os, but...
⊙145№E¹⁶⭆³§ι⁺ν×⁻Iλ&⊗λνπθ
... do not contain the word FOX.
Given any flattened board, there are always three three-letter words that can be formed starting at any letter on the board; from its (0-indexed) index l, you can step horizontally by 1-(l&2), vertically by 4-(l&8), and diagonally by 5-(l&10).
Jelly, 37 bytes
“OFX”ṁ⁴Œ!Qµs4ZU,ƊŒD;$Ẏṡ€3ẎUƬẎQṢ$ƑƇµÐḟ
A niladic Link that yields a list of lists of characters.
Don't Try it online! (way too inefficient.)
...a three by three using three of each letter takes ~30s.
How?
“OFX”ṁ⁴Œ!Qµ...µÐḟ - Link: no arguments
“OFX” - literal "OFX"
ṁ⁴ - mould like 16 -> "OFXOFXOFXOFXOFXO"
Œ! - all permutations
Q - deduplicate -> Potentials = distinct boards as lists of characters
µ...µÐḟ - discard those of {Potentials} for which...
s4ZU,ƊŒD;$Ẏṡ€3ẎUƬẎQṢ$ƑƇ - (...) - f(Potential):
s4 - split {Potential} into chunks of length four
ZU,Ɗ - rotate {that} a quarter and pair with {that}
ŒD;$ - concatenate {that} to its diagonals (i.e. the diagonals *and* anti-diagonals)
Ẏ - tighten {that}
ṡ€3 - all sublists of length three of each of {those}
Ẏ - tighten {that}
UƬ - collect up reversing each of {those} while distinct
Ẏ - tighten {that}
$ƑƇ - keep those which are invariant under:
Q - deduplicate {it}
Ṣ - sort {that}
05AB1E, 43 bytes
…OFX16∍œÙʒlS4ô2Fø€ü3}€`D€ø«D€í«D€Å\«J»'¨›å≠
Brute-force approach. Outputs as a list of flattened strings.
(Don't) try it online (way too slow).
Try it online with 3x3 instead. (16∍ and 4ô are changed to 9∍ and 3ô respectively.)
Explanation:
Unfortunately, 05AB1E lacks a builtin to get all diagonals/anti-diagonals of a matrix, except for the main diagonal, so some bytes are lost creating overlapping 3x3 blocks first.
…OFX # Push string "OFX"
16∍ # Extend it to length 16: "OFXOFXOFXOFXOFXO"
œ # Get all permutations of this string
Ù # Uniquify that list of permutations
ʒ # Filter this list of permutations by:
l # Convert it to lowercase
S # Convert it to a list of characters
4ô # Split it into 4 parts, to a 4x4 matrix
2Fø€ü3} # Create overlapping 3x3 blocks:
2F } # Loop two times:
ø # Zip/transpose; swapping rows/columns
€ # Map over each inner list:
ü3 # Create overlapping triplets
€` # Flatten this nested list of 3x3 blocks one level down
D # Duplicate it
€ø # Zip/transpose each inner 3x3 block
« # Merge the two lists of 3x3 blocks together
D # Duplicate that again
€ # Map over each inner 3x3 block:
í # Reverse each inner row
« # Merge the two lists of 3x3 blocks together again
# (we now have all four rotations of each 3x3 block)
D # Duplicate that yet again
ہ\ # Get each main diagonal of this copy
« # Merge it to the list of 3x3 blocks as well
# (no need for additional anti-diagonals, since we have four rotations)
J # Join each inner-most rows together to a string
» # Join each inner list of three rows by spaces;
# and then all those block-strings by newlines
'¨› '# Push dictionary string "fox"
å # Check if the string contains "fox"
≠ # Invert this check, to exclude those in the filter
# (after which the list of valid permutations are output implicitly)
See this 05AB1E tip of mine (section How to use the dictionary?) to understand why '¨› is "fox".
Maple, 202 bytes
a:=1,3,9,11;b:=0,1,4,5;s:=[[$0..2]$3];p:=s*~b[2..];q:=s*~(-1,3,4);for A in Iterator:-Permute([F$5,O$6,X$5])do`if`(`and`(seq(seq(seq(seq(A[j+~k])<>(F,O,X),k=[p,q,-q,-p][i]),j=a[i]+~b),i=1..4)),A,NULL)od;
Ungolfed:
a:=1,3,9,11; # top left cell of each quadrant
b:=0,1,4,5; # offsets to stay, or go right, down, downright
t[1]:=[[0,1,2],[0,4,8],[0,5,10]]; # right, down, downright (from first quadrant)
t[2]:=[[0,-1,-2],[0,3,6],[0,4,8]]; # left, down, downleft (from 2nd quadrant)
t[3]:=[[0,1,2],[0,-3,-6],[0,-4,-8]]; # up, right, upright (from 3rd quadrant)
t[4]:=[[0,-1,-2],[0,-4,-8],[0,-5,-10]]; # up, left, upleft (from 4th quadrant)
for A in Iterator:-Permute([F$5,O$6,X$5])do # all valid boards as 1D Arrays
`if`(`and`( # look for all 48 places FOX can be
seq(
seq(
seq(
seq(A[j+~k])<>(F,O,X), # test not F,O,X starting at j going in kth direction
k=t[i] # in t[i]
),
j=a[i]+~b # place to start in quadrant i
),
i=1..4) # for each quadrant i
),
A,NULL); # if none match output the 1D Array
od;
The board is in a 1D Array (1-relative indexing). For each quadrant of 4 cells in the (2D) board, e.g. top left, we look for F,O,X from each of the 4 cells going in each of 3 directions, e.g., right, down, downright from the top left. The t[i] are the offsets from the current cell to look in for the ith quadrant for each direction.
The 4 lines generating t[1]..t[4] can shortened to
s:=[[$0..2]$3]; # start with [[0,1,2],[0,1,2],[0,1,2]]
p:=s*~b[2..]; # multiply triples by 1, 4, 5 resp. to get t[1]
q:=s*~(-1,3,4); # multiply triples by -1, 3, 4 resp. to get t[2]
t:=[p,q,-q,-p]; # t[3] = -t[2], t[4] = -t[1]
JavaScript (V8), 141 bytes
f=(s=!0+'FX'+1e5,q)=>s[43]?/(.)(.*\1){12}|^(....)*.?(F(O|....O....)|..F..O..)X|F...O...X/.test(s)||print(q):[..."FXO"].map(c=>f(c+s+c,[q]+c))
Original version but seems to fail, not sure why
JavaScript (V8), 142 bytes
f=(s='')=>s[15]?[...s].some((c,i,A)=>!--t[c]|A.some((d,j)=>c<(m=i/4^j/4||s[(i+j)/2])&m<d),t={F:6,X:6,O:7})||print(s):[..."FXO"].map(O=>f(s+O))
Decide if pos i, mid(i,j), j build fox
JavaScript (V8), 144 bytes
Similar to the other version, but much slower.
f=(s=1e3+"FXFX"+1e3,q)=>s[43]?/(.)(.*\1){12}|^(....)*.?(F(O|....O....)|..F..O..)X|F...O...X/.test(s)||print(q):[..."FXO"].map(c=>f(c+s+c,[q]+c))
JavaScript (V8), 146 bytes
Prints the 255,304 flattened winning grids.
f=(s={}+0,q)=>s[47]?/(F|X)(\w*\1){5}|(O\w*){7}|^(....)*.?(F(O|....O....)|..F..O..)X|F...O...X/.test(s)||print(q):[..."FXO"].map(c=>f(c+s+c,[q]+c))
Method
We generate all 43,046,721 4x4 grids filled with F, O, X as flattened strings.
For each grid, we build the string consisting of the flattened grid, followed by the separator string "[object Object]0", followed by the reversed flattened grid.
For instance, the grid FFFFFXXXXXOOOOOO is turned into:
FFFFFXXXXXOOOOOO[object Object]0OOOOOOXXXXXFFFFF
For a grid to be valid, none of the following regular expression parts should match this string:
(F|X)(\w*\1){5}→ more than 5For 5Xon an an alphanumeric substring(O\w*){7}→ more than 6Oon an an alphanumeric substring^(....)*.?F(O|....O....)X→ horizontal or diagonal FOX, starting at 1st or 2nd character of a row^(....)*.?..F..O..X→ anti-diagonal FOX, starting at 3rd or 4th character of a rowF...O...X→ vertical FOX (anywhere)
Note that parts 3 and 4 are actually factorized as:
^(....)*.?(F(O|....O....)|..F..O..)X
Output
This is the beginning and the end of the output of a slightly modified version that prints the number of results:
Retina 0.8.2, 99 bytes
4$*
1
;;;4$*
+%1`1
F$'¶$`O$'¶$`X
A`(F|X)(.*\1){5}|(O.*){7}|(F|X)(.)*O(?<-5>.)*(?!\4)[FX](?(5)^)
;
Don't Try it online! - far too slow. Instead, Try it online! a 3×3 variant. Outputs a list of flattened boards. Explanation:
4$*
1
;;;4$*
Generate the string ;;;1111;;;1111;;;1111;;;1111.
+%1`1
F$'¶$`O$'¶$`X
Generate all the possibilities of filling 1s with F, O or X.
A`(F|X)(.*\1){5}|(O.*){7}|(F|X)(.)*O(?<-5>.)*(?!\4)[FX](?(5)^)
Exclude those with 6 Fs or Xs (shamelessly stealing @Arnauld's approach as both the ones I tried saved no bytes), 7 Os, or FOX or XOF spaced equidistantly using a .NET balancing group (compare my answers to Tic-Tac-Toe - X or O? or All Possible Ties in Tic-Tac-Toe). (Three semicolons are needed to stop the regex wrapping inappropriately.)
;
Delete the semicolons.
