Problem:
Problem I: Rolling Block

Problem

Rolling Blockは直方体の金属体を回転させつつ移動させ、ゴールの穴に落とすゲームである。

このゲームのクリア条件は金属体をゴールに落とすことである。

ブロックについて

下の図の(1)より、ブロックは1×1×Lの直方体である。
ブロックは東西南北のどれかの方向に回転しながら移動することができる。
しかし、ブロックはステージからはみ出るような動きをとることは出来ない。

下の図の(2)より、ブロックが横に倒れている場合は移動方向に対してこのような回転をしつつ移動する。

下の図の(3)より、ブロックが直立している場合は移動方向に対してこのような回転をしつつ移動する。

(2) 、(3) については灰色のブロックが移動前、白色のブロックが移動後のブロックとする。

黒い矢印はその方向に対してブロックが移動したことを示す。
また、白の矢印は移動する際にブロックがその方向へ回転したことを示す。
ブロックに点線が引かれているが、これは回転を分かりやすくするために引いたものである。
（実際にゲームで扱うブロックにはこのような点線は書かれていない）

以下の図はブロックの回転を補足するための図である。
サイコロのように対面の和が7になるようなブロックがあるとする。
直立している場合と倒れているブロックについて、このブロックを東西南北の4方向へ回転しつつ移動させたときの上面の数字の変化を以下の図に示す。
（実際にゲームで扱うブロックにはこのような数字は書かれていない。）

ステージについて

ステージはH×Wの二次元グリッドで与えられる(1 ≤ H,W ≤ 25) 。
二次元グリッドはそれぞれ以下の種類のセルから成る。

"." 床

床の上にブロックが乗ることができる。

"#" 壁

壁には進行不可能であり、ブロックの一部が壁の上に乗るような移動はできない。

"S" ブロックの初期位置

ブロックは１文字だけ与えられる。初期状態では直立している状態しか存在しない。

"G" ゴール地点

ゴールはステージ中に１つしか出現しない。

また、ブロックが直立している状態でしかゴールすることは不可能である。

特殊壁とスイッチ

アルファベット小文字 特殊壁

アルファベット大文字 特殊壁に対応するスイッチ

特殊壁は出現時には進行不可能であり、ブロックの一部が特殊壁の上に乗るような移動はできない。
ブロックが回転を行い直立したときにブロックの真下にスイッチがあるとき、そのスイッチは押される。

スイッチを押したとき、同じアルファベットの特殊壁が出現しているときは消滅し、逆に消滅しているときは出現する。

ステージ開始直後ではすべての特殊壁が出現しているとする。

ひとつのステージで現れる特殊壁とスイッチは最大５種類とする。

スイッチを表すアルファベットは{'A','B','C','D','E'}である。

特殊壁を表すアルファベットは{'a','b','c','d','e'}である。

スイッチと特殊壁の数はH×W個以下である。

特殊壁と同じアルファベットのスイッチがステージの中に必ず出現するとは限らない。

また、スイッチと同じアルファベットの特殊壁がステージの中に必ず出現するとは限らない。

"^" トラップ

トラップのマスの上には直方体が直立した状態で乗ってはいけない。

ステージの情報と金属体の初期位置が与えられるので、このパズルを解く最短手数を求めよ。
解が存在しない場合は-1を出力しなさい。

Input

H W L
Cell1-1 ... Cell1-W
.
.
.
CellH-1 ... CellH-W

最初にH,W,Lが与えられる。

それぞれ、ステージの縦の長さ、横の長さ、ブロックの長さを示す。

次にH×Wの二次元グリッドが与えられる。これはステージの情報を表している。

Constraints

入力は以下の条件を満たす。

1 ≤ H,W ≤ 25

1 < L < 10

Cell は Cell = {'A','B','C','D','E','S','G','a','b','c','d','e','^','#','.'} から成る。

Output

ステージの情報と金属体の初期位置が与えられるので、このパズルを解く最短手数を求めよ。

解が存在しない場合は-1を出力しなさい。

Sample Input 1

5 5 2
#####
#S.G#
#...#
#...#
#####

Sample Output 1

4

Sample Input 2

3 12 2
############
#S..A..a..G#
############

Sample Output 2

6

Sample Input 3

3 12 2
############
#S...A.a..G#
############

Sample Output 3

-1

Sample Input 4

7 13 3
#############
#S....#.....#
#.....#.....#
#.....#.....#
#...........#
#..........G#
#############

Sample Output 4

8

Sample Input 5

3 12 2
############
#S^^.^^.^^G#
############

Sample Output 5

6

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable

object Main extends App {
  import scala.io.StdIn._


