java_文字城堡游戏(翁恺)(我稍微补了些提示性语句,以及落入陷阱的情况判断)

本程序包括了oop的,抽象,继承,封装,多态,低耦合,易扩展,框架化+数据的特性.

package oop.example;
/*一个代码单元应该负责一个聚合的任务(也就是说,一个任务可以被看作是 一个逻辑单元)。一个方法应该实现一个逻辑操作,而一个类应该代表一定类型的实体。聚合 理论背后的要点是重用:如果一个方法或类是只负责一件定义明确的事情,那么就很有可能在 另外不同的上下文环境中使用。遵循这个理论的一个额外的好处是,当程序某部分的代码需要 改变时,在某个代码单元中很可能会找到所有需要改变的相关代码段。
从程序中识别出框架和数据,以代码实现框架,将部分功能以数据的方式加载,这样能在很大程度上实现可扩展性。*/
import java.util.HashMap;
import java.util.Scanner;
import java.util.logging.Handler;/*这是IDEA自动导入带来的坑,要么关闭自动导入(但是我觉得为Handler换个名字比较实在(和系统类名,本来就不建议嘛)
为此,我吃了不少苦头,一直感觉莫名其妙,以后遇到类似的多态报错问题,可以怀疑下是否和系统中的某个包下的类名冲突了(主要是自动导入功能要注意的)
还有eclipse虽然打开慢,但是编译运行快,不过它的报错似乎无法向idea那样及时的自动更新状态.
其实,IDEa的自动导入和自动优化导包虽然不错,但还算不上完美(自动优化可能会将你刚导入的还未用的包个删掉);
因此当出现了莫名其妙的错误时,导入的包也要看是否有多余的东西,不能完全依赖idea的自动化.*/

public class Game {
    /*成员域有一个Room引用类,一个HashMap容器,存储功能映射*/
    private Room currentRoom;
    private HashMap<String, Handlerr> handlers = new HashMap<>();
/*Game主公共类的构造器constructor*/
    public Game() {
        /*这里用到的this是当前这个Game对象的引用(会在main(args)时实例化出一个游戏game对象.*/
       // System.out.println(this.getClass().getName());//查看一下this所指对象是啥类型(Game)
        //该构造器将 功能字符串和对应的功能类(Handler的若干子类)建立映射关系放入handlers容器中
        /*从程序中识别出框架和数据,以代码实现框架,
        将部分功能以数据的方式加载,(比如下面的操作)这样能在很大程度上实现可扩展性。*/
        handlers.put("bye", new HandlerBye(this));
        handlers.put("help", new HandlerHelp(this));
        handlers.put("go", new HandlerGo(this));
        createRooms();

    }
/*创建房间以及内置出口信息*/
    public void createRooms() {
        Room outside, lobby, pub, study, bedroom;/*多余的逗号导致会错误全线变量混乱*/
        //创建房间
        lobby = new Room("大堂");
        study = new Room("书房");
        outside = new Room("城堡外");
        pub = new Room("酒吧");
        bedroom = new Room("卧室");
        //初始化出口(同一个方间可以设置多个出口.(出口方向所通向的房间)
        /*然而,这里的通路需要小心,每个房间都应该有去有回,如果进入到一个新地方后没有提供通路,那就困死在里面啦.*/
        lobby.setExit("south", outside);
        lobby.setExit("west", bedroom);

        pub.setExit("west", outside);
        study.setExit("south", lobby);
        outside.setExit("east", pub);
        outside.setExit("north", lobby);
        bedroom.setExit("east", lobby);
/*初始化当前所在房间(位置)为outside(城堡外面)*/
        currentRoom = outside;
    }

    public void printWelcome() {
        System.out.println();
        System.out.println("欢迎!");
        System.out.println();
        System.out.println("这是一个超级无聊的城堡游戏");
        System.out.println();
        System.out.println("如果你需要帮助请输入:help");
        System.out.println();
        System.out.println("那么现在开始吧!");
        System.out.println();
        //System.out.println("你现在在" + currentRoom + " " + currentRoom.getExitDesc());
        showPrompt();
        System.out.println();
    }

