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 C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;

public class Program
{
    /// <summary>
    /// プログラムエントリポイント
    /// </summary>
    public static void Main()
    {
        //問題数入力
        int countQ = int.Parse(Console.ReadLine());

        //問題数分繰り返す
        for (int i = 0; i < countQ; i++)
        {
            //戦車を動かすフィールドの２次元配列の大きさ入力
            string[] inputData = Console.ReadLine().Split(' ');

            //入力されたフィールドの大きさの値をもとに char[][] の配列生成
            char[,] aryChBattleArea = new char[int.Parse(inputData[0]), int.Parse(inputData[1])];

            for (int x = 0; x < aryChBattleArea.GetLength(0); x++)
            {

                char[] tmp = Console.ReadLine().ToCharArray();

                for (int y = 0; y < aryChBattleArea.GetLength(1); y++)
                {
                    aryChBattleArea[x, y] = tmp[y];
                }

            }

            int countOperation = int.Parse(Console.ReadLine());

            char[] aryChOperation = new char[countOperation];

            aryChOperation = Console.ReadLine().ToCharArray();

            BattleTown insBT = new BattleTown(aryChBattleArea, aryChOperation);

            char[,] aryChAnswer = insBT.runOperation();

            for (int x = 0; x < aryChBattleArea.GetLength(0); x++)
            {
                for (int y = 0; y < aryChBattleArea.GetLength(1); y++)
                {
                    Console.Write(aryChAnswer[x, y]);
                }
                Console.WriteLine();
            }
            if (i != countQ - 1)
            {
                Console.WriteLine();
            }

        }
    }
}

/// <summary>
/// BattleTownクラス
/// </summary>
class BattleTown
{

    private char[,] aryChBattleArea;
    private char[] aryChOperation;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="aryChBattleArea">文字２重配列</param>
    /// <param name="aryChOperation">文字配列</param>
    public BattleTown(char[,] aryChBattleArea, char[] aryChOperation)
    {
        this.aryChBattleArea = aryChBattleArea;
        this.aryChOperation = aryChOperation;
    }

    /// <summary>
    /// 命令を実行する
    /// </summary>
    /// <returns></returns>
    public char[,] runOperation()
    {

        foreach (char c in aryChOperation)
        {
            for (int pointX = 0; pointX < aryChBattleArea.GetLength(0); pointX++)
            {
                for (int pointY = 0; pointY < aryChBattleArea.GetLength(1); pointY++)
                {
                    if (aryChBattleArea[pointX, pointY] == '^' || aryChBattleArea[pointX, pointY] == 'v'
                            || aryChBattleArea[pointX, pointY] == '<' || aryChBattleArea[pointX, pointY] == '>')
                    {
                        this.actionTank(pointX, pointY, c);
                        pointX++;
                        break;
                    }

                }

            }
        }

        return this.aryChBattleArea;

    }

    /// <summary>
    /// 戦車を命令に従って動かす
    /// </summary>
    /// <param name="pointX">戦車の位置X</param>
    /// <param name="pointY">戦車の位置Y</param>
    /// <param name="operation">命令(文字)</param>
    private void actionTank(int pointX, int pointY, char operation)
    {
        //命令、向き、動きがリンクしている。
        char[] control = { 'U', 'D', 'R', 'L' };
        char[] direction = { '^', 'v', '>', '<' };
        int[,] move = { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } };

        //移動用
        if (operation != 'S')
        {
            //control[]の長さ分繰り返す
            for (int i = 0; i < control.Length; i++)
            {
                //命令が一致したら
                if (operation == control[i])
                {
                    //戦車の向きをかえる
                    aryChBattleArea[pointX, pointY] = direction[i];

                    //戦車がX方向,Y方向に動いた先がaryChBattleArea[,]の範囲内だったら

                    //if (pointX - 1 >= 0 && pointX + 1 < aryChBattleArea.Length
                    //        && pointY - 1 >= 0 && pointY + 1 < aryChBattleArea.Length)

                    if (pointX + move[i, 0] >= 0 && pointX + move[i, 0] < aryChBattleArea.GetLength(0)
                            && pointY + move[i, 1] >= 0 && pointY + move[i, 1] < aryChBattleArea.GetLength(1))
                    {
                        //戦車の移動先が '.'(平原) だったら
                        if (aryChBattleArea[pointX + move[i, 0], pointY + move[i, 1]] == '.')
                        {
                            //戦車がいた位置を'.'に変更
                            aryChBattleArea[pointX, pointY] = '.';

                            //戦車の移動先を向きにあわせて変更
                            aryChBattleArea[pointX + move[i, 0], pointY + move[i, 1]] = direction[i];

                        }
                    }
                }
            }

        }

        //射撃用
        else
        {
            int pointXS = pointX;
            int pointXY = pointY;

            for (int i = 0; i < direction.Length; i++)
            {

                if (aryChBattleArea[pointXS, pointXY] == direction[i])
                {

                    while (0 <= pointXS && pointXS < aryChBattleArea.GetLength(0) &&
                                0 <= pointXY && pointXY < aryChBattleArea.GetLength(1))
                    {

                        if (aryChBattleArea[pointXS, pointXY] == '*')
                        {

                            aryChBattleArea[pointXS, pointXY] = '.';
                            break;

                        }
                        else if (aryChBattleArea[pointXS, pointXY] == '#')
                        {

                            break;
                        }

                        pointXS += move[i, 0];
                        pointXY += move[i, 1];
                    }

                    break;
                }
            }
        }
    }
}