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



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Main {

	static int intHight;//マップの縦の幅。
	static int intWidth;//マップの横の幅。
	static int intMaxTurn;//データセット数。
	static List<Integer> intSensyaPosition;//戦車の位置の数値リスト。
	static boolean[][] blExist;//戦車がいるかどうかの判定配列。
	static String[][] strMap;//マップ構成。
	static String[][][] strAnswer;//最終的なマップ。

	public static void main(String[] args){

		BufferedReader insBR = new BufferedReader(new InputStreamReader(System.in));
		List<Integer> hightList = new ArrayList<Integer>();;
		List<Integer> widthList = new ArrayList<Integer>();;

		try{

			//ターン数を読み取る。
			String strMaxTurn = insBR.readLine();
			intMaxTurn = Integer.parseInt(strMaxTurn);

			//答えのマップを配列で用意。
			strAnswer = new String[intMaxTurn][20][20];

			//ターン数分マップを駆け巡る。
			for(int intTurn = 0; intTurn < intMaxTurn; intTurn++){

				//マップの広さを読み取る。
				String[] strArea = insBR.readLine().split(" ");
				intHight = Integer.parseInt(strArea[0]);
				intWidth = Integer.parseInt(strArea[1]);

				//後ほど答えを出すときに必要になるので、リストにマップの広さをそれぞれ格納。
				hightList.add(intHight);
				widthList.add(intWidth);

				//マップの配列。
				strMap = new String[intHight][intWidth];

				//戦車がいるかどうかの判定配列を初期化。
				blExist = new boolean[intHight][intWidth];

				//マップの構成要素を読み取る。
				for(int intGyou = 0; intGyou < intHight; intGyou++){
					strMap[intGyou]  = insBR.readLine().split("");
				}

				//入力操作数。
				String strOperation = insBR.readLine();
				int intMaxOrder = Integer.parseInt(strOperation);

				//戦車の動作。
				String[] strAction = insBR.readLine().split("");

				//戦車の位置を取得。
				intSensyaPosition = new ArrayList<Integer>();
				boolean blFind = false;
				for(int first = 0; first < intHight; first++){
					for(int second = 0; second < intWidth; second++){
						if("^".equals(strMap[first][second]) || "v".equals(strMap[first][second])
							|| "<".equals(strMap[first][second]) || ">".equals(strMap[first][second])){

								intSensyaPosition.add(first);
								intSensyaPosition.add(second);
								blFind = true;
								break;
						}
					}
					if(blFind){
						break;
					}
				}

				int intSensyaY = intSensyaPosition.get(0);
				int intSensyaX = intSensyaPosition.get(1);
				String strSensya = strMap[intSensyaY][intSensyaX];

				//戦車を操作。
				for(int intOrder = 0; intOrder < intMaxOrder; intOrder++){
					order(strAction[intOrder], intSensyaPosition, strSensya);
				}

				//答えを格納。
				for(int intY = 0; intY < intHight; intY++){
					for(int intX = 0; intX < intWidth; intX++){
						strAnswer[intTurn][intY][intX] = strMap[intY][intX];
					}
				}

			}

		}catch(IOException e){

		}

		//出力
		for(int i = 0; i < intMaxTurn; i++){
			for(int j = 0; j < hightList.get(i); j++){
				for(int k = 0; k < widthList.get(i); k++){
					System.out.print(strAnswer[i][j][k]);
				}
				System.out.println();
			}
			if(i < intMaxTurn - 1){
				System.out.println();
			}
		}

	}

	//オーダーの処理メソッド。
	public static void order(String strOrder, List<Integer> list, String strSensya){

		int intSensyaY = list.get(0);
		int intSensyaX = list.get(1);

		//砲弾を撃つとき。
		switch(strOrder){

			case "S":
				destroy(intSensyaY, intSensyaX, strMap[intSensyaY][intSensyaX]);
				break;


			//方向転換
			case "U":
				if(intSensyaY - 1 < 0){
					strMap[intSensyaY][intSensyaX] = "^";

				}else{

					switch(strMap[intSensyaY - 1][intSensyaX]){

						case ".":
							strMap[intSensyaY][intSensyaX] = ".";
							strMap[intSensyaY - 1][intSensyaX] = "^";
							intSensyaPosition.clear();
							intSensyaPosition.add(intSensyaY - 1);
							intSensyaPosition.add(intSensyaX);
							break;

						default:
							strMap[intSensyaY][intSensyaX] = "^";
							break;

					}

				}
				break;

			case "D":
				if(intHight <= intSensyaY + 1){
					strMap[intSensyaY][intSensyaX] = "v";

				}else{
					if(".".equals(strMap[intSensyaY + 1][intSensyaX])){
						strMap[intSensyaY][intSensyaX] = ".";
						strMap[intSensyaY + 1][intSensyaX] = "v";
						intSensyaPosition.clear();
						intSensyaPosition.add(intSensyaY + 1);
						intSensyaPosition.add(intSensyaX);
					}else{
						strMap[intSensyaY][intSensyaX] = "v";
					}
				}
				break;

			case "L":
				if(intSensyaX - 1 < 0){
					strMap[intSensyaY][intSensyaX] = "<";

				}else{
					switch (strMap[intSensyaY][intSensyaX - 1]){

						case ".":
							strMap[intSensyaY][intSensyaX] = ".";
							strMap[intSensyaY][intSensyaX - 1] = "<";
							intSensyaPosition.clear();
							intSensyaPosition.add(intSensyaY);
							intSensyaPosition.add(intSensyaX - 1);
							break;
						default:
							strMap[intSensyaY][intSensyaX] = "<";
							break;

					}
				}
				break;

			case "R":
				if(intWidth <= intSensyaX + 1){
					strMap[intSensyaY][intSensyaX] = ">";

				}else{
					switch(strMap[intSensyaY][intSensyaX + 1]){

						case ".":
							strMap[intSensyaY][intSensyaX] = ".";
							strMap[intSensyaY][intSensyaX + 1] = ">";
							intSensyaPosition.clear();
							intSensyaPosition.add(intSensyaY);
							intSensyaPosition.add(intSensyaX + 1);
							break;

						default:
							strMap[intSensyaY][intSensyaX] = ">";
							break;
					}

				}
				break;
		}
	}

	public static void destroy(int intY, int intX, String strSensya){
		boolean blDestroy = false;
		switch(strSensya){

			case "^":
				if(0 <= intY - 1 ){
					for(int i = intY - 1; 0 <= i; i--){
						if("*".equals(strMap[i][intX])){
							strMap[i][intX] = ".";
							break;
						}else if("#".equals(strMap[i][intX])){
							break;
						}


					}
				}
				break;

			case "v":
				if(intY + 1 < intHight){
					for(int i = intY + 1; i < intHight; i++){
						switch(strMap[i][intX]){

							case "*":
								strMap[i][intX] = ".";
								blDestroy = true;
								break;

							case "#":
								blDestroy = true;
								break;

						}

						if(blDestroy){
							break;
						}
					}
				}
				break;

			case "<":
				if(0 <= intX - 1){
					for(int i = intX - 1; 0 <= i; i--){
						switch(strMap[intY][i]){

							case "*":
								strMap[intY][i] = ".";
								blDestroy = true;
								break;

							case "#":
								blDestroy = true;
								break;

						}

						if(blDestroy){
							break;
						}
					}
				}
				break;

			case ">":
				if(intX + 1 < intWidth){
					for(int i = intX + 1; i < intWidth; i++){
						switch(strMap[intY][i]){

							case "*":
								strMap[intY][i] = ".";
								blDestroy = true;
								break;

							case "#":
								blDestroy = true;
								break;

						}

						if(blDestroy){
							break;
						}
					}
				}
				break;

		}

	}

}