Menu

Home

alhambra1

Usage:

Open a command prompt in the directory the file, "solve.exe" is in. (Windows Vista/7: hold down the Shift key and right-click a folder. The context menu will contain an entry, "Open command window here.")

Type, "solve"

Enter TARGET, the highest number to attain

Enter DENSITY, how many moves to choose from at each choice point; higher DENSITY means a more thorough but also exponentially slower search (between 3 and 6 is recommended)

BOARD is indexed
1 2 3
4 5 6
7 8 9
so enter the number from each index in order

For example, "solve", "9", "6", "5 1 4 8 2 9 6 7 3"
searches for a way to get a 9,
using 6 moves for each choice point,
on the board
5 1 4
8 2 9
6 7 3
and yields the result [[2,4]]



Haskell code:

:::haskell

{-# OPTIONS_GHC -O2 #-}
import Data.List (sortBy,nubBy)
import Data.Ord (compare)
import System.Time

main = do  
    putStrLn "Puzzle Number 9 Solver Copyright May 2015 alhambra1"
    putStrLn "\nEnter 'e' at any time to exit"
    putStrLn "\nEnter target number"
    target <- getLine  
    if null target  
        then main
        else if head target == 'e'    
                then return ()        
                else do 
                      putStrLn "Enter number of moves at each choice point (density, 3 to 6 recommended)"  
                      density <- getLine  
                      if null density  
                          then main
                          else if head density == 'e'    
                                  then return ()        
                                  else do 
                                        putStrLn "Enter board numbers separated by spaces"  
                                        board <- getLine  
                                        if null board  
                                            then main
                                            else if head board == 'e'    
                                                    then return ()        
                                                    else do 
                                                        putStrLn ""
                                                        time1 <- getClockTime 
                                                        let b = map (\x -> read x :: Int) (take 9 $ words board)
                                                            t = read (head (words target)) :: Int
                                                            d = read (head (words density)) :: Int
                                                        print (map reverse $ reverse $ head $ take 1 $ f t b [] d)
                                                        time2 <- getClockTime
                                                        putStrLn ""
                                                        print (timeDiffToString $ diffClockTimes time2 time1)
                                                        putStrLn ""
                                                        exit

exit = do
     putStrLn "Enter 'a' to start again or 'e' to exit"
     line <- getLine
     if null line 
        then exit
             else if head line == 'a'
                     then do putStrLn ""
                             main
                          else if head line == 'e'
                                  then return ()
                                  else exit

f target board paths toTake
  | not (null hasTarget) = [(((\(x,y,z)-> z) . head $ hasTarget):paths)]
  | null ms              = []
  | otherwise            = do (s,bd,idxs) <- take toTake (sortBy (\(x,y,z) (x',y',z') -> compare x' x) ms')
                              f target bd (idxs:paths) toTake
 where hasTarget = filter ((==target) . (\(x,y,z)-> x)) ms
       ms = moves board
       ms' = nubBy (\(x,y,z) (x',y',z') -> let a = drop 1 (init z)
                                               b = drop 1 (init z')
                                           in if not (null a) && not (null b)
                                                 then a == b
                                                 else False) ms

moves board = do j <- [1..9]
                 let num = board !! (j - 1)
                     board' = (take (j - 1) board) ++ [num + 1] ++ (drop j board)
                 moves' j board' num [j] 0 num
 where moves' ix board s idxs prev next
        | (s == 9 || multiple) && (length idxs > 1) = [(s,board',idxs)]
        | s > 9 && mod s 9 /= 0 = []
        | otherwise = case ix of
            1 -> if elem 2 idxs then [] else moves' 2 board' (s + b) (2:idxs) next b
                 ++ (if elem 4 idxs then [] else moves' 4 board' (s + d) (4:idxs) next d)
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
            2 -> if elem 1 idxs then [] else moves' 1 board' (s + a) (1:idxs) next a
                 ++ (if elem 3 idxs then [] else moves' 3 board' (s + c) (3:idxs) next c)
                 ++ (if elem 4 idxs then [] else moves' 4 board' (s + d) (4:idxs) next d)
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 6 idxs then [] else moves' 6 board' (s + f) (6:idxs) next f)
            3 -> if elem 2 idxs then [] else moves' 2 board' (s + b) (2:idxs) next b
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 6 idxs then [] else moves' 6 board' (s + f) (6:idxs) next f)
            4 -> if elem 1 idxs then [] else moves' 1 board' (s + a) (1:idxs) next a
                 ++ (if elem 2 idxs then [] else moves' 2 board' (s + b) (2:idxs) next b)
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 7 idxs then [] else moves' 7 board' (s + g) (7:idxs) next g)
                 ++ (if elem 8 idxs then [] else moves' 8 board' (s + h) (8:idxs) next h)
            5 -> if elem 1 idxs then [] else moves' 1 board' (s + a) (1:idxs) next a
                 ++ (if elem 2 idxs then [] else moves' 2 board' (s + b) (2:idxs) next b)
                 ++ (if elem 3 idxs then [] else moves' 3 board' (s + c) (3:idxs) next c)
                 ++ (if elem 4 idxs then [] else moves' 4 board' (s + d) (4:idxs) next d)
                 ++ (if elem 6 idxs then [] else moves' 6 board' (s + f) (6:idxs) next f)
                 ++ (if elem 7 idxs then [] else moves' 7 board' (s + g) (7:idxs) next g)
                 ++ (if elem 8 idxs then [] else moves' 8 board' (s + h) (8:idxs) next h)
                 ++ (if elem 9 idxs then [] else moves' 9 board' (s + i) (9:idxs) next i)
            6 -> if elem 2 idxs then [] else moves' 2 board' (s + b) (2:idxs) next b
                 ++ (if elem 3 idxs then [] else moves' 3 board' (s + c) (3:idxs) next c)
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 8 idxs then [] else moves' 8 board' (s + h) (8:idxs) next h)
                 ++ (if elem 9 idxs then [] else moves' 9 board' (s + i) (9:idxs) next i)
            7 -> if elem 4 idxs then [] else moves' 4 board' (s + d) (4:idxs) next d
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 8 idxs then [] else moves' 8 board' (s + h) (8:idxs) next h)
            8 -> if elem 4 idxs then [] else moves' 4 board' (s + d) (4:idxs) next d
                 ++ (if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e)
                 ++ (if elem 6 idxs then [] else moves' 6 board' (s + f) (6:idxs) next f)
                 ++ (if elem 7 idxs then [] else moves' 7 board' (s + g) (7:idxs) next g)
                 ++ (if elem 9 idxs then [] else moves' 9 board' (s + i) (9:idxs) next i)
            9 -> if elem 5 idxs then [] else moves' 5 board' (s + e) (5:idxs) next e
                 ++ (if elem 6 idxs then [] else moves' 6 board' (s + f) (6:idxs) next f)
                 ++ (if elem 8 idxs then [] else moves' 8 board' (s + h) (8:idxs) next h)
          where multiple = length idxs == 2 && prev == next && mod s 9 == 0
                [a,b,c,d,e,f,g,h,i] = board
                board' = if s == 9
                            then (take (headIdxs - 1) board) ++ [9] ++ (drop headIdxs board)
                            else if multiple
                                    then board''
                                    else (take (headIdxs - 1) board) ++ [next + 1] ++ (drop headIdxs board)
                board'' = map (\(x,y) -> if x == headIdxs then y * 2 else if x == last idxs then 1 else y) (zip [1..] board)
                headIdxs = head idxs

MongoDB Logo MongoDB