裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

ダブルテトロミノ

2017年02月17日 | ブログラミング

ダブルテトロミノ

締め切りが 2017/02/17 10:00 AM なので,その 1 分後に投稿されるように予約

下図のように、黒いマスが 8つあります。

  
  
テトロミノ2つを使って黒いマスで示された図形を作るには、どんなテトロミノが必要なのか、全ての組み合わせを求めてください。

例えば上の例の場合、
 LとO、LとS
という組み合わせが考えられます。

テトロミノは、下図の 5 種類があります:

     

裏返したり回転したりしてできるテトロミノは同じ名前です。

入力は
56 37 36 55 35 46 45 47
のような感じです。

空白区切りで黒いマスの位置が書かれています。
黒いマスの位置は、1文字目が x 座標、2文字目がy座標です。

出力は、
LO,LS
のような感じです。

ペアをコンマ区切りで並べてください。
ペア間もペア内も、アルファベット順に整列しておく必要があります。
下表の通りです。
誤     LS,LO
誤     OL,SL
正     LO,LS

入力の形が2つのテトロミノでは作れない場合は、
-
を出力してください。



【例】
入力                出力
56 37 36 55 35 46 45 47     LO,LS     
70 07 44 34 98 11 00 32     -     
63 60 67 65 64 62 61 66     II     

【補足】

    不正な入力に対処する必要はありません。
    入力には、かならず8マス含まれています。重複はありません。

====================

テトロミノは回転・対称も考えて 19 通りあるので,それをデータ化する。
たとえば,図にある T テトロミノは,左にある黒を(0,0) として,残り 3 つの正方形は (-1,1), (0,1), (1,1) にあるなど。


19 通りのテトロミノを最初の盤面の黒の位置に順次置いていって,最初の同じ盤面になれば 2 つのテトロミノの種類を記憶する。
ブルートフォースでプログラムしたが,制限時間内に答えが出るので,チューンアップはしない。

f = function(s) {
    a = cbind(
        c(0,0,1,0,2,0,3,0), # I
        c(0,0,0,1,0,2,0,3),
        c(0,0,1,0,2,0,2,1), # L
        c(0,0,0,1,0,2,-1,2),
        c(0,0,0,1,1,1,2,1),
        c(0,0,1,0,0,1,0,2),
        c(0,0,0,1,-1,1,-2,1),
        c(0,0,0,1,0,2,1,2),
        c(0,0,1,0,2,0,0,1),
        c(0,0,1,0,1,1,1,2),
        c(0,0,1,0,0,1,1,1), # O
        c(0,0,1,0,1,1,2,1), # S
        c(0,0,0,1,-1,1,-1,2),
        c(0,0,0,1,1,1,1,2),
        c(0,0,1,0,0,1,-1,1),
        c(0,0,-1,1,0,1,1,1), # T
        c(0,0,0,1,0,2,1,1),
        c(0,0,1,0,2,0,1,1),
        c(0,0,0,1,0,2,-1,1)
    )
    dim(a) = c(2, 4, 19) # ピースを構成する正方形の4つの座標(x, y)が19種類
    p = c("I", "I", rep("L", 8), "O", rep("S", 4), rep("T", 4)) # ピースの名前
    xy = matrix(as.numeric(unlist(strsplit(gsub(" ", "", s), ""))) + 1, byrow = TRUE, ncol = 2) # 10行10列の行列における黒いマスの座標
    b0 = matrix(0, 10, 10)
    b = matrix(0, 10, 10)
    b[xy] = 1 # マーク
    kxy = (xy[, 2] - 1) * 10 + xy[, 1] # ここまでで盤面の設定(手本の盤面と呼ぶ)
    ans = NULL
    for (i in 1:19) { # 回転・反転を考慮した19種のテトロミノを順次試す
        for (j in i:19) { # 回転・反転を考慮した19種のテトロミノを順次試す
            for (k1 in 1:8) { # i番目のテトロミノを置くマスの位置 (xy[k1,1], xy[k1,2]) を順次試す
                for (k2 in 1:8) { # j番目のテトロミノを置くマスの位置 (xy[k2,1], xy[k2,2]) を順次試す
                    b1 = b0 # 新しい(クリーンな)盤面
                    for (l in 1:4) { # テトロミノを構成する4つの正方形で盤面をマークする
                        sxi = xy[k1, 1] + a[1, l, i] # i番目のテトロミノが置かれる盤面の行
                        syi = xy[k1, 2] + a[2, l, i] # i番目のテトロミノが置かれる盤面の列
                        if ((sxi >= 1 && 10 >= sxi) && (syi >= 1 && 10 >= syi)) {
                            b1[sxi, syi] = 1 # はみ出さないのでマーク
                        }
                        sxj = xy[k2, 1] + a[1, l, j] # j番目のテトロミノが置かれる盤面の行
                        syj = xy[k2, 2] + a[2, l, j] # j番目のテトロミノが置かれる盤面の列
                        if ((sxj >= 1 && 10 >= sxj) && (syj >= 1 && 10 >= syj)) {
                            b1[sxj, syj] = 1 # はみ出さないのでマーク
                        }
                    }
                    if (all(b1 == b)) { # 手本の盤面と同じであれば結果を記録(2つのテトロミノは何だったか)
                        ans = rbind(ans, c(p[i], p[j]))
                    }
                }
            }
        }
    }
    ans = unique(as.data.frame(ans)) # 同じ解を取り除く
    if (nrow(ans) == 0) { # 解がないとき
        cat("-")
    } else { # 解があるとき
        cat(paste(apply(ans, 1, paste, collapse = ""), collapse = ","))
    }
    cat("\n")
}

f("56 37 36 55 35 46 45 47") # LO,LS
f("70 07 44 34 98 11 00 32") # -
f("63 60 67 65 64 62 61 66") # II
f("65 46 45 66 54 44 64 56") # LL
f("34 46 36 47 33 44 35 45") # II,SS,TT
f("85 75 76 84 83 73 86 74") # II,LL,OO
f("67 76 77 78 68 69 58 57") # LT,ST
f("44 45 34 55 43 35 33 56") # LO,LS
f("55 46 66 45 44 57 54 56") # LT,OT
f("43 24 35 33 34 32 23 44") # SS,TT
f("20 10 12 21 03 22 13 11") # LL,OS
f("53 54 75 45 55 35 65 56") # -
f("88 89 86 87 78 68 99 79") # -
f("28 37 25 38 35 47 46 36") # SS
f("94 93 01 03 02 91 92 04") # II

コメント    この記事についてブログを書く
  • Twitterでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 「ルーム・アンド・ルーフ」問題 | トップ | 現地で使いやすい両替 »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事