aboutsummaryrefslogtreecommitdiff
path: root/challenge-075/jeongoon/haskell/JCombinations.hs
blob: 07456e689cbc849bd701c173a5dc937473aac86f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
module JCombinations
  ( combinationsIndex
  ) where

combinationsIndex :: Int -> Int -> [[Int]]
combinationsIndex n m -- return always sorted members and sorted list
  | m < n = []
  | otherwise =
    --       acc         room               nextId to move
    impli [[0 .. (n-1)]] (replicate n (m-n)) (n-1)
    where
      incrAt idx list = take idx list
                        ++ ((list !! idx) +1) : drop (idx+1) list
      dcrAt idx list  = take idx list
                        ++ ((list !! idx) -1) : drop (idx+1) list
      impli acc roomLs nextCsr =
        if roomLs !! nextCsr > 0 -- still current cursor is movable
        then impli (acc ++ [newPosLs]) (dcrAt nextCsr roomLs) nextCsr
        else -- no more room to move
          -- find the next element available to move
          case (pointNextCsr nextCsr) of
            Nothing    -> acc  -- if we cannot move any of them which means
                              -- we found all cases.
            Just newCsr ->     -- move all cursors
                              -- and try to move last cursor next time
              impli ( acc ++ [updatePosLsFrom newCsr] )
                    (updateRoomFrom newCsr) (n-1)
          where
            posLs    = last acc
            newPosLs = (incrAt nextCsr posLs)

            updatePosLsFrom fromCsr = -- move all cursors
              take (fromCsr) posLs    -- keep until fromCsr
              -- and reset others to leftmost part of the elements
              ++ take (n -fromCsr) [ ((posLs !! fromCsr)+1) .. ]
            updateRoomFrom fromCsr =
              take (fromCsr) roomLs
              -- reduce each room by one
              ++ replicate (n -fromCsr) ((roomLs !! fromCsr) -1)

            pointNextCsr curcsr
              | curcsr == 0 = Nothing
              | otherwise  = if roomLs !! nxtcsr > 0 then Just nxtcsr
                             else pointNextCsr nxtcsr
              where nxtcsr = curcsr - 1