ダンジョン探索プログラム - 萌えJava超入門
最終章 超入門まとめ

ダンジョン探索プログラム

ダンジョンを探索するプログラム例です。

目次

1.プログラムの紹介


まずはこの章で使用するプログラムを紹介しましょう。

今回ご紹介するのは、縦10マス x 横10マス の碁盤の目状のマップをテンキーで移動するプログラムです。

マップイメージ
mapImage

コマンドラインで動作するので、ビジュアル的には渋いです。

これはナカナカ...。
渋いっスね。
渋いわね。
まあ学習用と
思って。
mapImage

これだと寂しいので、
章の終わりにGUIバージョンも載せてみました。そちらもお試しください。
ご参照 → GUI版ダンジョン探索プログラム

mapImage
おっ!
Wizardry Like** ね。
こっちは昭和感が
パナいっす。
まあ
そうなんだけどさぁ。
**Wizardry Like (ウィザードリィライク)。
ウィザードリィの様な3Dダンジョンゲームのこと。
RPGの王道の一つと言っていいでしょう。
ここでは歩くだけ。

操作方法

「8」キーで進行方向に進みます。(壁があると進めません。)
「6」キーで右を向きます。
「4」キーで左を向きます。
「2」キーで後ろを向きます。
「5」キーで現在位置の壁の配置を表示します。
   0 通れます。
   1 壁です。
   例:↓前後に進めます。
   put5key
「0」キーで強制終了します。

キーを押すごとに現在の座標と向いている方向を表示します。

1階で上り階段を昇るとゲームクリアです。
プログラムが終了します。




2.ソースコードの紹介と実行

プログラムは3つのソースファイルで構成されています。
  1. Sample24_01.java
  2. Cell.java
  3. Scan.java
以上の3つのファイルをワークフォルダに保存してください。

Scan.java は以前に紹介させていただいたものと同じです。
 ご参照↓
 第二十二章 コマンドラインから入力するⅡ
    Scanクラスにまとめる


Scan.java は、↓こちらからもダウンロードできます。
   Scan.java
ソースコードの説明は次のページにしますね。
とりあえず動かしてみましょう。
実行コマンドはソースコードの下です。

長っ!!
これ長すぎ
ません?
大丈夫。
習った内容
ばかりだ。
//Sample24_01.java
public class Sample24_01 {

    private final static int NORTH = 0;
    private final static int EAST  = 1;
    private final static int SOUTH = 2;
    private final static int WEST  = 3;

    //actionType cell.getBit4(4)
    //private final static int DOOR_NORTH = 1;
    //private final static int DOOR_EAST  = 2;
    //private final static int DOOR_SOUTH = 3;
    //private final static int DOOR_WEST  = 4;
    private final static int FIELD_MSG  = 5;
    private final static int ACTION_UP  = 6;
    private final static int ACTION_DOWN= 7;

    private int floor = 0;
    private int posX = 0;
    private int posY = 0;
    private int direction = 0;

    private int[][][] map3D = null;

    //cell.getBit4(5)
    private String[] msgArray = null;

    private boolean displayFieldMsg = true;
    private int displayX = 0;
    private int displayY = 0;

    public Sample24_01(
            int[][][] map3D,
            int posX,
            int posY,
            int direction)
    {
      this.map3D = map3D;
      this.posX = posX;
      this.posY = posY;
      this.direction = direction;
    }

    public Sample24_01(int[][][] map3D){
      this.map3D = map3D;
    }

    public void setMsgArray(String[] msgArray){
      this.msgArray = msgArray;
    }
    //Move floor.
    private void up() {
      ++floor;
    }
    private void down() {
      --floor;
    }
    public boolean isOut() {
      return floor < 0;
    }

    //Move field.
    public boolean toForward(){
      Cell cell = rotatePosCell(0, 0);
      boolean pass = cell.getF()!=1;
      if(pass){
        switch(direction){
        case NORTH:
          posY++;
          break;
        case EAST:
          posX++;
          break;
        case SOUTH:
          posY--;
          break;
        case WEST:
          posX--;
          break;
        }

        displayFieldMsg = true;
      }
      return pass;
    }
    public void lookBack(){
      direction += 2;
      direction %= 4;
    }
    public void toRight(){
      direction++;
      direction %= 4;
    }
    public void toLeft(){
      direction--;
      direction += 4;
      direction %= 4;
    }

    //RotateCell
    public Cell rotatePosCell(int x0, int y0){
      //(x0, y0) is relative position.
      int[] xy = rotatePos(x0, y0, direction);
      int[] RC = xytoRC(posX + xy[0], posY + xy[1]);

      Cell cell = null;
      try {
        cell = new Cell(map3D[floor][RC[0]][RC[1]]);
        return cell.rotateCell(direction);
      }catch(java.lang.ArrayIndexOutOfBoundsException e) {
        return cell;
      }
    }
    private int[] xytoRC(int x, int y){
      //(x, y) to Row and Column
      int[] RC = new int[2];
      RC[0]=map3D[floor].length - 1 - y; //Row
      RC[1]=x; //Column
      return RC;
    }

