# Solve the Zany car game

The Zany Car Game is a tile matching game. You are given a number of tiles, with coloured cars split into a top and bottom half. To win the game, you need to find a square arrangement of the tiles so that only whole, correctly coloured cars are formed at each tile join , like the image below.

## Challenge

Given a square set of mixed tiles, output any solution of correctly ordered tiles. If there is no solution, output nothing. You can choose how to input the tiles. You may either output the tiles in your input format, or output the required rearranged position of the tiles and their rotations from the input (see the example).

This is , the shortest answer in bytes wins

## Example

Take each tile as a flat list, of the form [UP, RIGHT, DOWN, LEFT]. The colour-half combinations are represented by numbers as follows

Red top = 1
Red bottom = 8
Green top = 2
Green bottom = 7
Blue top = 3
Blue bottom = 6
Yellow top = 4
Yellow bottom = 5


So that the top and bottom of any given colour add to 9 (similar to how a die is arranged).

For this example we will use the following arrangement of tiles that needs solving:

-------
2 | 3
6 1|1 5
5 | 7
-------
7 | 2
6 4|4 8
1 | 6
-------


Which can be represented as a 2D list or a flattened list:

input = [
[[2,1,5,6],[3,5,7,1],],
[[7,4,1,6],[2,8,6,4],],
]
or
input = [[2,1,5,6],[3,5,7,1],[7,4,1,6],[2,8,6,4]]


The solution for this example can either be given as the rearranged tiles or the new position of each tile in the flattened list, with the rotation for each tile given as 0=0°, 1=90°, 2=180°, 3=270°

output = [[6, 4, 2, 8], [7, 1, 3, 5], [7, 4, 1, 6], [6, 2, 1, 5]]
or
positions = [3, 1, 2, 0]
rotations = [2, 2, 0, 3]


Either of these should correspond to the solution:

-------
6 | 7
8 4|5 1
2 | 3
-------
7 | 6
6 4|5 2
1 | 1
-------


A python script solving this example can be found here.

## Test Cases

It's worth noting that each unique solution will have 4 solutions, 1 for each rotation of the whole grid. Only one orientation will be given here.

Input 1:

[[2,1,5,6],[3,5,7,1],[7,4,1,6],[2,8,6,4]]


Output 1:

[[6,4,2,8],[7,1,3,5],[7,4,1,6],[6,2,1,5]]
or
positions = [3, 1, 2, 0]
rotations = [2, 2, 0, 3]


Input 2:

[[1,2,3,4],[2,3,4,1],[3,4,2,1],[4,1,2,3]]


Output 2:
No solution

Input 3:

[[4,8,7,3],[1,2,5,7],[6,2,1,5],[2, 8, 6, 4]]


Output 3:

[[7,3,4,8],[4,2,8,6],[5,7,1,2],[1,5,6,2]]
or
Positions = [0, 3, 1, 2]
Rotations = [2, 3, 2, 2]


Input 4:

[[7,1,3,5],[1,6,7,4],[4,8,7,3],[1,5,6,2],[2,8,6,4],[2,5,6,1],[2,5,7,1],[3,5,7,1],[4,3,8,6]]


Output:

[[1,5,6,2],[1,6,7,4],[4,8,7,3],[3,5,7,1],[2,8,6,4],[2,5,6,1],[2,5,7,1],[8,6,4,3],[3,5,7,1]]
or
Positions = [8, 1, 2, 0, 4, 5, 6, 3, 7]
Rotations = [2, 0, 0, 0, 0, 0, 0, 0, 2]


# Python3, 408 bytes:

lambda s:(q:=int(len(s)**0.5))and[j for k in next(f([[0]*q]*q,[(x//q,x%q)for x in R(q**2)],s),[])for j in k]
R=range
v=lambda x,L,A,B:all(all(0 in[i[j],i[j+1]]or 9==i[j][A]+i[j+1][B]for j in R(L-1))for i in x)
def f(b,M,s):
if[]==s:yield b
x,y=M[0]
for O in s:
for j in R(4):
B=eval(str(b));B[x][y]=O[j:]+O[:j]
if v(B,L:=len(b),1,3)and v(zip(*B),L,2,0):yield from f(B,M[1:],[i for i in s if i!=O])


Try it online!

• Fast answer! Can save 4 bytes Commented May 19, 2022 at 22:18
• @jezza_99 Thank you, updated. Commented May 19, 2022 at 22:28
• You also don't need the return in f (considering s is empty!) Commented May 19, 2022 at 23:29
• 408 bytes Commented May 20, 2022 at 4:56
• Continuing @jezza_99's 408-byter above: **0.5 can be **.5; q**2 can be q*q; and 0 in can be 0in for -3 bytes. Commented May 20, 2022 at 6:46

# Python 3, 204 bytes

f=lambda a,*i:[z for b in a for c in f(a-{b},1)or[[]]for n in(0,1,2,3)for z in[c+[b[n:]+b[:n]]]if{p[2-b]+q[b*3]for b in(0,1)for p,q in zip(z,z[b or int(len(z)**.5):])if z.index(q)**2%len(z)-b+1}=={9}or i]


Try it online!

Recursively tries every possible permutation and returns the valid ones. This is a brute-force approach and times out for the last test case. It should work in principle, though.