    //以下为提供用户(玩家)的命令(操作):
    /*不过此前应给创建好各个房间以及内置存储了各个房间可走的方向-下个位置房间键值对的信息.*/
    public void goRoom(String dir) {
        Room nextRoom = currentRoom.getExit(dir);
        if (nextRoom == null) {
            System.out.println("那里没有门");
        } else {
            currentRoom = nextRoom;//更新currentRoom.
            /*System.out.println("你现在在" + currentRoom + " " + currentRoom.getExitDesc());
            System.out.println();*/
            showPrompt();
        }
    }
/*showPrompt附属个goRoom()方法,以便反馈操作的结果*/
    public void showPrompt() {
        System.out.println("你在" + currentRoom);
        System.out.print("出口有: ");
        System.out.println(currentRoom.getExitDesc());
        System.out.println();
    }
/*开始游戏:*/
    public void play() {
        Scanner in = new Scanner(System.in);//创建一个Scanner对象;
        while (true) {
            System.out.println("输入您的指令:");
            String line = in.nextLine();//读入玩家的操作字符串
            String[] words = line.split(" ");//预备解析玩家的操作,将处理的结果存入到一个String 数组中
            Handlerr handler;//声明一个功能类对象的引用(对象管理者)
            //handlers容器是装载着功能类的对象(handlers容器对象属于Game对象)
            handler = handlers.get(words[0]);/* 执行处理第一个词语解析:查询word[0]动作将对用什么操作(功能);
                                            返回一个功能类即Handlerr类的对象(到这里,handler已经指定好了功能对象(可能是
                                            HandlerGo/HandlerHelp/HandlerBye中的某一个*/
            /*为了提高健壮性,设置一个过渡字符串变量value*/
            String value = " ";
            if (words.length >= 2) {
                /*有两个词语的合法操作中,第二个词一定是方向*/
                value = words[1];
            }
            /*如果上头返回的handler功能存在(即handler!=null):*/
            if (handler != null) {

                handler.doCmd(value);/*通过功能类对象调用对应的功能(当然,现在提供的操作中有第二个词的只有go dir,ye也就是说,value如果非空且合法的话,应该是east/west/north/south中的某个*/
            /*游戏是否终止的检查阶段:*/
                if(!currentRoom.isSave()){break;}//当前是否落入死胡同.//此外,如果isSave()的具体实现在Room中发生变化,只要功能还是一样,就不会影响当前代码;
                /*bye操作比较特殊,在所有的玩家可执行的操作功能的功能对象中都从handlerr父类那里继承过了isBye()方法,只不过,
                仅在通过HandlerBye功能对象调用isBye()方法判断结果是才返回true,默认情况下继承过来的都是return false的操作
                即特地地判断一下是否终止游戏.(通过检查handler是否发出终止的信号(return true)*/
                if (handler.isBye()) {
                    break;
                }
            }

        }
        in.close();//结束从Console的输入需求
    }

    public static void main(String[] args) {
        Game game=new Game();
        game.printWelcome();
        game.play();
        System.out.println("感谢您的光临。再见!");
    }
}

package oop.example;

import java.util.HashMap;

class Room {
    private String description;
    boolean isOk=true;
    /*设有一个容器*/
    private HashMap<String, Room> exits = new HashMap<String, Room>();//String型对象保存方向的字符串,Room型对象为房间
//constructor:描述这是个什么房间:
    public Room(String description) {
        this.description = description;
    }
//重写toString以便打印对象(的指定属性(字段))
    public String toString() {
        return description;
    }

    //设置(该房间指定出口方向通往的房间)(具体实现是将dir和room映射对放入容器exits对象中
    public void setExit(String dir, Room room) {
        exits.put(dir, room);
    }
//获取出口的描述信息:(将容器中保存的键(房间名)打印出来
    public String getExitDesc() {
        StringBuffer sb = new StringBuffer();//StringBuffer对象中的内容可以方便变动,开销较小
        int cnt=0;
        for (String s : exits.keySet()) {//迭代容器exits中保存的键值.
            sb.append(s);//挨个地将内容(这里是表示方向的字符串)添加到StringBuffer对象中.
            sb.append(" ");//追加一个空格来隔开,
            cnt++;
        }//这样就达到提示玩家,当前有那些方向可以走
        //统一处理这些字符串
        if(cnt==0){
            System.out.print("没有其他方向可走啦,");
            System.out.print("你落入陷阱了!!\n 游戏结束!");
            isOk=false;
        }
        return sb.toString();//返回字符串
    }
//获取当前房间执行go direction操作时将会到达那个地方(房间)(这一个方法也是提供给game的接口
    public Room getExit(String direction) {
        return exits.get(direction);
    }
public boolean isSave(){return  isOk;}

}


package oop.example;

abstract class Handlerr {
    protected Game game;

    /*在Handler类中创建一个Game对象的引用(管理者而已),用来记住*/
    public Handlerr(Game game) {
        this.game = game;
    }
    public boolean isBye() {
        return false;
    }
/*必须重写的*/
    public abstract void doCmd(String cmd) ;
}

package oop.example;

class HandlerBye extends Handlerr {
    public HandlerBye(Game game) {
        super(game);/*super()在不同的子类(继承自不同父类)的时候,所代表的的方法也不同,此处是
        oop.example.Handlerr @Contract(pure = true)
public Handlerr(Game game) 即当前类的父类Handlerr类的构造方法.*/
        /*当然,super一般不用写,系统会自加上,淡入如果构造器有参数的时候,那么就需要传参个super()了*/
    }
/*super()方法:(直接父类对象的引用。可以通过super.*来
访问和调用父类中被子类覆盖(重写)的方法或属性)*/
    @Override
    public boolean isBye() {
        return true;
    }

    @Override
    public void doCmd(String cmd) {
        /*空*/
    }

}

package oop.example;
public class HandlerGo extends Handlerr {
    public HandlerGo(Game game) {
        super(game);
    }
    @Override
    public void doCmd(String cmd) {
        game.goRoom(cmd);
    }


}

package oop.example;


public class HandlerHelp extends Handlerr {
    public HandlerHelp(Game game) {
        super(game);
    }

    @Override
    public void doCmd(String cmd) {
        System.out.println("迷路了吗?可以输入:go/bye/help 如:\t go east");
    }


}


posted @ 2024-06-12 12:15  xuchaoxin1375  阅读(64)  评论(0)    收藏  举报  来源