    private static int[] rotatePos(int x0, int y0, int direction) {
      int x;
      int y;

      switch(direction) {
      case NORTH:
        x = x0;
        y = y0;
        break;
      case EAST:
        x = y0;
        y = -x0;
        break;
      case SOUTH:
        x = -x0;
        y = -y0;
        break;
      case WEST:
        x = -y0;
        y = x0;
        break;
      default:
        x = x0;
        y = y0;
      }
      int[] xy = {x, y};
      return xy;
    }

    public String message() {
      if(msgArray==null)return null;

      Cell cell = rotatePosCell(0, 0);
      int type = cell.getBit4(4);

      if(type == 0)return null;

      String msg = null;
      if(type == direction+1) {
        //doorMsg
        int msgNo = cell.getBit4(5);
        msg = msgArray[msgNo];

      }else if(type == FIELD_MSG) {
        //FieldMsg
        if(displayFieldMsg) {
          int msgNo = cell.getBit4(5);
          msg = msgArray[msgNo];
          displayFieldMsg = false;
        }
      }
      return msg;
    }

    public boolean action() {
      Cell cell = rotatePosCell(0, 0);
      int type = cell.getBit4(4);

      switch(type){
        case 0:
            return false;
        case ACTION_DOWN:
            if(displayFieldMsg) {
                Boolean yn
                  = Scan.getBoolean("上り階段があります。 昇りますか?(Y/N): ");
                if(yn) {
                  down();
                }
                displayFieldMsg = false;
                return true;
            }
            break;
        case ACTION_UP:
            if(displayFieldMsg) {
                Boolean yn
                  = Scan.getBoolean("下り階段があります。 降りますか?(Y/N): ");
                if(yn) {
                  up();
                }
                displayFieldMsg = false;
                return true;
            }
            break;
        }
      return false;
    }

    //Infomation string.

    public String getPos(){
      return String.format("%sF (%2s, %2s) %s",
              Integer.toString(floor+1, 10),
              Integer.toString(posX + displayX, 10),
              Integer.toString(posY + displayY, 10),
              strDirection()
          );
    }
    private String strDirection(){
      switch(direction){
        case NORTH:
          return "NORTH";
        case EAST:
          return "EAST";
        case SOUTH:
          return "SOUTH";
        case WEST:
          return "WEST";
        default:
          return "Invalid direction.";
      }
    }

    public static void main(String[] args){

  int[][][] map3D = {
          {//1st floor
{0x1001,0x1010,0x1010,0x1100,0x1001,0x1000,0x1000,0x1110,0x1101,0x61101},
{0x0101,0x1011,0x1110,0x0101,0x0011,0x0010,0x0110,0x1001,0x0110,0x0101},
{0x0011,0x1000,0x1010,0x0020,0x1010,0x1000,0x1010,0x0100,0x1111,0x0101},
{0x1101,0x0101,0x1001,0x2100,0x1101,0x0101,0x61101,0x0011,0x521210,0x0112},
{0x0111,0x0101,0x0011,0x0110,0x0101,0x0101,0x0211,0xa41102,0x1111,0x1101},
{0x1001,0x0010,0x1100,0x1001,0x0100,0x0201,0x451112,0x0201,0x1012,0x0100},
{0x0101,0x1101,0x0101,0x0011,0x0110,0x0101,0x1011,0x0010,0x1100,0x0101},
{0x220201,0x0102,0x0101,0x1011,0x1010,0x0110,0x1011,0x1110,0x0101,0x0101},
{0x0101,0x0111,0x0011,0x1010,0x351110,0xb31021,0x1010,0x1010,0x0110,0x0101},
{0x0011,0x1010,0x1010,0x151110,0x71011,0xc52110,0x451011,0x1010,0x1010,0x0110}
          },
          {//2nd floor
{0x351101,0x1011,0x1100,0x1001,0x1010,0x1010,0x1100,0x1011,0x1110,0x71101},
{0x0011,0x1100,0x0111,0x0101,0x1001,0x1100,0x0011,0x1010,0x521200,0x0112},
{0x1111,0x0001,0x1010,0x0100,0x0001,0x0010,0x1010,0x1100,0x0101,0x1101},
{0x1011,0x0110,0x1111,0x0101,0x0111,0x1101,0x71101,0x0111,0x0101,0x0101},
{0x1101,0x1001,0x1200,0x0002,0x1010,0x0100,0x0211,0xa41102,0x0101,0x0101},
{0x0201,0x0012,0x0110,0x0111,0x1111,0x0011,0x1010,0x0110,0x0101,0x0111},
{0x0011,0x1100,0x951121,0x1101,0x651121,0x1001,0x1000,0x1010,0x0010,0x1100},
{0x1101,0x0011,0x2020,0x0000,0x2020,0x0000,0x0100,0x1011,0x1110,0x0101},
{0x0011,0x1100,0x852111,0x0101,0x752111,0x0001,0x0010,0x1010,0x1010,0x0100},
{0x1111,0x0011,0x1010,0x0010,0x1010,0x0110,0x1011,0x1010,0x1110,0x0111}
          }
  };

        Sample24_01 mapper = new Sample24_01(map3D, 0, 1, 0);

        String[] msgs = {
          null,
          "ゴールはこの裏です。",
          "準備中。",
          "よくぞお越しくださいました。",
          "またのお越しをお待ちしております。",
          "非常階段",
          "大安吉日にございます。",
          "どうぞお気遣いなく。",
          "警備は万全にございます。",
          "眠ってはなりませぬ。",
          "階段",
          "EXIT",
          "おめでとうございます。",
          null,
          null,
          null
        };
        mapper.setMsgArray(msgs);

        boolean in_map = true;

        System.out.println(mapper.getPos());

        while(in_map){

          Integer oi = Scan.getInteger("> ");

          if(oi != null){
            switch(oi){
              case 8:
                boolean pass = mapper.toForward();
                if(!pass){
                    System.out.println("ouch!");
                }
                break;
              case 6:
                mapper.toRight();
                break;
              case 2:
                mapper.lookBack();
                break;
              case 4:
                mapper.toLeft();
                break;
              case 5:
                Cell cell = mapper.rotatePosCell(0, 0);
                String WallString = cell.toWallString();
                System.out.println("\n"+WallString+"\n");
                  break;
              case 0:
                System.exit(0);
                break;

            }
            System.out.println(mapper.getPos());
            String msg = mapper.message();
            if(msg != null){
              System.out.println(msg);
            }
            boolean action = mapper.action();

            in_map = !mapper.isOut();

            if(action) {
              System.out.println(mapper.getPos());
            }
          }
       }
       System.out.println("out");
    }
}

