challenge 箱詰めパズルの判定

以下の積み木のうち4つを、
重複を含めてランダムに選びます。
このとき、それらを4×4の箱に
詰められるかどうかを判定してください。

1.
■■■■

2.
■■
■■

3.
■■■
 ■

4.
■■■
■

5.
■■
 ■■

例えば、{ 1, 1, 1, 1 }, { 2, 2, 2, 2 } は箱につめることができますが、
{ 1, 2, 2, 3 } は箱につめることができません。

余力のある方は、以下の値を求めてみてください。
・箱につめることができる積み木の組み合わせの総数
・上記総数を、異なる詰め方の個数別にカウント
 (箱の回転・裏返しで一致するものは同一視します)

Posted feedbacks - Nested

Flatten Hidden

最近 Ruby を書いていなかったので、復習がてら。余力は残っていない(汗;)ので、箱にピッタリつめられるかの判定のみ。しかしこのやり方だと、組み合わせ総数を求められるように改造するのは、難しそうな気がする…。

  • [I,I,I,I] #=> true
  • [O,O,O,O] #=> true
  • [I,O,O,T] #=> false
  • [L,Z,L,Z] #=> true
  • [I,Z,Z,Z] #=> false

※1をIミノ、2をOミノ、3をTミノ、4をLミノ、5をZミノと表記しています。

 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class QuadraticArray < Array
  def col_size
    return self[0].length
  end
  def row_size
    return self.length
  end
  def each_elem(&fn)
    0.upto(row_size-1) do |i|
      0.upto(col_size-1) do |j|
        fn.call(i,j)
      end
    end
  end
end

class Mino < QuadraticArray
  def rot()
    res = Mino.new(col_size){Array.new(row_size, 0)}
    each_elem {|i, j| res[j][row_size - i - 1] = self[i][j] }
    return res
  end
end

I = Mino[[1,1,1,1]]
O = Mino[[1,1],[1,1]]
L = Mino[[1,1,1],[1,0,0]]
T = Mino[[1,1,1],[0,1,0]]
Z = Mino[[1,1,0],[0,1,1]]

def mirrors(*minos)
  minos.clone.each {|mino| minos << mino.reverse }
  return minos
end

def rotations(mino)
  minos = [mino]
  3.times do minos << minos[-1].rot end
  return minos
end

BasicMinos = Hash[]
BasicMinos[I] = [I, I.rot]
BasicMinos[O] = [O]
BasicMinos[T] = rotations(T)
BasicMinos[L] = mirrors(*rotations(L)) 
BasicMinos[Z] = mirrors(Z, Z.rot)

class Plate < QuadraticArray
  def clone
    Plate.new(map {|e| e.clone})
  end
  def isAbleToArrayMinos(minos)
    mino = minos.pop
    each_elem do |y, x| BasicMinos[mino].each do |m|
        plate = self.clone
        if plate.isAbleToPutMino(m, y, x) then
          if minos.length == 0 then 
            return true if plate.isCompleted
          elsif plate.isAbleToArrayMinos(minos.clone) then
            return true 
          end
        end
    end end
    return false
  end
  def isAbleToPutMino(mino, i, j)
    if (mino.row_size + i > row_size) then return false
    elsif (mino.col_size + j > col_size) then return false end
    mino.each_elem do |y, x|
      return false if ((self[i+y][j+x] += mino[y][x]) == 2)
    end
    return true
  end
  def isCompleted
    each_elem {|i, j| if not (self[i][j] == 1) then return false end}
    return true
  end
end

EmptyPlate = Plate.new(4){Array.new(4,0)}

p EmptyPlate.isAbleToArrayMinos([I,I,I,I])
p EmptyPlate.isAbleToArrayMinos([O,O,O,O])
p EmptyPlate.isAbleToArrayMinos([I,O,O,T])
p EmptyPlate.isAbleToArrayMinos([L,Z,L,Z])
p EmptyPlate.isAbleToArrayMinos([I,Z,Z,Z])

Scheme(Gauche)です。

積み木は、(行 . 列)という整数のペアで表しています。

探索は、DFSで、回転、反転をした積み木をテーブルのすべての位置に置くことを順に試しています。

# Schemeの練習として書いてみました。あまりきれいに書けている気がしません。

  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
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(use util.match)
(use gauche.array)
(use srfi-1)
(use srfi-42)

(define height 4)
(define width 4)

(define mino-images
  '(("****")

    ("**"
     "**")

    ("***"
     " * ")

    ("***"
     "*  ")

    ("** "
     " **")))


