Problem:
Problem D:バトルタウン

あなたは友人たちとゲームを開発することにした．
ゲームのタイトルは「バトルタウン」．
戦車による市街戦をテーマにしたゲームだ．
ゲーム開発の第一歩として，次のようなプロトタイプを開発することにした．

このプロトタイプでは，登場する戦車はプレイヤーの戦車のみであり，
敵の戦車は登場しない．
プレイヤーの戦車はプレイヤーの入力に従ってマップ上で様々な動作をする．
以下に，戦車の動作に関する仕様を述べる．

マップの構成要素は表1の通りである．
戦車が移動できるのはマップ内の平地の上だけである．

表1: マップの構成要素

文字

要素

.

平地

*

レンガの壁

#

鉄の壁

-

水

^

戦車（上向き）

v

戦車（下向き）

<

戦車（左向き）

>

戦車（右向き）

プレイヤーの入力は文字の列で与えられる．
各文字に対応する動作は表2の通りである．

表2: プレイヤーの入力に対する動作

文字

動作

U

Up: 戦車を上向きに方向転換し，さらに一つ上のマスが平地ならばそのマスに移動する

D

Down: 戦車を下向きに方向転換し，さらに一つ下のマスが平地ならばそのマスに移動する

L

Left: 戦車を左向きに方向転換し，さらに一つ左のマスが平地ならばそのマスに移動する

R

Right: 戦車を右向きに方向転換し，さらに一つ右のマスが平地ならばそのマスに移動する

S

Shoot: 戦車が現在向いている方向に砲弾を発射する

砲弾はレンガの壁あるいは鉄の壁にぶつかるか，マップの外に出るまで直進する．
レンガの壁にぶつかった場合は，砲弾は消滅し，レンガの壁は平地に変化する．
鉄の壁にぶつかった場合は，砲弾は消滅するが，鉄の壁は変化しない．
マップの外に出たときは砲弾はそのまま消滅する．

あなたの仕事は，初期マップとプレイヤーの入力操作列が与えられたときに，
最終的なマップの状態を出力するプログラムを作成することである．

Input

入力の1行目にはデータセット数を表す数 T
(0 < T ≤ 100) が与えられる．
この行に引き続き T 個のデータセットが与えられる．

各データセットの1行目にはマップの高さと幅を表す整数
H と W が
1つの空白文字で区切られて与えられる．
これらの整数は 2 ≤ H ≤ 20,
2 ≤ W ≤ 20 を満たす．
続く H 行はマップの初期状態を表す．
各行は長さ W の文字列である．
マップに含まれる文字はすべて表1で定義されたものであり，
全体でちょうど1つの戦車を含む．
マップに続く行には入力操作列の長さ N
(0 < N ≤ 100) が与えられ，
次の行には入力操作列を表す長さ N の文字列が与えられる．
入力操作列は表2で定義された文字のみからなる文字列である．

Output

各データセットに対し，すべての入力操作を終えた後のマップを，
入力マップと同じ形式で出力せよ．
データセットの間には1行の空行を出力せよ．
最後のデータセットの後に余計な空行を出力しないよう注意すること．

Sample Input

4
4 6
*.*..*
*.....
..-...
^.*#..
10
SRSSRRUSSR
2 2
<.
..
12
DDSRRSUUSLLS
3 5
>-#**
.-*#*
.-**#
15
SSSDRSSSDRSSSUU
5 5
v****
*****
*****
*****
*****
44
SSSSDDRSDRSRDSULUURSSSSRRRRDSSSSDDLSDLSDLSSD

Output for the Sample Input

*....*
......
..-...
..>#..

<.
..

^-#**
.-.#*
.-..#

.....
.***.
..*..
..*..
....v

Solution in Kotlin (judge verdict: Accepted)

