Skip to content

Instantly share code, notes, and snippets.

@tachiba
Created May 11, 2011 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tachiba/965838 to your computer and use it in GitHub Desktop.
Save tachiba/965838 to your computer and use it in GitHub Desktop.
Soko
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