オフラインリアルタイムどう書く第5回の参考問題のJava解答


```java:RailsOnTiles.java
import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * 3x3マスの各位置のタイル。東西南北に位置するタイルのindexを持つ
 */
class Tile {
	int northernIndex;
	int easternIndex;
	int sourthernIndex;
	int westernIndex;
	char name;

	Tile(int n, int e, int s, int w, char nm) {
		northernIndex = n;
		easternIndex = e;
		sourthernIndex = s;
		westernIndex = w;
		name = nm;
	}

	/**
	 * 東西南北のindexを返す。9の場合はタイルの外
	 */
	int get(char bearing) {
		if (bearing == 'N') {
			return northernIndex;
		}
		if (bearing == 'E') {
			return easternIndex;
		}
		if (bearing == 'S') {
			return sourthernIndex;
		}
		return westernIndex;
	}

	@Override
	public String toString() {
		return String.valueOf(name);
	}
}

/**
 * 既定の3つのレール。各方角から入ったときの出口の方角を持つ
 */
class Rail {
	char northernExit;
	char easternExit;
	char sourthernExit;
	char westernExit;

	Rail(char n, char e, char s, char w) {
		northernExit = n;
		easternExit = e;
		sourthernExit = s;
		westernExit = w;
	}

	/**
	 * enter方角から入ってきた場合のexit方角を返す
	 */
	char getExit(char enter) {
		if (enter == 'N') {
			return northernExit;
		}
		if (enter == 'E') {
			return easternExit;
		}
		if (enter == 'S') {
			return sourthernExit;
		}
		return westernExit;
	}
}

/**
 * 問題: http://nabetani.sakura.ne.jp/hena/ord5railsontiles/
 */
public class RailsOnTiles {

	protected String solve(String input) {
		Rail[] rails = createRails();
		Tile[] tiles = createTiles();

		String result = "";
		result = loop(tiles, rails, 'S', 1, input, result);
		return result;
	}

	protected String loop(Tile[] tiles, Rail[] rails, char bearing, int index,
			String input, String result) {
		if (isOut(index)) {
			return result;
		}
		result += tiles[index].toString();
		int railId = Integer.valueOf(String.valueOf(input.charAt(index)));
		Rail rail = rails[railId];
		char exitBearing = rail.getExit(invert(bearing)); // 前回の出口の方角を反転して、入口として与え、次の出口の方角を得る
		int nextIndex = tiles[index].get(exitBearing); // 出て行く方角のindexを得る
		return loop(tiles, rails, exitBearing, nextIndex, input, result);
	}

	protected char invert(char c) {
		if (c == 'N') {
			return 'S';
		}
		if (c == 'E') {
			return 'W';
		}
		if (c == 'S') {
			return 'N';
		}
		return 'E';
	}

	protected boolean isOut(int i) {
		return 8 < i ? true : false;
	}

	protected Rail[] createRails() {
		Rail[] result = new Rail[3];
		result[0] = new Rail('S', 'W', 'N', 'E');
		result[1] = new Rail('E', 'N', 'W', 'S');
		result[2] = new Rail('W', 'S', 'E', 'N');
		return result;
	}

	protected Tile[] createTiles() {
		Tile[] result = new Tile[9];
		result[0] = new Tile(9, 1, 3, 9, 'A');
		result[1] = new Tile(9, 2, 4, 0, 'B');
		result[2] = new Tile(9, 9, 5, 1, 'C');
		result[3] = new Tile(0, 4, 6, 9, 'D');
		result[4] = new Tile(1, 5, 7, 3, 'E');
		result[5] = new Tile(2, 9, 8, 4, 'F');
		result[6] = new Tile(3, 7, 9, 9, 'G');
		result[7] = new Tile(4, 8, 9, 6, 'H');
		result[8] = new Tile(5, 9, 9, 7, 'I');
		return result;
	}

	public static void main(String[] args) {
		RailsOnTiles rot = new RailsOnTiles();
		System.out.println(rot.solve("101221102"));
	}

	protected void test(String input, String expected) {
		RailsOnTiles rot = new RailsOnTiles();
		assertEquals(expected, rot.solve(input));
	}

	@Test
	public void testRailsOnTiles() throws Exception {
		/* #0 */test("101221102", "BEDGHIFEH");
		/* #1 */test("000000000", "BEH");
		/* #2 */test("111111111", "BCF");
		/* #3 */test("222222222", "BAD");
		/* #4 */test("000211112", "BEFIHEDGH");
		/* #5 */test("221011102", "BADGHIFEBCF");
		/* #6 */test("201100112", "BEHIFCBADEF");
		/* #7 */test("000111222", "BEFIH");
		/* #8 */test("012012012", "BC");
		/* #9 */test("201120111", "BEDABCFI");
		/* #10 */test("220111122", "BADEHGD");
		/* #11 */test("221011022", "BADG");
		/* #12 */test("111000112", "BCFIHEBA");
		/* #13 */test("001211001", "BEFI");
		/* #14 */test("111222012", "BCFEHIF");
		/* #15 */test("220111211", "BADEHI");
		/* #16 */test("211212212", "BCFEBAD");
		/* #17 */test("002112210", "BEFC");
		/* #18 */test("001010221", "BEF");
		/* #19 */test("100211002", "BEFIHG");
		/* #20 */test("201212121", "BEFCBAD");
	}
}
```