import Control.Applicative
import Data.Array (Array,array,assocs,(//),(!))
import Data
.Maybe (isJust
,listToMaybe
) import Data.List (sortBy,transpose,nub,(\\))
import Data
.Ord (comparing
) import Debug.Trace
ans = [1..9]
block_side = 3
paper :: Mesh
paper
= array
((1,1),(length ans
,length ans
)) [(l
, Nothing
) | l
<- (,) <$> ans
<*> ans
]
main = case solve problem of
Nothing
-> print "can't solve it." where
problem = paper // [
((1, 2), Just 5), ((1, 4), Just 7), ((1, 9), Just 1)
, ((2, 4), Just 3), ((2, 5), Just 2)
, ((3, 2), Just 8), ((3, 4), Just 6), ((3, 5), Just 9), ((3, 9), Just 4)
, ((4, 1), Just 2), ((4, 3), Just 9), ((4, 5), Just 1), ((4, 7), Just 3)
, ((5, 2), Just 6), ((5, 3), Just 3), ((5, 7), Just 1), ((5, 8), Just 4)
, ((6, 3), Just 7), ((6, 5), Just 5), ((6, 7), Just 6), ((6, 9), Just 2)
, ((7, 1), Just 1), ((7, 5), Just 3), ((7, 6), Just 9), ((7, 8), Just 7)
, ((8, 5), Just 6), ((8, 6), Just 4)
, ((9, 1), Just 4), ((9, 6), Just 7), ((9, 8), Just 2)
]
solve
:: Mesh
-> Maybe Mesh
solve m
| completed m = Just m
| otherwise = listToMaybe
[s
| Just s
<- map solve progress
] where
completed
= (all $ isJust
. snd) . assocs
empties = [l | (l, Nothing) <- assocs m]
easy
_to
_head
= sortBy
. comparing
$ length . snd filling
= easy
_to
_head
$ zip empties
$ map (candidates m
) empties
progress = progress' -- `debugMesh` m
progress' = [m // [(loc, Just x)] | (loc, xs) <- filling, x <- xs]
candidates
:: Mesh
-> Loc
-> [Int]candidates m (x,y) = let
block
_range l
= map (+ 3 * div (l
- 1) block
_side
) [1 .. block
_side
] block = (,) <$> block_range x <*> block_range y
row = (,) <$> [x] <*> ans
col = (,) <$> ans <*> [y]
fixedVals ls = [ n | Just n <- [m ! l | l <- ls]]
constraint = fixedVals . nub $ block ++ row ++ col
in ans \\ constraint
chunk
:: Int -> [a
] -> [[a
]]chunk _ [] = []
chunk n list
= first :
(chunk n rest
) where (first
,rest
) = splitAt n list
showMesh
:: Mesh
-> [[String]]showMesh m
= transpose
$ chunk
(length ans
) [maybe " " show x
| (_, x
) <- assocs m
]
debugMesh :: a -> Mesh -> a
debugMesh f m
= foldr traceShow
(trace
"----" f
) $ showMesh m
debug
:: Show a
=> c
-> a
-> c
aW1wb3J0IENvbnRyb2wuQXBwbGljYXRpdmUKaW1wb3J0IERhdGEuQXJyYXkgKEFycmF5LGFycmF5LGFzc29jcywoLy8pLCghKSkKaW1wb3J0IERhdGEuTWF5YmUgKGlzSnVzdCxsaXN0VG9NYXliZSkKaW1wb3J0IERhdGEuTGlzdCAoc29ydEJ5LHRyYW5zcG9zZSxudWIsKFxcKSkKaW1wb3J0IERhdGEuT3JkIChjb21wYXJpbmcpCmltcG9ydCBEZWJ1Zy5UcmFjZQoKdHlwZSBMb2MgPSAoSW50LCBJbnQpCnR5cGUgTWVzaCA9IEFycmF5IExvYyAoTWF5YmUgSW50KQoKYW5zIDo6IFtJbnRdCmFucyA9IFsxLi45XQoKYmxvY2tfc2lkZSA6OiBJbnQKYmxvY2tfc2lkZSA9IDMKCnBhcGVyIDo6IE1lc2gKcGFwZXIgPSBhcnJheSAoKDEsMSksKGxlbmd0aCBhbnMsbGVuZ3RoIGFucykpIFsobCwgTm90aGluZykgfCBsIDwtICgsKSA8JD4gYW5zIDwqPiBhbnNdCgptYWluIDo6IElPICgpCm1haW4gPSBjYXNlIHNvbHZlIHByb2JsZW0gb2YKICAgIE5vdGhpbmcgLT4gcHJpbnQgImNhbid0IHNvbHZlIGl0LiIKICAgIEp1c3QgbSAtPiBtYXBNXyBwcmludCAkIHNob3dNZXNoIG0KICB3aGVyZQogICAgcHJvYmxlbSA9IHBhcGVyIC8vIFsKICAgICAgICAoKDEsIDIpLCBKdXN0IDUpLCAoKDEsIDQpLCBKdXN0IDcpLCAoKDEsIDkpLCBKdXN0IDEpCiAgICAgICwgKCgyLCA0KSwgSnVzdCAzKSwgKCgyLCA1KSwgSnVzdCAyKQogICAgICAsICgoMywgMiksIEp1c3QgOCksICgoMywgNCksIEp1c3QgNiksICgoMywgNSksIEp1c3QgOSksICgoMywgOSksIEp1c3QgNCkKICAgICAgLCAoKDQsIDEpLCBKdXN0IDIpLCAoKDQsIDMpLCBKdXN0IDkpLCAoKDQsIDUpLCBKdXN0IDEpLCAoKDQsIDcpLCBKdXN0IDMpCiAgICAgICwgKCg1LCAyKSwgSnVzdCA2KSwgKCg1LCAzKSwgSnVzdCAzKSwgKCg1LCA3KSwgSnVzdCAxKSwgKCg1LCA4KSwgSnVzdCA0KQogICAgICAsICgoNiwgMyksIEp1c3QgNyksICgoNiwgNSksIEp1c3QgNSksICgoNiwgNyksIEp1c3QgNiksICgoNiwgOSksIEp1c3QgMikKICAgICAgLCAoKDcsIDEpLCBKdXN0IDEpLCAoKDcsIDUpLCBKdXN0IDMpLCAoKDcsIDYpLCBKdXN0IDkpLCAoKDcsIDgpLCBKdXN0IDcpCiAgICAgICwgKCg4LCA1KSwgSnVzdCA2KSwgKCg4LCA2KSwgSnVzdCA0KQogICAgICAsICgoOSwgMSksIEp1c3QgNCksICgoOSwgNiksIEp1c3QgNyksICgoOSwgOCksIEp1c3QgMikKICAgICAgXQoKc29sdmUgOjogTWVzaCAtPiBNYXliZSBNZXNoCnNvbHZlIG0KICB8IGNvbXBsZXRlZCBtID0gSnVzdCBtCiAgfCBvdGhlcndpc2UgPSBsaXN0VG9NYXliZSBbcyB8IEp1c3QgcyA8LSBtYXAgc29sdmUgcHJvZ3Jlc3NdCiAgd2hlcmUKICAgIGNvbXBsZXRlZCA9IChhbGwgJCBpc0p1c3QgLiBzbmQpIC4gYXNzb2NzCiAgICBlbXB0aWVzID0gW2wgfCAobCwgTm90aGluZykgPC0gYXNzb2NzIG1dCiAgICBlYXN5X3RvX2hlYWQgPSBzb3J0QnkgLiBjb21wYXJpbmcgJCBsZW5ndGggLiBzbmQKICAgIGZpbGxpbmcgPSBlYXN5X3RvX2hlYWQgJCB6aXAgZW1wdGllcyAkIG1hcCAoY2FuZGlkYXRlcyBtKSBlbXB0aWVzCiAgICBwcm9ncmVzcyA9IHByb2dyZXNzJyAtLSBgZGVidWdNZXNoYCBtCiAgICBwcm9ncmVzcycgPSBbbSAvLyBbKGxvYywgSnVzdCB4KV0gfCAobG9jLCB4cykgPC0gZmlsbGluZywgeCA8LSB4c10KCmNhbmRpZGF0ZXMgOjogTWVzaCAtPiBMb2MgLT4gW0ludF0KY2FuZGlkYXRlcyBtICh4LHkpID0gbGV0CiAgICBibG9ja19yYW5nZSBsID0gbWFwICgrIDMgKiBkaXYgKGwgLSAxKSBibG9ja19zaWRlKSBbMSAuLiBibG9ja19zaWRlXQogICAgYmxvY2sgPSAoLCkgPCQ+IGJsb2NrX3JhbmdlIHggPCo+IGJsb2NrX3JhbmdlIHkKICAgIHJvdyA9ICgsKSA8JD4gW3hdIDwqPiBhbnMKICAgIGNvbCA9ICgsKSA8JD4gYW5zIDwqPiBbeV0KICAgIGZpeGVkVmFscyBscyA9IFsgbiB8IEp1c3QgbiA8LSBbbSAhIGwgfCBsIDwtIGxzXV0KICAgIGNvbnN0cmFpbnQgPSBmaXhlZFZhbHMgLiBudWIgJCBibG9jayArKyByb3cgKysgY29sCiAgaW4gYW5zIFxcIGNvbnN0cmFpbnQKCmNodW5rIDo6IEludCAtPiBbYV0gLT4gW1thXV0KY2h1bmsgXyBbXSA9IFtdCmNodW5rIG4gbGlzdCA9IGZpcnN0IDogKGNodW5rIG4gcmVzdCkgIHdoZXJlIChmaXJzdCxyZXN0KSA9IHNwbGl0QXQgbiBsaXN0CgpzaG93TWVzaCA6OiBNZXNoIC0+IFtbU3RyaW5nXV0Kc2hvd01lc2ggbSA9IHRyYW5zcG9zZSAkIGNodW5rIChsZW5ndGggYW5zKSBbbWF5YmUgIiAiIHNob3cgeCB8IChfLCB4KSA8LSBhc3NvY3MgbV0KCmRlYnVnTWVzaCA6OiBhIC0+IE1lc2ggLT4gYQpkZWJ1Z01lc2ggZiBtID0gZm9sZHIgdHJhY2VTaG93ICh0cmFjZSAiLS0tLSIgZikgJCBzaG93TWVzaCBtCgpkZWJ1ZyA6OiBTaG93IGEgPT4gYyAtPiBhIC0+IGMKZGVidWcgPSBmbGlwIHRyYWNlU2hvdwo=
["3","6","7","2","5","8","1","9","4"]
["5","9","8","4","6","1","2","7","3"]
["2","4","1","9","3","7","8","5","6"]
["7","3","6","8","9","4","5","2","1"]
["4","2","9","1","7","5","3","6","8"]
["8","1","5","6","2","3","9","4","7"]
["9","7","2","3","1","6","4","8","5"]
["6","8","3","5","4","9","7","1","2"]
["1","5","4","7","8","2","6","3","9"]