Problem:
Squid Ink

Problem

近年、イカたちの間では縄張り争いが頻繁に起きている。複数のイカたちがチームを組み、自らのイカスミを武器に戦うのが近年のイカの戦闘スタイルである。

現在も縄張り争いが起こっており、その戦場は R×C のグリッドで表される。縄張り争いに参加しているイカのゲソ太はこのグリッド上のある場所にいる。この争いでは、重要な場所を敵よりも早く占拠することで戦況を有利にすることができる。そのため、ゲソ太は重要そうな場所を1つ決め、そこになるべく早く移動したいと考えている。

ゲソ太は隣接する上下左右のマスに移動することができる。グリッドの各マスには味方、または敵のイカスミが塗られている場合がある。なにも塗られていないマスに移動する場合、2秒かかるが、味方のイカスミが塗られているマスに移動する場合、その半分の時間(1秒)で済む。敵のイカスミが塗られているマスには移動することができない。壁があるマスや戦場の外へは当然移動することができない。

また、ゲソ太は上下左右のいずれかの方向を向き、イカスミを吐くことができる。すると、前方の3マスが味方のイカスミで上書きされる。ただし途中に壁がある場合はその手前までしかイカスミは届かない。この動作には2秒かかる。

戦場の情報とゲソ太の位置と目的の位置が与えられるので、最短で何秒で移動できるか求めてほしい。

Input

入力は以下の形式で与えられる。

R C
a1,1 a1,2 ... a1,C
a2,1 a2,2 ... a2,C
:
aR,1 aR,2 ... aR,C

1行目に2つの整数R,Cが空白区切りで与えられる。続くR行に戦場の情報としてC個のマスの情報が与えられる。ai,jは戦場の位置(i,j)のマスの情報を表し、以下のいずれかの文字である。

'.': なにも塗られていないマス

'#': 壁

'o': 味方のイカスミが塗られているマス

'x': 敵のイカスミが塗られているマス

'S': ゲソ太の位置(入力中に1つだけ存在し、マスはなにも塗られていない)

'G': 目的の位置(入力中に1つだけ存在し、マスはなにも塗られていない)

与えられる入力は、目的の位置まで移動することが可能であることが保証される。

Constraints

2 ≤ R,C ≤ 30

Output

ゲソ太が目的の位置まで移動するのにかかる最短の秒数を1行に出力せよ。

Sample Input 1

5 5
S....
.....
.....
.....
....G

Sample Output 1

14

Sample Input 2

5 5
Sxxxx
xxxxx
xxxxx
xxxxx
xxxxG

Sample Output 2

15

Sample Input 3

4 5
S#...
.#.#.
.#.#.
...#G

Sample Output 3

23

Sample Input 4

4 5
S#ooo
o#o#o
o#o#o
ooo#G

Sample Output 4

14

Sample Input 5

4 5
G####
ooxoo
##x#o
Soooo

Sample Output 5

10

Solution in Scala (judge verdict: Accepted)

import scala.annotation.tailrec
import scala.collection.mutable
object Main extends App {
  import scala.io.StdIn._

  val Array(r, c) = readLine.trim.split(' ').map(_.toInt)
  val state = Array.fill(r){readLine.trim.toCharArray}
  val start = (0 until r).flatMap(y ⇒ (0 until c).find(x ⇒ state(y)(x) == 'S').map(x ⇒ Coordinate(x, y))).head
  val goal = (0 until r).flatMap(y ⇒ (0 until c).find(x ⇒ state(y)(x) == 'G').map(x ⇒ Coordinate(x, y))).head
  val minStep = Array.fill(r){Array.fill(c){Int.MaxValue}}.wrap
  minStep(start) = 0
  val queue = mutable.PriorityQueue[(Coordinate, Int)]((start, 0))(Ordering.by[(Coordinate, Int), Int](_._2).reverse)
  while (queue.nonEmpty) {
    val (current, cost) = queue.dequeue()
    if (minStep(current) == cost) {
      for (direction ← Direction.all.map(_.asCoordinate)) if (state.isDefinedAt(current + direction)) {
        if (state(current + direction) != '#' && state(current + direction) != 'x') {
          if (state(current + direction) == 'o') {
            if (minStep(current + direction) > minStep(current) + 1) {
              minStep(current + direction) = minStep(current) + 1
              queue.enqueue((current + direction, minStep(current + direction)))
            }
          }else {
            if (minStep(current + direction) > minStep(current) + 2) {
              minStep(current + direction) = minStep(current) + 2
              queue.enqueue((current + direction, minStep(current + direction)))
            }
          }
        }
        val line = (0 until 3).scanLeft(current){case (c, _) ⇒ c + direction}.tail.takeWhile(c ⇒ state.isDefinedAt(c) && state(c) != '#').zipWithIndex
        for ((next, distance) ← line) {
          if (minStep(next) > minStep(current) + 3 + distance) {
            minStep(next) = minStep(current) + 3 + distance
            queue.enqueue((next, minStep(next)))
          }
        }
      }
    }
  }
  println(minStep(goal))


  implicit class Wrap[T](val array: Array[Array[T]]) extends AnyVal {
    def apply(coordinate: Coordinate): T = array(coordinate.y)(coordinate.x)
    def update(coordinate: Coordinate, value: T): Unit = array(coordinate.y)(coordinate.x) = value
    def isDefinedAt(coordinate: Coordinate): Boolean = array.indices.contains(coordinate.y) && array(coordinate.y).indices.contains(coordinate.x)
    def wrap: Wrap[T] = this
  }
}

case class Coordinate(x: Int, y: Int) {
  def +(that: Coordinate): Coordinate = Coordinate(x + that.x, y + that.y)
}
sealed trait Direction {
  def asCoordinate: Coordinate
}
object Direction {
  def all: List[Direction] = List(Up, Right, Down, Left)
}
object Up extends Direction {
  override def asCoordinate: Coordinate = Coordinate(0, -1)
}
object Right extends Direction {
  override def asCoordinate: Coordinate = Coordinate(1, 0)
}
object Down extends Direction {
  override def asCoordinate: Coordinate = Coordinate(0, 1)
}
object Left extends Direction {
  override def asCoordinate: Coordinate = Coordinate(-1, 0)
}