//Cell.java
public class Cell {
  /*
    0x_76543210
    4bit x 8unit
  */
  private static final int INDEX_F = 3;
  private static final int INDEX_R = 2;
  private static final int INDEX_B = 1;
  private static final int INDEX_L = 0;

  private int value;//4bit x 8unit

  public Cell(int value){
    this.value = value;
  }

  public Cell rotateCell(int direction){
    int r16 = value & 0xffff;
    int l16 = value & 0xffff0000;
    int part1 = r16<<(direction*4)& 0xffff;
    int part2 = r16>>>((4-direction)*4)& 0xffff;
    return new Cell(l16 | part1 | part2);
  }

  public int getValue(){
    return value;
  }
  public int getBit4(int index){
    return value>>>(index*4) & 0xf;
  }
  public int getF(){
    return getBit4(INDEX_F);
  }
  public int getR(){
    return getBit4(INDEX_R);
  }
  public int getB(){
    return getBit4(INDEX_B);
  }
  public int getL(){
    return getBit4(INDEX_L);
  }

  public String toWallString(){

  String form = "  %x  \t^\n%x + %x\t^ Forward\n  %x  \t^";
    String str = String.format(form,
        getBit4(INDEX_F),
        getBit4(INDEX_L),
        getBit4(INDEX_R),
        getBit4(INDEX_B)
    );
    return str;
  }
}

コマンドライン
>cd ws
ws>javac -encoding UTF-8 Sample24_01.java
ws>java Sample24_01




3.動作確認

コマンドライン
>cd ws
ws>javac -encoding UTF-8 Sample24_01.java
ws>java Sample24_01
1F ( 0,  1) NORTH
> 8
1F ( 0,  2) NORTH
> 8
1F ( 0,  3) NORTH
> 8
1F ( 0,  4) NORTH
> 8
ouch!
1F ( 0,  4) NORTH
> 5

  1     ^
1 + 0   ^ Forward
  0     ^

1F ( 0,  4) NORTH
> 6
1F ( 0,  4) EAST
>
----------------------------------------------
            中略
----------------------------------------------
1F ( 6,  1) WEST
> 8
1F ( 5,  1) WEST
> 4
1F ( 5,  1) SOUTH
EXIT
> 8
1F ( 5,  0) SOUTH
おめでとうございます。
> 6
1F ( 5,  0) WEST
> 8
1F ( 4,  0) WEST
上り階段があります。 昇りますか?(Y/N): y
0F ( 4,  0) WEST
out


アハハ!
動いた動いた!
入力のたびに[Enter]キーを
押さないといけないのがうざいなぁ。
暗闇感があって
意外とおもしろいっスよ?
でもこれ
マップが無いと
さすがにキツイわね。
1F/2F マップ
画像をクリックして拡大しよう。

それじゃあ早速
次のページから
プログラムの説明をしよう。


お疲れ様でした。


© 2019 awasekagami