Created
May 11, 2011 02:49
-
-
Save tachiba/965838 to your computer and use it in GitHub Desktop.
Soko
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.*; | |
import java.util.*; | |
import java.awt.Point; | |
/** | |
* 倉庫でポン. | |
* @author Takashi CHIBA | |
* @version 1.02 | |
*/ | |
public class Soko{ | |
/** MAPの状態 */ | |
private char[][] map; | |
private char[][] mapSource; | |
/** MAPのサイズ */ | |
private int N, M; | |
/** MAPの種類 */ | |
private int mapIndex; | |
/** [.]の残り数 */ | |
private int task; | |
private int taskSource; | |
/** 移動回数 */ | |
private int cost; | |
/** コマンド */ | |
private final char MOVE_UP = 'w'; | |
private final char MOVE_DOWN = 's'; | |
private final char MOVE_LEFT = 'a'; | |
private final char MOVE_RIGHT = 'd'; | |
private final char UNDO = 'u'; | |
private final char RESET = '@'; | |
private final char CANCEL = '!'; | |
/** MAP上の物体 */ | |
private final char BLOCK = 'o'; | |
private final char BLOCK_ON_TARGET = 'O'; | |
private final char PLAYER = 'p'; | |
private final char PLAYER_ON_TARGET = 'P'; | |
private final char WALL = '#'; | |
private final char TARGET = '.'; | |
private final char SPACE = ' '; | |
/** 現在位置 */ | |
private Point now = new Point(); | |
private Point nowSource; | |
/** 行動パターン */ | |
private Point[] move = new Point[]{new Point(1,0), new Point(0,1), new Point(-1,0), new Point(0,-1)}; | |
/** 行動パターン配列のインデックス */ | |
private final int MOVE_DOWN_INDEX = 0; | |
private final int MOVE_RIGHT_INDEX = 1; | |
private final int MOVE_UP_INDEX = 2; | |
private final int MOVE_LEFT_INDEX = 3; | |
/** 行動履歴(戻る機能のために) */ | |
private LinkedList<Integer> log = new LinkedList<Integer>(); | |
/** ブロックを移動した履歴(ブロックを伴ったら真) */ | |
private LinkedList<Boolean> withBlockLog = new LinkedList<Boolean>(); | |
public static void main(String... arg){ | |
try { | |
new Soko().run(new Scanner(System.in)); | |
} catch (FileNotFoundException e){ | |
System.out.println("実行に必要なファイルが見つかりません"); | |
} catch (IOException e) { | |
System.out.println(e.toString()); | |
} | |
} | |
/** | |
* 倉庫でポンを実行する. | |
* @param Scanner sc 入力に使うScannerを与える | |
* @throws FileNotFoundException | |
* @throws IOException | |
*/ | |
public void run(Scanner sc) throws FileNotFoundException, IOException{ | |
/* スプラッシュ */ | |
{ | |
BufferedReader br = new BufferedReader(new FileReader("splush.txt")); | |
String line; | |
while ((line = br.readLine()) != null) { | |
System.out.println(line); | |
} | |
} | |
System.out.println("Please Enter Key... Game Start"); | |
// TODO choosing map | |
mapIndex = 1; | |
build(); | |
while (true) { | |
String in = sc.nextLine(); | |
if (in.length() > 0 && !in.contains(CANCEL + "")) { | |
switch (in.charAt(0)) { | |
case MOVE_DOWN: foward(MOVE_DOWN_INDEX); break; | |
case MOVE_RIGHT: foward(MOVE_RIGHT_INDEX); break; | |
case MOVE_UP: foward(MOVE_UP_INDEX); break; | |
case MOVE_LEFT: foward(MOVE_LEFT_INDEX); break; | |
case UNDO: back(); break; | |
case RESET: reset(); | |
} | |
} | |
for (char[] c : map) { | |
System.out.println(new String(c)); | |
} | |
System.out.printf("移動回数: %d\n", cost); | |
if (task == 0) break; | |
System.out.printf("移動: (上->%s, 左->%s, 下->%s, 右->%s) + Enter%n", MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT); | |
System.out.printf("戻す->%s, リセット->%s, 入力キャンセル->%sを含める%n", UNDO, RESET, CANCEL); | |
} | |
System.out.println("ゲームクリア!おめでとう!!"); | |
} | |
/** | |
* 指定したところへ進む. | |
* @param int moveIndex | |
*/ | |
private boolean foward(int moveIndex){ | |
/* now -> next -> next2 */ | |
Point next = moveTo(move[moveIndex].x, move[moveIndex].y); | |
Point next2 = moveTo(move[moveIndex].x * 2, move[moveIndex].y * 2); | |
boolean withBlock = false; | |
/* If you can NOT move */ | |
if (!canFoward(next, next2)) return false; | |
/* now? */ | |
switch (map[now.x][now.y]) { | |
case PLAYER_ON_TARGET: map[now.x][now.y] = TARGET; break; | |
case PLAYER: map[now.x][now.y] = SPACE; | |
} | |
/* next? */ | |
switch (map[next.x][next.y]) { | |
case BLOCK_ON_TARGET: | |
map[next.x][next.y] = PLAYER_ON_TARGET; | |
withBlock = true; | |
task++; | |
break; | |
case BLOCK: | |
map[next.x][next.y] = PLAYER; | |
withBlock = true; | |
break; | |
case TARGET: | |
map[next.x][next.y] = PLAYER_ON_TARGET; | |
break; | |
case SPACE: | |
map[next.x][next.y] = PLAYER; | |
} | |
/* next2? */ | |
if (withBlock) switch (map[next2.x][next2.y]) { | |
case TARGET: | |
map[next2.x][next2.y] = BLOCK_ON_TARGET; | |
task--; | |
break; | |
case SPACE: | |
map[next2.x][next2.y] = BLOCK; | |
} | |
now = new Point(next); | |
cost++; | |
log.add(moveIndex); | |
withBlockLog.add(withBlock); | |
return true; | |
} | |
/** | |
* 前に進めるかどうか. | |
* @param Point next 次に行く座標 | |
* @param Point next2 次の次に行く座標 | |
* @return boolean 進めるかどうか | |
*/ | |
private boolean canFoward(Point next, Point next2){ | |
return ((map[next.x][next.y] == SPACE || map[next.x][next.y] == TARGET) || | |
(map[next.x][next.y] == BLOCK || map[next.x][next.y] == BLOCK_ON_TARGET) && | |
(map[next2.x][next2.y] == SPACE || map[next2.x][next2.y] == TARGET)); | |
} | |
/** | |
* 履歴をたどりひとつ戻る. | |
*/ | |
private boolean back(){ | |
if (log.size() == 0) return false; | |
int moveIndex = log.pollLast(); | |
boolean withBlock = withBlockLog.pollLast(); | |
cost--; | |
/* next <--(will)-- now --(back)--> prev */ | |
Point prev = moveTo(-move[moveIndex].x, -move[moveIndex].y); | |
// Point prev = new Point(now.x - move[moveIndex].x, now.y - move[moveIndex].y); | |
Point next = moveTo(move[moveIndex].x, move[moveIndex].y); | |
// Point next = new Point(now.x + move[moveIndex].x, now.y + move[moveIndex].y); | |
/* now? */ | |
switch (map[now.x][now.y]) { | |
case PLAYER_ON_TARGET: | |
if (withBlock) { | |
map[now.x][now.y] = BLOCK_ON_TARGET; | |
task--; | |
} else { | |
map[now.x][now.y] = TARGET; | |
} | |
break; | |
case PLAYER: | |
if (withBlock) { | |
map[now.x][now.y] = BLOCK; | |
} else { | |
map[now.x][now.y] = SPACE; | |
} | |
} | |
/* prev? */ | |
switch (map[prev.x][prev.y]) { | |
case TARGET: map[prev.x][prev.y] = PLAYER_ON_TARGET; break; | |
case SPACE: map[prev.x][prev.y] = PLAYER; | |
} | |
/* next? */ | |
if (withBlock) switch(map[next.x][next.y]) { | |
case BLOCK_ON_TARGET: | |
map[next.x][next.y] = TARGET; | |
task++; | |
break; | |
case BLOCK: | |
map[next.x][next.y] = SPACE; | |
} | |
now = new Point(prev); | |
return true; | |
} | |
/** | |
* リセットする. | |
* @throws FileNotFoundException | |
* @throws IOException | |
*/ | |
private void reset() throws FileNotFoundException, IOException{ | |
cost = 0; | |
task = taskSource; | |
now = new Point(nowSource); | |
map = new char[N][M]; | |
deepcopy(mapSource, map); | |
} | |
/** | |
* MAPを構築する(初期化する). | |
* ファイルからMAPを読み取り、ゲームを始められる状態にする | |
* @throws FileNotFoundException | |
* @throws IOException | |
*/ | |
private void build() throws FileNotFoundException, IOException{ | |
BufferedReader br = new BufferedReader(new FileReader("map/gamemap_" + mapIndex + ".txt")); | |
String line; | |
LinkedList<String> data = new LinkedList<String>(); | |
while ((line = br.readLine()) != null) { | |
if (line.length() == 0 || line.charAt(0) == ';') continue; | |
data.add(line); | |
} | |
// line = null; | |
N = data.size(); | |
M = data.getFirst().length(); | |
map = new char[N][M]; | |
for (int i = 0; i < N; i++) { | |
map[i] = data.get(i).toCharArray(); | |
for (int j = 0; j < M; j++) { | |
if (map[i][j] == PLAYER) { | |
now.x = i; | |
now.y = j; | |
} else if (map[i][j] == TARGET) { | |
task++; | |
} | |
} | |
} | |
// data = null; | |
nowSource = new Point(now); | |
taskSource = task; | |
mapSource = new char[N][M]; | |
deepcopy(map, mapSource); | |
} | |
/** | |
* 指定した分移動したPointを返す. | |
* @param int x X軸の移動 | |
* @param int y Y軸の移動 | |
* @return Point | |
*/ | |
private Point moveTo(int a, int b){ | |
return new Point(now.x + a, now.y + b); | |
} | |
/** | |
* 二次元配列を深ーくコピーする. | |
* @param char[][] source コピーされる配列 | |
* @param char[][] to コピーする配列 | |
*/ | |
private static void deepcopy(char[][] source, char[][] to){ | |
for (int i = 0; i < source.length; i++) { | |
// to[i] = source[i].clone(); | |
for (int j = 0; j < source[0].length; j++) { | |
to[i][j] = source[i][j]; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment