type Pair = (Point, Point)
type Node = [Pair]
main = do
plus :: Point -> Point -> Point
plus (x1, y1) (x2, y2) = (x1+x2, y1+y2)
minus :: Point -> Point -> Point
minus (x1, y1) (x2, y2) = (x1-x2, y1-y2)
move :: Pair -> Point -> Pair
move (f, b) p = (f `plus` p, b `minus` p)
moves :: Pair -> Pair -> [Pair]
moves
(pf
, pb
) (qf
, qb
) = map (move
(pf
, pb
)) [f
, r
, l
] where
(dx, dy) = pf `minus` qf
f = (dx, dy)
r = (-dy, dx)
l = (dy, -dx)
nexts :: Node -> [Node]
nexts (p1:p0:ps) = [p2:p1:p0:ps | p2 <- moves p1 p0]
exists
:: Point
-> [Pair
] -> Bool where
either p
(pf
, pb
) = p
== pf
|| p
== pb
solve size = solutions initial
where
center :: Point
center
= (size `
div`
2, size `
div`
2)
p0 :: Pair
p0 = (center, center)
initial :: Node
initial = [move p0 (0, 1), p0]
atboundary
:: Point
-> Bool atboundary (x, y) = (x == 0) || (x == size) || (y == 0) || (y == size)
solutions :: Node -> [Node]
solutions n
| atboundary f = [n]
| exists f ps = []
n'' <- solutions n']
where
(f,b):ps = n
dHlwZSBQb2ludCA9IChJbnQsIEludCkKdHlwZSBQYWlyID0gKFBvaW50LCBQb2ludCkKdHlwZSBOb2RlID0gW1BhaXJdCgptYWluIDo6IElPICgpCm1haW4gPSAgZG8KICBwcmludCAkIGxlbmd0aCAkIHNvbHZlIDgKCnBsdXMgICAgICAgICAgICAgICAgICAgOjogUG9pbnQgLT4gUG9pbnQgLT4gUG9pbnQKcGx1cyAoeDEsIHkxKSAoeDIsIHkyKSA9ICAoeDEreDIsIHkxK3kyKQoKbWludXMgICAgICAgICAgICAgICAgICAgOjogUG9pbnQgLT4gUG9pbnQgLT4gUG9pbnQKbWludXMgKHgxLCB5MSkgKHgyLCB5MikgPSAgKHgxLXgyLCB5MS15MikKCm1vdmUgICAgICAgICAgOjogUGFpciAtPiBQb2ludCAtPiBQYWlyCm1vdmUgKGYsIGIpIHAgPSAgKGYgYHBsdXNgIHAsIGIgYG1pbnVzYCBwKQoKbW92ZXMgICAgICAgICAgICAgICAgICAgOjogUGFpciAtPiBQYWlyIC0+IFtQYWlyXQptb3ZlcyAocGYsIHBiKSAocWYsIHFiKSA9ICBtYXAgKG1vdmUgKHBmLCBwYikpIFtmLCByLCBsXQogIHdoZXJlCiAgICAoZHgsIGR5KSA9IHBmIGBtaW51c2AgcWYKICAgIGYgPSAoZHgsIGR5KQogICAgciA9ICgtZHksIGR4KQogICAgbCA9IChkeSwgLWR4KQoKbmV4dHMgICAgICAgICAgICA6OiBOb2RlIC0+IFtOb2RlXQpuZXh0cyAocDE6cDA6cHMpID0gIFtwMjpwMTpwMDpwcyB8IHAyIDwtIG1vdmVzIHAxIHAwXQoKZXhpc3RzIDo6IFBvaW50IC0+IFtQYWlyXSAtPiBCb29sCmV4aXN0cyBwID0gYW55IChlaXRoZXIgcCkKICB3aGVyZQogICAgZWl0aGVyIHAgKHBmLCBwYikgPSBwID09IHBmIHx8IHAgPT0gcGIKCnNvbHZlICAgICAgOjogSW50IC0+IFtOb2RlXQpzb2x2ZSBzaXplID0gIHNvbHV0aW9ucyBpbml0aWFsCiAgd2hlcmUKICAgIGNlbnRlciA6OiBQb2ludAogICAgY2VudGVyID0gIChzaXplIGBkaXZgIDIsIHNpemUgYGRpdmAgMikKCiAgICBwMCA6OiBQYWlyCiAgICBwMCA9ICAoY2VudGVyLCBjZW50ZXIpCgogICAgaW5pdGlhbCA6OiBOb2RlCiAgICBpbml0aWFsID0gW21vdmUgcDAgKDAsIDEpLCBwMF0KCiAgICBhdGJvdW5kYXJ5ICAgICAgICA6OiBQb2ludCAtPiBCb29sCiAgICBhdGJvdW5kYXJ5ICh4LCB5KSA9ICAoeCA9PSAwKSB8fCAoeCA9PSBzaXplKSB8fCAoeSA9PSAwKSB8fCAoeSA9PSBzaXplKQoKICAgIHNvbHV0aW9ucyAgIDo6IE5vZGUgLT4gW05vZGVdCiAgICBzb2x1dGlvbnMgbgogICAgICB8IGF0Ym91bmRhcnkgZiA9IFtuXQogICAgICB8IGV4aXN0cyBmIHBzICA9IFtdCiAgICAgIHwgb3RoZXJ3aXNlICAgID0gW24nJyB8IG4nIDwtIG5leHRzIG4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4nJyA8LSBzb2x1dGlvbnMgbiddCiAgICAgIHdoZXJlCiAgICAgICAgKGYsYik6cHMgPSBuCg==