g | x | w | all
Bytes Lang Time Link
7827Haskell230125T213724Znimi
643C 64170820T234928Zuser6318

Haskell, Score: 3.70M, 7827 Bytes

Score: 4.98M, 7564 Bytes

{-# LANGUAGE BangPatterns #-}

import Control.Concurrent.Async (mapConcurrently)
import Control.Monad (foldM)
import Data.Maybe (mapMaybe)
import Data.Vector ((//),(!))
import qualified Data.Vector as V
import qualified Data.List   as L
import qualified Data.IntSet as S

type Deck     = String           -- a line of the input, eg. JD 2D 9H JC 5D ...
type Card     = (Int , Int)      -- (Suit, Rank)
type Cascade  = [Card]           -- bottom up, i.e. head is the accessible card
type Board    = V.Vector Cascade -- the whole Board: 16 lots of cascades
                                 -- 0..7:tableau, 8..11:cells, 12..15:foundation
type Move     = (Int , Int)      -- 'from' and 'to' board index
type Game     = (Board, [Move])  -- a Board and the Moves to get there
type Solution = (Deck, [Move])   -- a deck and its solving moves
type Strategy = Int

idxTbl, idxTblR, idxFnd, idxCell, idxFrom :: [Int]
idxTbl  = [ 0.. 7]               -- indices of tableau cascades
idxTblR = [7,6..0]               -- indices of tableau in reverse order
idxFnd  = [12..15]               -- indices of foundations
idxCell = [ 8..11]               -- indices of freecells
idxFrom = [ 0..11]               -- indices where a card can be moved from

(@!) :: Board -> Int -> Int      -- return the rank of the top card at index i
brd @! i = snd $ head $ brd!i

mvCard :: Board -> Move -> Board -- move a card in a board, return new board
mvCard b (f,t) | c:cs <- b!f = b // [(t,c:if t<8 then b!t else []) , (f,cs)]
mvCard _ _     = error "mvCard: move from empty cascade"

--
--
--

main :: IO ()
main = announce =<< mapConcurrently solveDeck . lines =<< getContents

-- accumulate total # of moves, print it and output game solutions along the way
announce :: [Solution] -> IO ()
announce sols = print =<< foldM accumTotal 0 sols
  where
  accumTotal acc (deck, mvs) = do 
    let l = length mvs
    putStrLn $ "Playing Deck: " ++ deck
    putStrLn $ "# of moves: " ++ show l
    putStrLn $ "Solution: " ++ show mvs
    return $ acc+l

-- find solutions by applying different strategies, hash functions and/or
-- forcing moves to foundation with a dfs in a given deck; pick best; optimize
solveDeck :: Deck -> IO Solution
solveDeck deck
  | not $ null first  = let !win = bestOf first  in return (deck, win)
  | not $ null second = let !win = bestOf second in return (deck, win)
  | otherwise         = return (deck, [])

  where
  first  = doDFS True  [hashA1, hashA2]
  second = doDFS False [hashC]

  startBrd = deal deck
  startGame = [(startBrd, [])]
  doDFS ff hshFn = filter (not.null) [dfs ff h s startGame | h<-hshFn,s<-[0..7]]
  bestOf = optimize . reverse . bfs startBrd . reverse
           . snd . minimum . map ((,)=<<length)

-- replace: i->j, [... !=j, !=k ...], j->k  with  (i->k|[]) : middle part 
optimize :: [Move] -> [Move]
optimize [] = [] 
optimize (m1@(f1,t1):mvs)
  | t1 < 12,
    (hd, (_,t2):tl) <- span ((/= t1).fst) mvs,
    all (\(f3,t3) -> f3 /= t2 && t3 /=t2 && f3/=t1 && t3/=t1) hd
    = if t2==f1 then optimize (hd ++ tl) else (f1,t2) : optimize (hd ++ tl)
  | otherwise = m1 : optimize mvs

-- breadth-first search with search space limited to boards found by dfs
bfs :: Board -> [Move] -> [Move]
bfs startBrd mvs = search bfOrder False hashB 0 [(startBrd,[])]
  where 
  bfOrder = \new old -> old ++ filter (\(b,_) -> S.member (hashB b) space) new
  space   = S.fromList $ map hashB $ scanl mvCard startBrd mvs

-- depth-first search with a given hash function and strategy
dfs :: Bool -> (Board -> Int) -> Strategy -> [Game] -> [Move]
dfs = search (++)

-- generic search function - search order is given via argument as a function
search :: ([Game]->[Game]->[Game]) -> Bool -> (Board->Int) -> Strategy -> [Game] -> [Move]
search order ff hashFn strat = search' S.empty
  where
  search' _ [] = []
  search' seen ((brd,mvs):games)
    | S.member hBrd seen = search' seen games                  --skip if seen
    | all ((==13).(brd@!)) idxFnd = mvs                        --solution found
    | otherwise = search' (S.insert hBrd seen) (order newGames games) --descend
    where
    hBrd = hashFn brd
    newGames = nextGames ff mvs brd strat

-- one step in search, return all valid games reachable within one step
nextGames :: Bool -> [Move] -> Board -> Strategy -> [Game]
nextGames ff mvs brd strat
  | ff, mv:_ <- fndMoves = [(mvCard brd mv, mv:mvs)]
  | otherwise            = mapMaybe checkMove allMoves

  where

  -- all possible from/to combinations except between freecells and only to
  -- first empty freecell
  allMoves = case (strat `mod` 4) of
    0 -> [(f,t) | f<-fList, t<-tList idxTbl,  f<8 || t<8 || t>11]
    1 -> [(f,t) | f<-fList, t<-tList idxTblR, f<8 || t<8 || t>11]
    2 -> [(f,t) | t<-tList idxTbl, f<-fList,  f<8 || t<8 || t>11]
    3 -> [(f,t) | t<-tList idxTblR, f<-fList, f<8 || t<8 || t>11]
    _ -> undefined

  -- two different strategies for "from" indices
  -- * first by minimum rank in cascade and then by length of cascade
  -- * by minimum rank only
  fList
    | strat>3 = L.sortOn ((\c->(minimum$map snd c,length c)).(brd!)) nonEmptyIdx
    | otherwise = L.sortOn (minimum . map snd . (brd!)) nonEmptyIdx
                               
  -- order of "to" indices is foundation before freecell before tableau
  -- * foundation only if moves to there are not forced 
  -- * foundation index is "12" for all suits, we'll unravel that later
  -- * only first empty freecell (if any)
  tList idxs = [12|not ff] ++ take 1 [i | i<-idxCell, null$brd!i] ++ idxs

  nonEmptyIdx = filter (not.null.(brd!)) idxFrom

  -- check whether a move is valid and if so play it and return the new game
  -- (wrapped in 'Just'). Otherwise return 'Nothing'.
  checkMove mv@(f,t)
    | t <=  7, fitsTbl = Just doTbl   -- to tableau
    | t >=  8, t <= 11 = Just doCell  -- to cell (always empty)
    | t == 12, fitsFnd = Just doFnd   -- to foundation
    | otherwise        = Nothing      -- invalid move

    where
    !cscdT = brd!t
    !(cardF@(suitF,rankF):cscdFs) = brd!f

    fitsTbl = case cscdT of
      []              -> True
      (suitT,rankT):_ -> rankT == rankF+1 && odd (suitF+suitT)

    fitsFnd = rankF == brd@!(12+suitF) + 1

    doTbl  = (brd // [(t,  cardF:cscdT), (f, cscdFs)], mv:mvs)
    doCell = (brd // [(t,  [cardF]),     (f, cscdFs)], mv:mvs)
    doFnd  = (brd // [(t', [cardF]), (f, cscdFs)], (f,t'):mvs)
      where t' = t+suitF  -- 'to' index needs to be adjusted when moving to fnd

  -- a list of all valid moves to the foundation
  fndMoves =[(f,12+s) | f<-nonEmptyIdx, let (s,r)=head$brd!f, r-1==brd@!(12+s)]
 
--
-- parsing and dealing decks
--

deal :: Deck -> Board
deal = foldl putCard emptyBoard . zip (cycle idxTbl) . map readCard . words
  where
  putCard brd (i,crd) = brd // [(i, crd : brd!i)]
  emptyBoard = -- init foundation with cards of rank 0 so that aces fit on them
    foldl (\b i -> putCard b (i+12, (i,0))) (V.replicate 16 []) [0..3]

readCard :: String -> Card
readCard ['1','0',s] | Just j <- L.elemIndex s "DSHC"           = (j,10)
readCard [r,s]       | Just i <- L.elemIndex r " A23456789 JQK"
                     , Just j <- L.elemIndex s "DSHC"           = (j,i)
readCard _ = error "parse: invalid deck"

--
-- hash functions
--

hashA1, hashA2, hashC, hashB :: Board -> Int

hashA1  b = foldl (\h r -> h*16+r)  c $ map (b@!) idxFnd
  where c = foldl (\h l -> h*32+l)  0 $ L.sort $ map (length.(b!)) idxTbl

hashA2  b = foldl (\h r -> h*16+r)  c $ map (b@!) idxFnd
  where c = foldl (\h l -> h*32+l)  0 $ map (length.(b!)) idxTbl

hashC   b = foldl (\h s->h*26633+s) 1 $ L.sort $ map (hCscd.(b!)) $ idxTbl++idxFnd
  where hCscd = foldl (\v (s,r) -> (v*26633+s)*94291+r) 1

hashB = snd . V.foldl (\(i,h) c -> (i+1, (h*94291+hCscd c)*26633+i)) (2,1)
  where hCscd = foldl (\v (i,(s,r)) -> ((v*26633+s)*94291+r)*i) 1 . zip [2..]

The list of games is read via stdin. For each game the output is a pair of the number of moves and a list of moves as (from,to) pairs, where both 'from' and 'to' are indices of board positions. 0 to 7 are the eight cascades, 8 to 11 the four free cells and 12 to 15 the four foundations. E.g.

Playing Deck: KS 8S 3C 9D QS 4D JD QH 5C 10H 5D 10C 4H 3D 7H AD KC 6S 2S 8D AH 7C QD 6C 7S KH 8C 6H 2C 9C JH KD 4S 5S AC 10S JS 3S 9S 5H AS 4C 8H QC 6D 2H JC 10D 7D 2D 3H 9H
Solution: (85,[(0,8),(0,13),(2,9),(2,10),(2,15),(4,11),(7,6),(2,3),(2,13),(9,0),(4,9),(4,15),(4,14),(5,14),(0,14),(4,14),(5,13),(0,13),(7,14),(5,6),(11,5),(1,11),(5,0),(1,2),(0,5),(1,13),(5,0),(8,3),(7,8),(7,3),(7,12),(11,12),(2,11),(2,3),(2,15),(11,15),(5,11),(5,12),(5,12),(3,12),(0,12),(0,5),(0,2),(0,15),(3,15),(3,12),(11,15),(3,15),(6,15),(1,11),(1,13),(5,13),(3,5),(9,7),(3,9),(6,7),(1,6),(1,13),(3,1),(3,14),(3,12),(3,15),(3,12),(7,12),(6,7),(6,15),(6,13),(1,13),(6,4),(6,3),(6,14),(6,12),(3,12),(8,12),(10,14),(5,14),(7,14),(4,14),(7,13),(4,13),(0,13),(7,14),(9,15),(2,15),(11,14)])

At the end the total number of moves is printed.

How it works: The basic approach is a depth first search. As the quality of the search (both number of moves and search time) heavily depends on the search order, I try several orders concurrently and pick the result that finishes first:

That's four different orders (or strategies as I call them) in combination. Source order is the same for all strategies: sorted by minimum rank of all cards in the respective cascade/freecell. There's also autoplay, i.e. if a card can safely be placed in the foundation it's the only move in this situation. It turns out that a greedy autoplay leads to slightly better results, so I autoplay up to two additional ranks (e.g. autoplay 8s even if 5s of opposite color are still around).

However, all this is not good enough (5 games do not finish within reasonable time; about 14.7M moves for the rest), but I had a lucky find: somehow you have to keep track of the boards visited so far to prevent infinite loops during the search. The above method uses a hash which is calculated by rolling through the cascades and including suit and rank of all the cards along the way. Now we are just hashing the length of each cascade plus the top foundation cards (i.e. two boards result in the same hash if (and only if) the foundations are equal and all cascades in order have pairwise the same length). Yes, we do get a lot of collisions but they restrict the search space at pretty good spots and lead to far fewer moves in far less time. In fact, the search is so fast that we can afford to finish all four strategies and pick the best result. A similar hash function where for collision the matching length of a cascade can be anywhere in the tableau and not necessarily at the same index produces even better results - at least on average. Now we can try 8 variants (2 fast hash function with 4 strategies each) and pick the best result. Note: not all variants can solve every game but just one success is enough to get a result. There are 11 games (including the unsolvable #11982) which none of the variants can solve. In these cases I switch back to the slow hash function and pick the fastest result.

Using 4 cores on my laptop this solves all games in about 1.5h and a total of 4.98M moves.

Remarks

Update

Yet another strategy (sorting 'from' indices by length of cascade as a second criterion after minimal rank) - now a total of 16 variants per deck - brings the score down by 600k. Replacing greedy autoplay by forcing moves to the foundation whenever possible saves only 30k moves but also reduces the running time, so I take it. This leaves us with 10 unsolvable decks. However, all, except of course #11982, can be solved with a different hash function and autoplay/forcing disabled. No need for letting strategies race against each other anymore.

So far we've found a solution for each deck, but they have a lot of unnecessary moves. We can optimize a given solution by

The overall running time went down to 1:20h despite of twice as much strategies mostly because of making better use of parallelism and to a lesser extend because of removing autoplay.

The output format changed to

Playing Deck: 7C 5C 10S 8C 9H 7H 5S 4D 2C 5D 4C 10C 3D 2D AD JS 3H 9C 8D QS 6D 8S QC KS 2S 10H JC 6C 9S 6S JH AS AH 8H JD KH 7D KC QH QD 10D 3C 4S 9D 5H 3S 6H 4H AC 7S 2H KD
# of moves: 72
Solution: [(0,15),(0,8),(0,14),(2,14),(6,9),(6,10),(6,11),(6,3),(6,12),(7,6),(5,6),(7,5),(7,13),(0,13),(0,14),(0,15),(6,13),(2,13),(6,14),(4,14),(6,13),(9,14),(5,9),(5,6),(5,13),(1,13),(1,15),(5,13),(5,12),(5,14),(1,14),(4,5),(4,13),(4,0),(4,12),(4,14),(1,14),(11,14),(10,14),(2,10),(2,11),(2,4),(2,15),(2,13),(7,2),(7,13),(7,12),(1,7),(1,12),(0,12),(1,15),(5,12),(4,12),(3,5),(3,4),(3,12),(3,14),(3,15),(0,15),(3,13),(2,13),(8,12),(10,12),(9,12),(4,12),(3,8),(3,15),(7,15),(8,15),(11,15),(5,15),(6,15)]

C 64,643 bytes, Score: ~6.5 million

The following Stack Snippet (courtesy of Mego) outputs all of the code as a single standalone C file:

$("#a").text(pako.inflate(atob('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'), {to: 'string'}));
<script src="https://cdn.rawgit.com/nodeca/pako/master/dist/pako.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="a">
  
</pre>

Download the original source here. Use GCC and run make then using the guideline in the readme.

My formatting is bad (all the different files are in one code block) and this could be golfed more (12k bytes tho). Any help would be loved!

Some of the code is not mine. I used it from a un-copyrighted source. I however fixed the input/output method to be within the challenge (a long task since I am horrible at C (5ish hours)). I also had to re-write much of the code and debug everything. Many thanks to my Dad for helping out and being a rubber duck (and pointing out my memory management errors) and for everyone on TNB who dealt with my angry rants about segfaults and C.