[Question]
  [
A grid-filling meander is a closed path that visits every cell of a square \$N \times N\$ grid at least once, never crossing any edge between adjacent cells more than once and never crossing itself. For example:
![](https://i.stack.imgur.com/WTQSE.png)
Once filled, each cell of the grid can be represented by one of the following 8 tiles:
![](https://i.stack.imgur.com/qKSzJ.png)
Numbered this way, the tiles of the above meander can be represented by this matrix:
```
5 6 5 6
4 8 3 2
5 7 6 2
4 3 4 3
```
Your task is to complete a grid-filling meander given an incomplete set of tiles. For example, the incomplete meander:
![](https://i.stack.imgur.com/tDaYc.png)
...which can be represented using `0`s for missing tiles:
```
5 0 0 0 6
0 0 7 0 0
0 0 0 0 3
2 4 0 0 0
0 0 3 0 0
```
...could be completed like this:
![](https://i.stack.imgur.com/NDsGR.png)
...i.e.:
```
5 6 5 1 6
4 8 7 6 2
5 7 7 7 3
2 4 8 8 6
4 1 3 4 3
```
### Specifications
* The input will always have at least \$1\$ and at most \$N^2\$ (non-empty) tiles, where \$2 \le N \le 7\$.
* You may use any set of values to represent the tiles, as long as it's specified in your answer.
* Your input and output may be in any format and order, as long as it's specified in your answer.
* At least one valid solution will exist for all inputs (i.e. you don't need to handle invalid input).
* [Standard I/O rules](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods "Default for Code Golf: Input/Output methods") apply.
* [Standard loopholes](https://codegolf.meta.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default "Loopholes that are forbidden by default") are forbidden.
* Explanations, even for "practical" languages, are encouraged.
### Test cases
> 
> Input ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#0,6,0,0)):
> 
> 
> 
> ```
> 0 6
> 0 0
> 
> ```
> 
> Output ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,4,3)):
> 
> 
> 
> ```
> 5 6
> 4 3
> 
> ```
> 
> 
> 
> Input ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,5,6,4,0,3,2,5,7,6,2,4,3,4,3)):
> 
> 
> 
> ```
> 5 6 5 6
> 4 0 3 2
> 5 7 6 2
> 4 3 4 3
> 
> ```
> 
> Output ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,5,6,4,8,3,2,5,7,6,2,4,3,4,3)):
> 
> 
> 
> ```
> 5 6 5 6
> 4 8 3 2
> 5 7 6 2
> 4 3 4 3
> 
> ```
> 
> 
> 
> Input ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#5,0,0,0,6,0,0,7,0,0,0,0,0,0,3,2,4,0,0,0,0,0,3,0,0)):
> 
> 
> 
> ```
> 5 0 0 0 6
> 0 0 7 0 0
> 0 0 0 0 3
> 2 4 0 0 0
> 0 0 3 0 0
> 
> ```
> 
> Output ([Θ](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,5,1,6,4,8,7,6,2,5,7,7,7,3,2,4,8,8,6,4,1,3,4,3)):
> 
> 
> 
> ```
> 5 6 5 1 6
> 4 8 7 6 2
> 5 7 7 7 3
> 2 4 8 8 6
> 4 1 3 4 3
> 
> ```
> 
> 
  
[Answer]
# JavaScript (ES7), ~~236 ... 193~~ 185 bytes
Outputs by modifying the input matrix.
```
m=>(g=(d,x,y,v,r=m[y],h=_=>++r[x]<9?g(d,x,y,v)||h():r[x]=0)=>r&&1/(n=r[x])?x|y|!v?n?g(d='21100--13203-32-21030321'[n*28+d*3+7&31],x+--d%2,y+--d%2,v+=n<7||.5):h():!m[v**.5|0]:0)(0,0,0,0)
```
[Try it online!](https://tio.run/##ZU/bboMwDH3nK9KHlQQMC0lpt66hT/sKFk2o0JuaUEGFQMu@nZHRrpUmy4p9LrZzzJqs3lSH8yXQZV70W9ErkeCdwDm00EEDlVBpJ2EvPkXi@1XaytXrenejiTF7TJYWFpSIpJpOo2eshQXIujWdmTRrbfXCZVFEaRBEnFEecBawiHLKWeSm2mMvfu5xfzHlkYTWD4L8iUF3fRtf6NXCmDAmS7ttotLG88LYULmkBFP4DdJfivqCBFJIJOgLbUpdl6ciPJU7vMWKkDeUuh/aBeSCK8NtWb1nmz2ui7PVP6pVqLIzrixchcfyoPHgIGQsBz1BPrKT7Mhvx7FrceoglFKYSxgLKh1JHqgY5hDf6NlwLwc2NjEsBo7dGA5D/jOPf7xPHzx2x19rg48tg9kI3FkO14P6Hw "JavaScript (Node.js) – Try It Online")
(includes some post-processing code to print the result both as a matrix and as a flat list compatible with the [visualization tool](https://observablehq.com/@jrunning/grid-filling-meanders) provided by the OP)
## Results
* [Test case #1](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,4,3)
* [Test case #2](https://observablehq.com/@jrunning/grid-filling-meanders#5,6,5,6,4,8,3,2,5,7,6,2,4,3,4,3)
* [Test case #3](https://observablehq.com/@jrunning/grid-filling-meanders#5,1,6,5,6,2,5,7,3,2,2,2,2,5,3,2,4,7,8,6,4,1,3,4,3)
## How?
### Variables
\$g\$ is a recursive function taking the current direction \$d\$, the current coordinates \$(x,y)\$ and the number of visited cells \$v\$.
The following variables are also defined in the scope of \$g\$:
* \$r\$ is the current row of the matrix.
```
r = m[y]
```
* \$h\$ is a helper function that tries all values from \$1\$ to \$8\$ for the current cell and invokes \$g\$ with each of them. It either stops as soon as \$g\$ succeeds or sets the current cell back to \$0\$ if we need to backtrack.
```
h = _ => ++r[x] < 9 ? g(d, x, y, v) || h() : r[x] = 0
```
### Initial checks
We first make sure that our current location is valid and we load the value of the current cell into \$n\$:
```
r && 1 / (n = r[x]) ? ... ok ... : ... failed ...
```
We test whether we're back to our starting position, i.e. we're located at \$(0,0)\$ and we've visited at least a few cells (\$v>0\$):
```
x | y | !v ? ... no ... : ... yes ...
```
For now, let's assume that we're not back to the starting point.
### Looking for a path
If \$n\$ is equal to \$0\$, we invoke \$h\$ to try all possible values for this tile.
If \$n\$ is not equal to \$0\$, we try to move to the next tile.
The tile connections are encoded in a lookup table, whose index is computed with \$n\$ and \$d\$, and whose valid entries represent the new values of \$d\$.
```
d = '21100--13203-32-21030321'[n * 28 + d * 3 + 7 & 31]
```
The last 8 entries are invalid and omitted. The other 4 invalid entries are explicitly marked with hyphens.
For reference, below are the decoded table, the compass and the tile-set provided in the challenge:
```
   | 1 2 3 4 5 6 7 8
---+-----------------
 0 | 0 - - 1 3 - 3 1          1
 1 | - 1 - - 2 0 2 0        0 + 2
 2 | 2 - 1 - - 3 1 3          3
 3 | - 3 0 2 - - 0 2
```
![](https://i.stack.imgur.com/qKSzJ.png)
We do a recursive call to \$g\$ with the new direction and the new coordinates. We add \$1/2\$ to \$v\$ if we were on a tile of type \$7\$ or \$8\$, or \$1\$ otherwise (see the next paragraph).
```
g(d, x + --d % 2, y + --d % 2, v += n < 7 || .5)
```
If \$d\$ is invalid, \$x\$ and \$y\$ will be set to *NaN*, forcing the next iteration to fail immediately.
### Validating the path
Finally, when we're back to \$(0,0)\$ with \$v>0\$, it doesn't necessarily mean that we've found a valid path, as we may have taken a shortcut. We need to check if we've visited the correct number of cells.
Each tile must be visited once, except tiles \$7\$ and \$8\$ that must be visited twice. This is why we add only \$1/2\$ to \$v\$ when such a tile is visited.
In the end, we must have \$v = N^2\$. But it's also worth noting that we can't possibly have \$v > N^2\$. So, it's enough to test that we don't have \$v < N^2\$, or that the \$k\$th row of the matrix (0-indexed) does not exist, where \$k=\lfloor\sqrt{v}\rfloor\$.
Hence the JS code:
```
!m[v ** .5 | 0]
```
### Formatted source
```
m => (
  g = (
    d,
    x, y,
    v,
    r = m[y],
    h = _ => ++r[x] < 9 ? g(d, x, y, v) || h() : r[x] = 0
  ) =>
    r && 1 / (n = r[x]) ?
      x | y | !v ?
        n ?
          g(
            d = '21100--13203-32-21030321'[n * 28 + d * 3 + 7 & 31],
            x + --d % 2,
            y + --d % 2,
            v += n < 7 || .5
          )
        :
          h()
      :
        !m[v ** .5 | 0]
    :
      0
)(0, 0, 0, 0)
```
]