;; string list -> point list
(define (mino-image->points mino-image)
  (append-map (lambda (row s)
                (filter-map (lambda (col)
                              ;; asterisk -> (row . col)
                              (match (string-ref s col)
                                [#\*    (cons row col)]
                                [#\space #f]))
                            (iota (string-length s) 0)))
              (iota (length mino-image) 0)
              mino-image))

(define (rotate mino) (map (match-lambda [(row . col) (cons col (- row))]) mino))
(define (flip mino) (map (match-lambda [(row . col) (cons col row)]) mino))

;; rotate, flip and delete duplicates
(define (mino-patterns mino)
  (define (rotate-n mino n)
    (let f ([i 0] [m mino] [l '()])
      (if (< i n) (f (+ i 1) (rotate m) (cons m l)) l)))
  (delete-duplicates (append (rotate-n mino 4) (rotate-n (flip mino) 4))))

;;; Table

(define (make-tbl row col) (make-array (shape 0 row 0 col) #f))
(define tbl-ref array-ref)
(define tbl-set  (cut array-set! <> <> <> #t))
(define tbl-unset  (cut array-set! <> <> <> #f))

(define (tbl-encode tbl)
  (fold (lambda (c n) (match c [#t (+ (* 2 n) 1)] [#f (* 2 n)]))
        0
        (array->list tbl)))

(define (tbl-put tbl mino row col)
  (define (valid? tbl mino row col)
    (every (match-lambda [(d-row . d-col)
                          (let ([r (+ row d-row)] [c (+ col d-col)])
                            (and (>= r 0) (< r height)
                                 (>= c 0) (< c width)
                                 (not (tbl-ref tbl r c))))])
           mino))
  (and (valid? tbl mino row col)
      (let ()
        (for-each (match-lambda [(d-row . d-col)
                                 (tbl-set tbl (+ row d-row) (+ col d-col))])
                  mino)
        #t)))
(define (tbl-unput-mino tbl mino row col)
  (for-each (match-lambda [(d-row . d-col)
                           (tbl-unset tbl (+ row d-row) (+ col d-col))])
            mino))

;; for debug
(define (tbl-dump tbl)
  (format #t "--~%")
  (do-ec (: row 0 height)
         (begin
           (do-ec (: col 0 width)
                  (format #t "~a" (if (tbl-ref tbl row col) #\* #\space)))
           (format #t "~%"))))

(define (dfs ht tbl mino-list)
  (or (null? mino-list)
      (let* ([e (tbl-encode tbl)])
        (and (not (hash-table-get ht e #f))
            (let ()
              (hash-table-put! ht e #t)
              (and (not (null? mino-list))
                   (any?-ec (:list m (mino-patterns (car mino-list)))
                            (: row 0 height) (: col 0 width)
                            (if (tbl-put tbl m row col)
                                (let1 r (dfs ht tbl (cdr mino-list))
                                  (tbl-unput-mino tbl m row col)
                                  r)
                                #f))))))))

(define all-mino-list (map mino-image->points mino-images))

(define (can-put-minos? ids)
  (format #t "~a : ~a~%"
          ids
          (if (dfs (make-hash-table) (make-tbl height width)
                   (map (lambda (id) (ref all-mino-list (- id 1))) ids))
              "ok"
              "ng")))

(define (main args)
  (can-put-minos? '(1 1 1 1))
  (can-put-minos? '(2 2 2 2))
  (can-put-minos? '(3 3 3 3))
  (can-put-minos? '(4 4 4 4))
  (can-put-minos? '(5 5 5 5))
  (can-put-minos? '(1 2 2 3))
  (can-put-minos? '(1 4 4 5))
  0) ; exit code

dfs手続きが非常に見づらかったので書き直してみました。

手続き型言語のようなコードなので、継続を使って脱出すると見通しがだいぶ良くなります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(define (dfs ht tbl mino-list)
  (let/cc return
    (if (null? mino-list) (return #t))
    (let ([e (tbl-encode tbl)])
      (if (hash-table-get ht e #f) (return #f))
      (hash-table-put! ht e #t)
      (for-each (lambda (m)
                  (do-ec (: row 0 height) (: col 0 width)
                    (when (tbl-put tbl m row col)
                      (if (dfs ht tbl (cdr mino-list)) (return #t))
                      (tbl-unput-mino tbl m row col))))
                (mino-patterns (car mino-list)))
      #f)))
二次元配列とか使ってないです。
整数とビット演算だけでゴリゴリ処理してます。
Cに移植しようかどうしようか考え中。
  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
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#coding:utf-8

import copy


class packField:
    @staticmethod
    def strToBitpattern(patternString):
        n = 0
        for s in patternString:
            if s == 'x':
                n |= 1
                n <<= 1
            elif s == '_':
                n <<= 1
            else:
                pass

        while n & 1 == 0:
            n >>= 1
        return n

    def __init__ (self):
        self.field = packField.strToBitpattern(
                '''
                xxxxxx
                x____x
                x____x
                x____x
                x____x
                xxxxxx
                ''')

        self.block = {}
        self.block['I'] = []
        self.block['O'] = []
        self.block['T'] = []
        self.block['L'] = []
        self.block['Z'] = []

        self.block['I'].append(
            packField.strToBitpattern(
            '''xxxx'''
            )
        )
        self.block['I'].append(
            packField.strToBitpattern(
                '''
                x_____
                x_____
                x_____
                x_____
                ''')
        )
        self.block['O'].append(
            packField.strToBitpattern(
                '''
                xx____
                xx____
                ''')
        )

        self.block['T'].append(
            packField.strToBitpattern(
                '''
                _x____
                xxx___
                ''')
        )
        self.block['T'].append(
            packField.strToBitpattern(
                '''
                xxx___
                _x____
                ''')
        )
        self.block['T'].append(
            packField.strToBitpattern(
                '''
                x_____
                xx____
                x_____
                ''')
        )
        self.block['T'].append(
            packField.strToBitpattern(
                '''
                _x____
                xx____
                _x____
                ''')
        )

        self.block['L'].append(
            packField.strToBitpattern(
                '''
                x_____
                x_____
                xx____
                ''')
        )

        self.block['L'].append(
            packField.strToBitpattern(
                '''
                _x____
                _x____
                xx____
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                xx____
                _x____
                _x____
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                xx____
                x_____
                x_____
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                xxx___
                x_____
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                xxx___
                __x___
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                x_____
                xxx___
                ''')
        )
        self.block['L'].append(
            packField.strToBitpattern(
                '''
                __x___
                xxx___
                ''')

        )
        self.block['Z'].append(
            packField.strToBitpattern(
                '''
                xx____
                _xx___
                ''')
        )
        self.block['Z'].append(
            packField.strToBitpattern(
                '''
                _xx___
                xx____
                ''')
        )
        self.block['Z'].append(
            packField.strToBitpattern(
                '''
                x_____
                xx____
                _x____
                ''')
        )
        self.block['Z'].append(
            packField.strToBitpattern(
                '''
                _x____
                xx____
                x_____
                ''')
        )

        print self.field
        print self.block

    def solve(self, blocks, field = None):
        if blocks == []:
            return True

        if field == None:
            field = self.field

        for pattern in self.block[blocks[0]]:
            while pattern < field:
                if field & pattern == 0:
                    field ^= pattern
                    result = self.solve(blocks[1:], field)
                    if result == True:
                        return True
                    field ^= pattern
                pattern <<= 1
        return False




if __name__ == "__main__":
    p = packField()
    print 'IIII', p.solve(['I','I','I','I',])
    print 'OOOO', p.solve(['O','O','O','O',])
    print 'IOOT', p.solve(['I','O','O','T',])
    print 'LZLZ', p.solve(['L','Z','L','Z',])
    print 'IZZZ', p.solve(['I','Z','Z','Z',])

import copyは不要ですね。整数演算してなかったときの名残です。

 先に全数検索するコードを書いて、後でブロックが置けるか調べるコードを追加したら、
グチャグチャになってしまいました。テトリスと違って裏返しもカウントしてます。

<実行結果>
*Main> main
<1111>
[0,0,0,0]
[0,0,0,0]
[0,0,0,0]
[1,1,1,1]

[0,0,0,0]
[0,0,0,0]
[1,1,1,1]
[0,0,0,0]

[0,0,0,0]
[1,1,1,1]
[0,0,0,0]
[0,0,0,0]

[1,1,1,1]
[0,0,0,0]
[0,0,0,0]
[0,0,0,0]
...
<4455>
[0,0,0,0]
[0,0,0,0]
[0,1,1,0]
[0,0,1,1]

[0,0,0,0]
[1,0,0,0]
[1,0,0,0]
[1,1,0,0]

[0,0,1,1]
[0,0,0,1]
[0,0,0,1]
[0,0,0,0]

[1,1,0,0]
[0,1,1,0]
[0,0,0,0]
[0,0,0,0]

Number of solutions: 70

Can put {1,1,2,2}? : True
Can put {2,3,4,5}? : False
Can put {4,4,5,5}? : True
 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import Data.List
import Data.Maybe(isJust, mapMaybe)
import Data.Tree(unfoldTree, levels)

initialState = replicate 16 0 -- 空箱
b1 = [[1, 1, 1, 1]]
b2 = [[1, 1], [1, 1]]
b3 = [[1, 1, 1], [0, 1, 0]]
b4 = [[1, 1, 1], [1, 0, 0]]
b5 = [[1, 1, 0], [0, 1, 1]]

packBox [] = []
packBox b  = [take 4 b] ++ (packBox $ drop 4 b)
unpackBox b = concat b

rotate b d = case (d `mod` 360 + 360) `mod` 360 of
  0 -> b
  90 -> reverse $ transpose b
  180 -> flip rotate  90 $ rotate b 90
  270 -> flip rotate 180 $ rotate b 90

normalize b = unfoldr f (0, b) --箱の大きさに正規化
  where f (4, _     ) = Nothing
        f (i, (x:xs)) = Just (take 4 $ x ++ (repeat 0), (i + 1, xs))
        f (i, _     ) = Just ([0, 0, 0, 0], (i + 1, []))

horizontalPatterns b = if any (/= 0) $ b' !! 3 then [b]
                       else b : (horizontalPatterns $ transpose $ [last b'] ++ (take 3 b'))
  where b' = transpose b

verticalPatterns   b = if any (/= 0) $ b !! 3 then [b]
                       else b : (verticalPatterns $ [last b] ++ (take 3 b))

-- 指定されたブロックの全ての配置パターンを生成
generatePatterns b = concatMap verticalPatterns $ concatMap horizontalPatterns ps
  where ps = nub
             $ (normalize $ reverse b) : (normalize $ reverse $ rotate b 90) -- 反転パターン
             : (map (\d -> normalize $ rotate b d) [0, 90, 180, 270])        -- 回転パターン

listOfPatterns = map ((map unpackBox) . generatePatterns) [b1, b2, b3, b4, b5]

listOfBlocks ps = sort $ f ps listOfPatterns
  where f []       _           = ""
        f _        []          = ""
        f pps'@(p':ps') (x:xs) = case find (== p') x of
                              Just i -> (show (length listOfPatterns - length xs)) ++ (f ps' listOfPatterns)
                              otherwise -> f pps' xs

solutions = sortBy (\a b -> compare (fst a) (fst b)) $ map (\x -> (listOfBlocks x, x))
            $ nub $ map (sort . snd) $ flip (!!) 4 $ levels $ unfoldTree f (initialState, [])
  where f x@(b, ps) = (x, mapMaybe g $ concat listOfPatterns)
          where g p = if any (1 <) b' then Nothing else Just (b', p : ps)
                  where b' = zipWith (+) b p

solve s = let s' = sort s in
            if isJust $ find (\x -> s' == (fst x)) solutions then True else False

main = do mapM_ f solutions
          putStrLn $ "Number of solutions: " ++ (show $ length solutions)
          putStrLn ""
          putStr "Can put {1,1,2,2}? : "
          print $ solve "1122"
          putStr "Can put {2,3,4,5}? : "
          print $ solve "2345"
          putStr "Can put {4,4,5,5}? : "
          print $ solve "4455"
  where f x = do putStrLn $ "<" ++ (fst x) ++ ">"
                 mapM_ g $ map packBox $ snd x
          where g x' = do mapM_ print x'
                          putStrLn ""
 しまった。反転パターンを回転させてなかった。

generatePatterns b = concatMap verticalPatterns $ concatMap horizontalPatterns ps
  where ps = nub
             $ (map (\d -> normalize $ rotate (reverse b) d) [0, 90, 180, 270])  -- 反転パターン
             ++ (map (\d -> normalize $ rotate b d) [0, 90, 180, 270])           -- 回転パターン

<実行結果>
Number of solutions: 117

 なんか、怪しい数字になってしまった...
補題だけに集中してみた。

<実行結果>
Combinations of Blocks: 12
1111: 1
1122: 2
1144: 2
1244: 3
1334: 2
1445: 2
2222: 1
2244: 1
3333: 1
3345: 1
4444: 2
4455: 1
 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import Data.List
import Data.Maybe(mapMaybe)
import Data.Tree(unfoldTree, levels)

emptyBox = replicate 16 0
b1 = [[1, 1, 1, 1]]
b2 = [[1, 1], [1, 1]]
b3 = [[1, 1, 1], [0, 1, 0]]
b4 = [[1, 1, 1], [1, 0, 0]]
b5 = [[1, 1, 0], [0, 1, 1]]

packBlock   [] = []
packBlock   b  = [take 4 b] ++ (packBlock $ drop 4 b)
unpackBlock b  = concat b

rotateBlock d b = f d b
  where f d = case (d `mod` 360 + 360) `mod` 360 of
                0   -> id
                90  -> reverse . transpose
                180 -> rotateBlock  90 . rotateBlock 90
                270 -> rotateBlock 180 . rotateBlock 90

normalizeBlock b = unfoldr f (0, b)
  where f (4, _     ) = Nothing
        f (i, (x:xs)) = Just (take 4 $ x ++ (repeat 0), (i + 1, xs))
        f (i, _     ) = Just (replicate 4 0, (i + 1, []))

rotatePattern b = unfoldr f b
  where f b'
          | null b' = Nothing
          | any (/= 0) $ last b' = Just (b', [])
          | otherwise = Just (b', (last b') : (take 3 b'))

generatePatterns b = nub $ [] ++ (map (f (reverse b)) l) ++ (map (f b) l)
          where l = [0, 90, 180, 270]
                f b d = normalizeBlock $ rotateBlock d b

allPatterns = map ((map unpackBlock) . f) [b1, b2, b3, b4, b5]
  where f = concatMap rotatePattern . concatMap (map transpose . rotatePattern . transpose)
            . generatePatterns

patternsToBlocks ps = sort $ f ps allPatterns
  where f []       _           = ""
        f pps'@(p':ps') (x:xs) = case find (== p') x of
                              Just _ -> (show (length allPatterns - length xs)) ++ (f ps' allPatterns)
                              otherwise -> f pps' xs

rawSolutions = map (sort. snd) $ levels (unfoldTree f (emptyBox, [])) !! 4
  where f x@(b, ps) = (x, mapMaybe g $ concat allPatterns)
          where g p = if any (1 <) b' then Nothing else Just (b', p : ps)
                  where b' = zipWith (+) b p

solutions = map (\x -> (patternsToBlocks (head x), x))
            $ filterPatterns $ groupByPatterns $ nub rawSolutions
              where groupByPatterns = f . g
                      where f = groupBy (\x1 x2 -> (patternsToBlocks x1) == (patternsToBlocks x2))
                            g = sortBy  (\x1 x2 -> compare (patternsToBlocks x1) (patternsToBlocks x2))
                    filterPatterns  = map f
                      where f [] = []
                            f (x:xs) = x : (f $ filter g xs)
                              where g p =  h x /= h p
                                    h = sort . concatMap (generatePatterns . packBlock)

printResult = do
    -- 箱につめることができる積み木の組み合わせの総数
    putStrLn $ "Combinations of Blocks: "   ++ (show $ length solutions)

    -- 上記総数を、異なる詰め方の個数別にカウント
    flip mapM_ solutions $ \x -> putStrLn (fst x ++ ": " ++ (show $ length $ snd x))

    -- 組み合わせをテキストで出力
    p solutions

  where p = mapM_ f
        f x = putStrLn "\n---------" >> putStrLn ("<" ++ (fst x) ++ ">") >> mapM_ g (snd x)
        g x = putStrLn "---------\n" >> mapM_ h (map packBlock x)
        h x = mapM_ print x >> putStrLn ""

main = printResult
 解の同一視処理で、面倒なので反転、回転させた集合全体で比較していたのですが、それでは
不十分で漏れがありました。結局、地道に処理することに...。すいません。出直してきます...

Combinations of Blocks: 12
1111: 1
1122: 2
1144: 2
1244: 4
1334: 2
1445: 3
2222: 1
2244: 1
3333: 1
3345: 1
4444: 3
4455: 1

generatePatterns b = (map (f (reverse b)) l) ++ (map (f b) l)
          where l = [0, 90, 180, 270]
                f b d = normalizeBlock $ rotateBlock d b

allPatterns = map ((map unpackBlock) . f) [b1, b2, b3, b4, b5]
  where f = concatMap rotatePattern . concatMap (map transpose . rotatePattern . transpose)
            . nub . generatePatterns

solutions = map (\x -> (patternsToBlocks (head x), x))
...
                    filterPatterns  = map f
                      where f [] = []
                            f (x:xs) = x : (f $ filter g xs)
                              where g p =  all (/= x) $ h p
                                    h = map sort . transpose . map (map unpackBlock . generatePatterns . packBlock)

ごちゃごちゃと長くなってしまったが、答えは出たっぽいので投稿。組み合わせ数:11、重複の無い詰め方数:15

  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
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace hakodume
{
    class Program
    {
        static void Main(string[] args)
        {
            var a1 = new Mino(new int[,]{
                            {1,1,1,1}
                        }, 1);
            var a2 = new Mino(new int[,]{
                            {1},
                            {1},
                            {1},
                            {1}
                        }, 1);

            var b = new Mino(new int[,]{
                            {2,2},
                            {2,2}
                       }, 2);

            var c1 = new Mino(new int[,]{
                            {3,3,3},
                            {0,3,0}
                        },3);
            var c2 = new Mino(new int[,]{
                            {3,0},
                            {3,3},
                            {3,0}
                        },3);
            var c3 = new Mino(new int[,]{
                            {0,3},
                            {3,3},
                            {0,3}
                        },3);
            var c4 = new Mino(new int[,]{
                            {0,3,0},
                            {3,3,3}
                        },3);
            var d1 = new Mino(new int[,]{
                            {4,4,4},
                            {4,0,0}
                        },4);
            var d2 = new Mino(new int[,]{
                            {4,4},
                            {0,4},
                            {0,4}
                        },4);
            var d3 = new Mino(new int[,]{
                            {0,0,4},
                            {4,4,4}
                        },4);
            var d4 = new Mino(new int[,]{
                            {4,0},
                            {4,0},
                            {4,4}
                        },4);
            var e1 = new Mino(new int[,]{
                            {5,5,0},
                            {0,5,5}
                        },5);
            var e2 = new Mino(new int[,]{
                            {0,5},
                            {5,5},
                            {5,0}
                        },5);

            var minos = new List<Mino> { a1, a2, b, c1, c2, c3, c4, d1, d2, d3, d4, e1, e2 };

            Box box = new Box(minos);

            box.Solve(1);
            box.DisplayAll();
        }

        class Mino
        {
            private int[,] mino;

            public Mino( int[,] mino, int pattern )
            {
                this.mino = mino;
                this.Pattern = pattern;
            }

            public int RowLength { get { return mino.GetLength(0); } }
            public int ColomnLength { get { return mino.GetLength(1); } }
            public int Pattern { get; private set; }
            public int GetValue(int row, int col)
            {
                return mino[row, col];
            }
        }

        class Box
        {
            private int[,] box = {
                           {0,0,0,0},
                           {0,0,0,0},
                           {0,0,0,0},
                           {0,0,0,0}
                       };
            private int RowLength { get { return box.GetLength(0); } }
            private int ColomnLength { get { return box.GetLength(1); } }
            private int GetValue(int row, int col)
            {
                return box[row, col];
            }
            private void SetValue(int row, int col, int value)
            {
                box[row, col] = value;
            }

            private List<Mino> minos;

            public Box(List<Mino> minos)
            {
                this.minos = minos;
            }

            private List<int[,]> boxes = new List<int[,]>();
            private int[] pattern = new int[4];
            private List<int[]> patterns = new List<int[]>();

            public void DisplayAll()
            {
                foreach (var b in boxes)
                {
                    for (int i = 0; i < RowLength; ++i)
                    {
                        for (int j = 0; j < ColomnLength; ++j)
                        {
                            Console.Write("{0}", b[i, j]);
                        }
                        Console.WriteLine();
                    }
                    Console.WriteLine();
                }

                foreach (var p in patterns)
                {
                    foreach (var i in p)
                    {
                        Console.Write(i);
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("組み合わせ積み木のパターン数:{0}", patterns.Count);
                Console.WriteLine("重複のない詰め方の数:{0}", boxes.Count);
            }
            
            private void Record()
            {
                var pattern_sorted = pattern.Clone() as int[];
                Array.Sort<int>(pattern_sorted);

                if (!ExistPatternMino(pattern_sorted))
                {
                    patterns.Add(pattern_sorted);
                }

                if (!ExistPatternBox(box))
                {
                    boxes.Add(box.Clone() as int[,]);
                }
            }

            private bool ExistPatternMino(int[] pattern)
            {
                return patterns.Any( p => EqualArray( p, pattern ) );
            }

            private bool ExistPatternBox(int[,] box)
            {
                return boxes.Any(r => EqualBox(r, box)) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._90 ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._180 ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._270 ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._y ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._90y ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._180y ))) ||
                    boxes.Any(r => EqualBox(r, Rotate(box, Rotation._270y )));
            }

            private int[,] Rotate(int[,] box_s, Rotation rotation)
            {
                int[,] box_d = {
                           {0,0,0,0},
                           {0,0,0,0},
                           {0,0,0,0},
                           {0,0,0,0}
                       };
                
                switch (rotation)
                {
                    case Rotation._90:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[3 - j, i] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._180:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[3 - i, 3 - j] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._270:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[j, 3 - i] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._y:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[3 - i, j] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._90y:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[j, i] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._180y:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[i, 3 - j] = box_s[i, j];
                            }
                        }
                        break;
                    case Rotation._270y:
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                box_d[3 - j, 3 - i] = box_s[i, j];
                            }
                        }
                        break;
                }

                return box_d;
            }

            private enum Rotation
            {
                _90,
                _180,
                _270,
                _y,
                _90y,
                _180y,
                _270y
            }

            private bool EqualBox(int[,] lhs, int[,] rhs)
            {
                return Enumerable.Range(0, lhs.GetLength(0)).All(i =>
                    Enumerable.Range(0, lhs.GetLength(1)).All(j =>
                        lhs[i, j] == rhs[i, j]
                    ));
            }

            private bool EqualArray(int[] lhs, int[] rhs)
            {
                return Enumerable.Range(0, lhs.Length).All(i => lhs[i] == rhs[i]);
            }

            private bool CanPut(int row, int col, Mino mino)
            {
                if (row + mino.RowLength > RowLength ||    col + mino.ColomnLength > ColomnLength)
                {
                    return false;
                }

                return Enumerable.Range(0, mino.RowLength).Any(i =>
                    Enumerable.Range(0, mino.ColomnLength).Any(j =>
                        GetValue(row + i, col + j) != 0 && mino.GetValue(i, j) != 0)) ? false : true;
            }

            private void Put(int row, int col, Mino mino, int n)
            {
                for (int i = 0; i < mino.RowLength; i++)
                {
                    for (int j = 0; j < mino.ColomnLength; j++)
                    {
                        if (mino.GetValue(i, j) != 0)
                        {
                            SetValue(row+i, col+j, mino.GetValue(i, j));
                        }
                    }
                }
                pattern[n - 1] = mino.Pattern;
            }

            private void Remove(int row, int col, Mino mino)
            {
                for (int i = 0; i < mino.RowLength; i++)
                {
                    for (int j = 0; j < mino.ColomnLength; j++)
                    {
                        if (mino.GetValue(i, j) != 0)
                        {
                            SetValue(row+i, col+j, 0);
                        }
                    }
                }
            }

            public void Solve(int n)
            {
                for (int row = 0; row < RowLength; row++)
                {
                    if (CheckFilledRow(row))
                    {
                        continue;
                    }

                    for (int col = 0; col < ColomnLength; col++)
                    {
                        if (CheckFilledColomn(col))
                        {
                            continue;
                        }

                        foreach (var mino in minos)
                        {
                            if (CanPut(row, col, mino))
                            {
                                Put(row, col, mino, n);

                                if (n != 4)
                                {
                                    Solve(n + 1);
                                }
                                else
                                {
                                    Record();
                                }
                                Remove(row, col, mino);
                            }
                        }

                        if (GetValue(row, col) == 0)
                        {
                            return;
                        }
                    }
                }
            }

            private bool CheckFilledRow(int row)
            {
                return Enumerable.Range(0, ColomnLength).All(col => GetValue(row, col) != 0);
            }
            private bool CheckFilledColomn(int col)
            {
                return Enumerable.Range(0, RowLength).All(row => GetValue(row, col) != 0);
            }
        }
    }
}

Squeak Smalltalk で。つめることができる組み合わせを列挙させてみました。ブロックは画素で表現し、4×4の領域を塗りつぶせる配置があるかで判断しています。

 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
46
47
48
49
50
51
52
53
| blocks extent rec results |

blocks := {
  Form extent: 4@1 fromArray: #(2r1111e28) offset: nil.
  Form extent: 2@2 fromArray: #(2r11e30 2r11e30) offset: nil.
  Form extent: 3@2 fromArray: #(2r111e29 2r010e29) offset: nil.
  Form extent: 3@2 fromArray: #(2r111e29 2r100e29) offset: nil.
  Form extent: 3@2 fromArray: #(2r110e29 2r011e29) offset: nil}.
extent := 4@4.

blocks := blocks collect: [:ori |
  | specs |
  specs := Set new.
  #(0 90 180 270) do: [:angle |
    | rot |
    rot := (ori rotateBy: angle) trimBordersOfColor: Color white.
    specs add: {rot extent. rot bits}.
    rot := rot flipBy: #horizontal centerAt: 0@0.
    specs add: {rot extent. rot bits}].
    specs collect: [:spec | Form extent: spec first depth: 1 bits: spec second]].

results := Set new.
(1 to: 5) asDigitsToPower: 4 do: [:comb |
  comb isSorted ifTrue: [
    | box |
    comb printString displayAt: 0@0.
    box := Form extent: extent.
    rec := nil.
    rec := [:prevBox :rest |
      | trials currBox |
      rest ifEmpty: [results add: comb copy] ifNotEmpty: [
        trials := blocks at: rest first.
        trials do: [:currBlk |
        (0 to: 4 - currBlk width) do: [:xx | (0 to: 4 - currBlk height) do: [:yy | 
          currBlk displayOn: (currBox := prevBox deepCopy) at: xx@yy rule: Form paint.
          currBox primCountBits = (4 * (5 - rest size)) ifTrue: [
            rec copy fixTemps value: currBox value: rest allButFirst]]]]]].
    rec copy fixTemps value: box value: comb]].
^results asArray sort: [:a :b | (b - a detect: [:delta | delta abs > 0] ifNone: [0]) >= 0]

"=> #(
  #(1 1 1 1)
  #(1 1 2 2)
  #(1 1 4 4)
  #(1 2 4 4)
  #(1 3 3 4)
  #(1 4 4 5)
  #(2 2 2 2)
  #(2 2 4 4)
  #(3 3 3 3)
  #(3 3 4 5)
  #(4 4 4 4)
  #(4 4 5 5))
Explorerでは積み木の形が認識できませんでした。
地道な解法です。5の裏返しを認めない場合は、置き方の総数は99通り。
認めた場合は117通り。
どちらにしろ、組み合わせの総数は12通り、詰め方は22通りという結果となりました。
実行結果は次のようになります。

置き方の総数...99

[1; 1; 1; 1]
[1; 1; 2; 2]
[1; 1; 4; 4]
[1; 2; 4; 4]
[1; 3; 3; 4]
[1; 4; 4; 5]
[2; 2; 2; 2]
[2; 2; 4; 4]
[3; 3; 3; 3]
[3; 3; 4; 5]
[4; 4; 4; 4]
[4; 4; 5; 5]

組み合わせの総数...12

異なる詰め方の個数...22

[1; 1; 1; 1]

1|1|1|1
       
1|1|1|1
       
1|1|1|1
       
1|1|1|1


[1; 1; 2; 2]

1|2 2|1
       
1|2 2|1
  - -  
1|2 2|1
       
1|2 2|1


[1; 1; 2; 2]

2 2|2 2
       
2 2|2 2
- - - -
1 1 1 1
- - - -
1 1 1 1


[1; 1; 4; 4]

1|4 4|1
    -  
1|4|4|1
       
1|4|4|1
  -    
1|4 4|1


[1; 1; 4; 4]

4|4 4 4
  - -  
4 4 4|4
- - - -
1 1 1 1
- - - -
1 1 1 1


[1; 2; 4; 4]

4 4|2 2
  -    
4|4|2 2
    - -
4|4 4 4
- - - -
1 1 1 1


[1; 2; 4; 4]

4 4|4 4
  - -  
4|2 2|4
       
4|2 2|4
- - - -
1 1 1 1


[1; 2; 4; 4]

4 4 4|1
- -    
2 2|4|1
    -  
2 2|4|1
- -    
4 4 4|1


[1; 2; 4; 4]

4 4 4|4
- -    
2 2|4|4
    -  
2 2|4 4
- - - -
1 1 1 1


[1; 3; 3; 4]

3|4 4|1
  -    
3 3|4|1
  -    
3|3|4|1
-   -  
3 3 3|1


[1; 3; 3; 4]

4 4|3|1
  -    
4|3 3|1
  -    
4|3|3|1
-   -  
3 3 3|1


[1; 4; 4; 5]

4 4|5|1
  -    
4|5 5|1
    -  
4|5|4|1
- -    
4 4 4|1


[1; 4; 4; 5]

4 4|5|4
  -    
4|5 5|4
    -  
4|5|4 4
- - - -
1 1 1 1


[1; 4; 4; 5]

5 5|4 4
-   -  
4|5 5|4
  - -  
4 4 4|4
- - - -
1 1 1 1


[2; 2; 2; 2]

2 2|2 2
       
2 2|2 2
- - - -
2 2|2 2
       
2 2|2 2


[2; 2; 4; 4]

4|4 4 4
  - -  
4 4 4|4
- - - -
2 2|2 2
       
2 2|2 2


[3; 3; 3; 3]

3|3 3 3
  -   -
3 3|3|3
  - -  
3|3|3 3
-   -  
3 3 3|3


[3; 3; 4; 5]

5 5|4 4
-   -  
3|5 5|4
  - -  
3 3|3|4
  -   -
3|3 3 3


[4; 4; 4; 4]

4|4 4 4
  - -  
4 4 4|4
- - - -
4|4 4 4
  - -  
4 4 4|4


[4; 4; 4; 4]

4|4 4 4
  - -  
4 4 4|4
- - - -
4 4 4|4
  - -  
4|4 4 4


[4; 4; 4; 4]

4 4 4|4
- -    
4 4|4|4
  - -  
4|4|4 4
    - -
4|4 4 4


[4; 4; 5; 5]

5 5|4 4
-   -  
4|5 5|4
  - -  
4|5 5|4
  -   -
4 4|5 5
  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
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
let pieces = [|
        ((1,0),[|(0,0);(1,0);(2,0);(3,0)|]);((1,1),[|(0,0);(0,1);(0,2);(0,3)|]);
        ((2,0),[|(0,0);(1,0);(0,1);(1,1)|]);
        ((3,0),[|(0,0);(1,0);(2,0);(1,1)|]);((3,1),[|(0,0);(0,1);(1,1);(0,2)|]);                       
        ((3,2),[|(0,0);(-1,1);(0,1);(1,1)|]);((3,3),[|(0,0);(-1,1);(0,1);(0,2)|]);                       
        ((4,0),[|(0,0);(1,0);(2,0);(0,1)|]);((4,1),[|(0,0);(1,0);(1,1);(1,2)|]);                       
        ((4,2),[|(0,0);(0,1);(0,2);(1,2)|]);((4,3),[|(0,0);(-2,1);(-1,1);(0,1)|]);
        ((4,4),[|(0,0);(1,0);(2,0);(2,1)|]);((4,5),[|(0,0);(1,0);(0,1);(0,2)|]);                       
        ((4,6),[|(0,0);(0,1);(1,1);(2,1)|]);((4,7),[|(0,0);(0,1);(-1,2);(0,2)|]);
        ((5,0),[|(0,0);(1,0);(1,1);(2,1)|]);((5,1),[|(0,0);(-1,1);(0,1);(-1,2)|]);                       
//5の逆転     ((5,2),[|(0,0);(0,1);(1,1);(1,2)|]);((5,3),[|(0,0);(1,0);(-1,1);(0,1)|])
             |]
let Mdim = 4 
let isPutable p (x,y) (arr:int[,])=
    let isThatPositionPutable (x1,y1) = 
        0 <= x+x1 && 0 <= y+y1 && 
        x+x1<Mdim && y+y1<Mdim && arr.[y+y1,x+x1] = 0
    let (_,rPositions) = p     
    Array.forall isThatPositionPutable rPositions    

let put p (x,y) (arr:int[,]) =
    let putOneLocation pID  (x1,y1) = arr.[y+y1,x+x1] <- pID
    let ((pId,_),rPositions) = p
    Array.map (putOneLocation pId) rPositions

let remove p (x,y) (arr:int[,]) =
   let removeOneLocation (x1,y1) = arr.[y+y1,x+x1] <- 0
   let (_,rPositions) = p     
   Array.map removeOneLocation rPositions

let findNextPutLoc (arr:int[,]) =
    let mutable isFirst = true
    let  result = ref None
    for y in 0 .. Mdim-1 do
       for x in 0 .. Mdim-1 do
            if arr.[y,x] = 0 && isFirst then
                result := Some((x,y))
                isFirst <- false
    !result
 
let check in_arr =
    let sucHisLst = ref []  
    let rec search hist  (arr:int[,]) =
        if findNextPutLoc arr = None then //成功!全部置けた
            sucHisLst := hist:: !sucHisLst
        else
            let (x,y) = (findNextPutLoc arr).Value
            for p in pieces do
                if isPutable p (x,y) arr then
                    put p (x,y) arr |> ignore
                    search (((x,y),p)::hist) arr
                    remove p (x,y) arr |> ignore
    search [] in_arr                       
    sucHisLst
 
let initArr = Array2D.create Mdim Mdim 0 //0は何も置かれていない状態 
let solutions = !(check initArr)

printfn "\n置き方の総数...%d\n" solutions.Length

///ここから「箱につめることができる積み木の組み合わせの総数」の処理

let extractKindlistAndSort eles  =
    let t = List.map (fun ((x,y),((k,_),_)) -> k) eles
    List.sort t

let combSet = solutions 
              |> List.map extractKindlistAndSort 
              |> Set.ofList
Set.iter (fun x -> printfn "%A" x ) combSet
printfn "\n組み合わせの総数...%d\n" combSet.Count

///ここから「上記総数を、異なる詰め方の個数別にカウント
// (箱の回転・裏返しで一致するものは同一視します)」の処理

//縦横2*Mdimの配列を準備して境界線を引きながら、もう一度積み木を置いていく。
//それから、回転裏返しで一致するものを除きながら、解のリストを作る。

let Connected = -1
let Discreet = -2

let put2 p (x,y) (arr:int[,]) =
    let putOneLocation pID  (x1,y1) = arr.[2*y+2*y1,2*x+2*x1] <- pID
    let ((pId,_),rPositions) = p
    Array.map (putOneLocation pId) rPositions

let upDateConnection (arr:int[,]) =
    for c in 0 .. Mdim - 1 do
        for r in 0 .. Mdim - 2 do
            if arr.[2*r,2*c] <> 0 && arr.[2*r,2*c]=arr.[2*r + 2,2*c] && arr.[2*r+1,2*c] = 0
                then arr.[2*r+1,2*c] <- Connected 
            if arr.[2*r,2*c] <> arr.[2*r + 2,2*c] && arr.[2*r+1,2*c] = 0
                then arr.[2*r+1,2*c] <- Discreet 
    for c in 0 .. Mdim - 2 do
        for r in 0 .. Mdim - 1 do
            if arr.[2*r,2*c] <> 0 && arr.[2*r,2*c]=arr.[2*r,2*c+2] && arr.[2*r,2*c+1] = 0
                then arr.[2*r,2*c+1] <- Connected 
            if arr.[2*r,2*c] <> arr.[2*r,2*c+2] && arr.[2*r,2*c+1] = 0
                then arr.[2*r,2*c+1] <- Discreet 
             
let rotateArr (arr:int[,]) =
    let tempArr = Array2D.create (2*Mdim-1) (2*Mdim-1) 0
    for c in 0 .. 2*Mdim - 2 do
        for r in 0 .. 2*Mdim - 2 do
            tempArr.[r,(2*Mdim-1) - c - 1 ] <- arr.[c,r]
    tempArr

let reverseArr (arr:int[,]) =
    let tempArr = Array2D.create (2*Mdim-1) (2*Mdim-1) 0
    for c in 0 .. 2*Mdim - 2 do
        for r in 0 .. 2*Mdim - 2 do
            tempArr.[r,c] <- arr.[c,r]
    tempArr

let makeUpPA ele =
    let tempArr = Array2D.create (2*Mdim-1) (2*Mdim-1) 0
    let t = List.fold (fun s ((x,y),((k,id),a)) ->
                            put2 ((k,id),a)(x,y) tempArr |>ignore;
                            upDateConnection tempArr|> ignore ;
                            k :: s) [] ele
    ((List.sort t),tempArr)

let isEqueWRR oriP uP oriArr arr = //回転反転すると等しくなる 
    let rec isEqueWRRSub arr1 arr2 count =
        if count = 4 then 
            false
        else
          if oriArr = arr1 || oriArr = arr2 then
            true
          else
            isEqueWRRSub (rotateArr arr1) (rotateArr arr2) (count + 1)
    if oriP <> uP then
        false
    else
        isEqueWRRSub arr (reverseArr arr) 0
              
let makeUpSolutions2 sols =
    let isInclude ele lst =
        let (usedPiece,arr0) = ele
        List.exists(fun (u,arr) ->isEqueWRR usedPiece u arr0 arr) lst

    let rec musSub lst res =
        match lst with
        |[]
            ->res
        |hd::tl 
            ->let t = makeUpPA hd
              if (isInclude t res)  then
                musSub tl res
              else
                musSub tl (t::res)
    musSub sols []


let solutions2 = (makeUpSolutions2 solutions)

printf "異なる詰め方の個数...%d"  solutions2.Length

///ここまでで答え終わり
//ここから見やすく答えを表示

let dispEach (kLst, (arr : int [,])) =
    printfn "\n\n%A" kLst
    for r in 0 .. 2*Mdim - 2 do
        printfn ""
        for c in 0 .. 2*Mdim - 2 do
          let st =  
                match arr.[r,c] with
                |i  when i = 0 || i = Connected -> " "
                |i  when i = Discreet && (c % 2 = 1 && r % 2 = 0) -> "|"
                |i  when i = Discreet && (c % 2 = 0 && r % 2 = 1) -> "-"
                |i   -> i.ToString()
          printf "%s" st     
    printfn ""

List.iter (fun ele -> dispEach ele) (List.sort solutions2)

Index

Feed

Other

Link

Pathtraq

loading...