  val Array(h, w, l) = readLine.trim.split(' ').map(_.toInt)
  val state = Array.tabulate(h){_ ⇒ readLine.trim}
  val stage = new Stage(h, w, state)
  val start = new Stand(l, (0 until w).flatMap(x ⇒ (0 until h).find(y ⇒ state(y)(x) == 'S').map(y ⇒ Coordinate(x, y))).head)
  val switches = new Switches
  val minCost = Array.tabulate(h){_ ⇒ Array.tabulate(w){_ ⇒ Array.tabulate(3){_ ⇒ Array.tabulate(1 << 5){_ ⇒ Int.MaxValue}}}}
  val queue = mutable.PriorityQueue()(Ordering.by[(Block, Switches, Int), Int](_._3).reverse)
  minCost(start.position.y)(start.position.x)(start.typeId)(switches.toInt) = 0
  queue.enqueue((start, switches, 0))

  while(queue.nonEmpty && !stage.isGoal(queue.head._1)) {
    val (block, switch, cost) = queue.dequeue()
    if (minCost(block.position.y)(block.position.x)(block.typeId)(switch.toInt) == cost) {
      for (next ← block.neighbor if stage.canPut(next, switch)){
        val nextS = stage.put(next, switch)
        if (minCost(next.position.y)(next.position.x)(next.typeId)(nextS.toInt) > cost + 1){
          minCost(next.position.y)(next.position.x)(next.typeId)(nextS.toInt) = cost + 1
          queue.enqueue((next, nextS, cost + 1))
        }
      }
    }
  }
  println(
    if (queue.isEmpty) -1
    else queue.head._3
  )

  class Stage(val height: Int, val width: Int, private[this] val state: Array[String]) {
    def canPut(block: Block, switches: Switches): Boolean = {
      block.indices.forall{c ⇒
        (0 until width).contains(c.x) && (0 until height).contains(c.y) &&
          (state(c.y)(c.x) match {
          case '#' ⇒ false
          case '^' ⇒ !block.isStand
          case 'S' | 'G' ⇒ true
          case c if c.isLower ⇒ switches.isOn(c)
          case _ ⇒ true
        })
      }
    }
    def put(block: Block, switches: Switches): Switches = {
      if (block.isStand)
        state(block.position.y)(block.position.x) match {
          case 'S' | 'G' ⇒ switches
          case s if s.isUpper ⇒ switches.pushSwitch(s)
          case _ ⇒ switches
        }
      else switches
    }
    def isGoal(block: Block): Boolean = block.isStand && (0 until width).contains(block.position.x) && (0 until height).contains(block.position.y) && state(block.position.y)(block.position.x) == 'G'
  }
  class Switches(private[this] val flag: Int = 0) {
    def toInt = flag
    def pushSwitch(char: Char): Switches = new Switches(flag ^ (1 << (char - 'A')))
    def isOn(char: Char): Boolean = (flag & (1 << (char - 'a'))) != 0
  }
  sealed trait Block {
    def right: Block
    def left: Block
    def up: Block
    def down: Block
    def indices: Iterable[Coordinate]
    def isStand: Boolean = false
    def position: Coordinate
    def typeId: Int
    def neighbor: Iterable[Block] = List(right, left, up, down)
  }
  class Stand(private[this] val length: Int, val position: Coordinate) extends Block {
    override def right: Block = new Horizontal(length, position + Coordinate(1, 0))
    override def left: Block = new Horizontal(length, position - Coordinate(length, 0))
    override def up: Block = new Vertical(length, position - Coordinate(0, 1))
    override def down: Block = new Vertical(length, position + Coordinate(0, length))
    override def indices: Iterable[Coordinate] = Some(position)
    override def isStand: Boolean = true
    override def typeId: Int = 0
  }
  class Vertical(private[this] val length: Int, val position: Coordinate) extends Block {
    override def right: Block = new Vertical(length, position + Coordinate(1, 0))
    override def left: Block = new Vertical(length, position - Coordinate(1, 0))
    override def up: Block = new Stand(length, position - Coordinate(0, length))
    override def down: Block = new Stand(length, position + Coordinate(0, 1))
    override def indices: Iterable[Coordinate] = (0 until length).map(y ⇒ position - Coordinate(0, y))
    override def typeId: Int = 1
  }
  class Horizontal(private[this] val length: Int, val position: Coordinate) extends Block {
    override def right: Block = new Stand(length, position + Coordinate(length, 0))
    override def left: Block = new Stand(length, position - Coordinate(1, 0))
    override def up: Block = new Horizontal(length, position - Coordinate(0, 1))
    override def down: Block = new Horizontal(length, position + Coordinate(0, 1))
    override def indices: Iterable[Coordinate] = (0 until length).map(x ⇒ position + Coordinate(x, 0))
    override def typeId: Int = 2
  }
  case class Coordinate(x: Int, y: Int) {
    def +(that: Coordinate): Coordinate = Coordinate(x + that.x, y + that.y)
    def -(that: Coordinate): Coordinate = Coordinate(x - that.x, y - that.y)
  }
  implicit class Scope[T](val value: T) extends AnyVal{
    @inline
    def also(@inline func: T ⇒ Unit): T = {
      func(value)
      value
    }
    @inline
    def let[A](func: T ⇒ A): A = func(value)
  }
}