| Bytes | Lang | Time | Link |
|---|---|---|---|
| 461 | Python3 | 250517T155610Z | Ajax1234 |
| 285 | Python 2 | 190122T054120Z | Chas Bro |
| 183 | JavaScript ES6 | 190120T203915Z | Arnauld |
| 057 | Jelly | 190121T000728Z | Jonathan |
Python3, 461 bytes
E=enumerate
def V(P,j):
B=P[j][-1]
q=[(5,j,B,-1,-1),(5,j,B,-1,1)]
for x,y,B,X,Y in q:
if 0<=(J:=x+X)<6 and 0<=(K:=y+Y)<7:q+=[(J,K,B+[*zip(*P)][J][K],X,Y)]
else:yield B
def f(b):
q=[(['']*7,0)]
for B,T in q:
P=[' '*(6-len(j))+j for j in B]
if b==P:return 1
if not any('0'*4 in''.join(i)or'1'*4 in''.join(i)for i in B+[*zip(*P)]+[k for j,_ in E(P)for k in V(P,j)]):
for i,a in E(B):q+=[(B[:i]+[str(T)+a]+B[i+1:],(T+1)%2)]*b[i].endswith(str(T)+a)
Python 2, 295 285 bytes
def f(a):
if 1-any(a):return[]
p=sum(map(len,a))%2
for i in R(7):
if a[i][-1:]==`p`:
b=a[:];b[i]=b[i][:-1];L=f(b)
if L>1>(`1-p`*4in','.join([J((u[j]+' '*14)[n-j]for j in R(7))for n in R(12)for u in[b,b[::-1]]]+b+map(J,zip(*[r+' '*7for r in b])))):return L+[i]
R=range;J=''.join
-10 thx to Jo King.
Input is a list of strings representing the columns; with '1' for Red and '0' for Yellow. The strings are not ' '-padded. So the (falsey) case:
| | | | | | | |
| | | | | | | |
|Y| | | | | | |
|R|Y| | | | | |
|R|R|Y| | | | |
|Y|R|R|Y| | |R|
is input as:
[
'0110',
'110',
'10',
'0',
'',
'',
'1'
]
Output is a list of column indexes, 0-indexed, that could make the board; or None if it's not valid.
Accepts the empty board as valid (returns the empty list [] instead of None).
This approach is recursive from the last move to the first move: based on the parity of the total number of moves taken, we remove either the last Red move or the last Yellow move (or fail if that is not possible); check the resulting board to see if the opponent has 4-in-a-row (in which case fail, because the game should have stopped already); otherwise, recurse until the board is empty (which is valid).
The 4-in-a-row code is the most bloaty part. All the diagonal strings for the matrix b are generated by:
[
''.join(
(u[j]+' '*14)[n-j] for j in range(7)
)
for u in[b,b[::-1]]for n in range(12)
]
which first lists out the 'down-sloping' diagonals, and then 'up-sloping' ones.
JavaScript (ES6), 202 194 187 183 bytes
Takes input as a matrix with \$2\$ for red, \$4\$ for yellow and \$0\$ for empty. Returns a string of 0-indexed moves (or an empty string if there's no solution). Reds start the game.
m=>(p=[...'5555555'],g=(c,s=o='')=>/2|4/.test(m)?['',0,2,4].some(n=>m.join``.match(`(1|3)(.{1${n}}\\1){3}`))?o:p.map((y,x)=>m[m[y][x]--^c||p[g(c^6,s+x,p[x]--),x]++,y][x]++)&&o:o=s)(2)
How?
The recursive function \$g\$ attempts to replace all \$2\$'s and \$4\$'s in the input matrix with \$1\$'s and \$3\$'s respectively.
While doing so, it makes sure that we don't have any run of four consecutive odd values until all even values have disappeared (i.e. if a side wins, it must be the last move).
The row \$y\$ of the next available slot for each column \$x\$ is stored in \$p[x]\$.
Commented
m => ( // m[] = input matrix
p = [...'5555555'], // p[] = next row for each column
g = (c, // g = recursive function taking c = color,
s = o = '') => // s = current solution, o = final output
/2|4/.test(m) ? // if the matrix still contains at least a 2 or a 4:
['', 0, 2, 4] // see if we have four consecutive 1's or 3's
.some(n => // by testing the four possible directions
m.join`` // on the joined matrix, using
.match( // a regular expression where the number of characters
`(1|3)(.{1${n}}\\1){3}` // between each occurrence is either 1, 10, 12 or 14
) // (horizontal, diagonal, vertical, anti-diagonal)
) ? // if we have a match:
o // abort and just return the current value of o
: // else:
p.map((y, x) => // for each cell at (x, y = p[x]):
m[ //
m[y][x]-- // decrement the value of the cell
^ c || // compare the original value with c
p[ // if they're equal:
g( // do a recursive call with:
c ^ 6, // the other color
s + x, // the updated solution
p[x]-- // the updated row for this column
), // end of recursive call
x // then:
]++, // restore p[x]
y // and restore m[y][x]
][x]++ // to their initial values
) && o // end of map(); yield o
: // else:
o = s // we've found a solution: copy s to o
)(2) // initial call to g() with c = 2
Jelly, 57 bytes
ŒṪŒ!µ0ịŒṬ¬a³ZU,Ɗ;ŒD$€Ẏṡ€4Ḅo1%15;Ḋ€ṢṚ$Ƒƙ$Ȧȧœị³$2R¤ṁ$ƑµƇṪṪ€
Takes a matrix where 0 is unfilled, 1 played first, and 2 played second. Yields a list of 1-indexed columns, empty if a fake was identified.
Try it online! (too inefficient for more than 7 pieces to run in under a minute)
Note:
- Assumes that no "floating" pieces are present (fix this by prepending
ZṠṢ€Ƒȧfor +6 bytes) - Assumes that the empty board is a fake