fun main(args:Array<String>):Unit {
    repeat(readLine()!!.toInt()){
        val (h, w) = readLine()!!.split(' ').map(String::toInt)
        val stage = Stage(h, w)
        var tank = Tank()
        repeat(h){ y ->
            readLine()!!.forEachIndexed { x, c ->
                stage[x, y] = when (c) {
                    '*' -> MapObject.Block
                    '#' -> MapObject.Steal
                    '-' -> MapObject.Water
                    '.' -> MapObject.Plane
                    else -> {
                        tank = Tank(Point(x, y), when (c) {
                            '^' -> TankDirection.Up
                            'v' -> TankDirection.Down
                            '<' -> TankDirection.Left
                            else -> TankDirection.Right
                        })
                        MapObject.Plane
                    }
                }
            }
        }
        readLine()
        readLine()!!.toCharArray().forEach {
            if (it == 'S') {
                var point = tank.bullet.find {
                    when (stage[it]) {
                        MapObject.Block -> true
                        MapObject.Steal -> true
                        else -> false
                    }
                }!!
                when (stage[point]) {
                    MapObject.Block -> {
                        stage[point] = MapObject.Plane
                    }
                    else -> {
                    }
                }
            } else {
                tank = when (it) {
                    'U' -> tank.turnedToUp
                    'D' -> tank.turnedToDown
                    'L' -> tank.turnedToLeft
                    else -> tank.turnedToRight
                }
                when (stage[tank.forward]) {
                    MapObject.Plane -> tank = tank.moved()
                    else -> {
                    }
                }
            }
        }
        if (it != 0) println()
        println(stage.mkString(tank))
    }
}

class Point(val x:Int, val y:Int){
    operator fun plus(other:Point):Point = Point(x + other.x, y + other.y)
}
sealed class MapObject(val asChar:Char){
    object Plane:MapObject('.')
    object Block:MapObject('*')
    object Steal:MapObject('#')
    object Water:MapObject('-')
}
sealed class TankDirection(val asChar:Char, val difference:Point){
    object Up:TankDirection('^', Point(0, -1))
    object Down:TankDirection('v', Point(0, 1))
    object Left:TankDirection('<', Point(-1, 0))
    object Right:TankDirection('>', Point(1, 0))
}
class Stage(val height:Int, val width:Int){
    private val mArray:Array<Array<MapObject>> = Array(height + 2){Array(width * 2){MapObject.Steal as MapObject}}
    operator fun set(x:Int, y:Int, value:MapObject):Unit {
        mArray[y + 1][x + 1] = value
    }
    operator fun set(point:Point, value:MapObject):Unit {
        mArray[point.y + 1][point.x + 1] = value
    }
    operator fun get(x:Int, y:Int):MapObject = mArray[y + 1][x + 1]
    operator fun get(point:Point):MapObject = mArray[point.y + 1][point.x + 1]
    fun mkString(tank:Tank):String {
        val str = (1 .. height).map{y -> (1 .. width).map{x -> mArray[y][x].asChar}.toCharArray()}.toTypedArray()
        str[tank.position.y][tank.position.x] = tank.direction.asChar
        return str.joinToString (separator = "\n"){ it.joinToString("") }
    }
}
class Tank(val position:Point = Point(0, 0), val direction: TankDirection = TankDirection.Up){
    val bullet:Iterable<Point>
        get() = BulletLine(position, direction.difference)
    val turnedToUp:Tank
        get() = Tank(position, TankDirection.Up)
    val turnedToDown:Tank
        get() = Tank(position, TankDirection.Down)
    val turnedToLeft:Tank
        get() = Tank(position, TankDirection.Left)
    val turnedToRight:Tank
        get() = Tank(position, TankDirection.Right)
    val forward:Point
        get() = position + direction.difference
    fun moved():Tank = Tank(forward, direction)
    private class BulletLine(private var current:Point, private val diff:Point):Iterator<Point>, Iterable<Point>{
        override fun iterator(): Iterator<Point> = this
        override fun hasNext(): Boolean = true
        override fun next(): Point {
            current += diff
            return current
        }
    }
}