推箱子——Java控制台版

package com.bao.txz;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

/**
 * 推箱子(控制台版)
 *
 * 2021.11.07
 * @author 尘客
 * @version v1.0_bao
 */
public class Txz {
    private Scanner sc; // 扫描器
    private Random rd; // 随机器

    private int[][] map; // 地图
    private int high = 10; // 地图高
    private int width = 10; // 地图宽
    private int playerX, playerY; // 玩家坐标
    private int boxX, boxY; // 箱子坐标
    private int terminusX, terminusY; // 终点坐标

    private boolean pd = false; // 判断玩家坐标是否和终点坐标重合
    private boolean exit = false; // 是否退出

    private List<int[][]> maps; // 地图集合 记录玩家走过的地图

    /**
     * 无参构造方法
     * 默认地图的大小为 10*10
     */
    public Txz() {
        sc = new Scanner(System.in); // 初始化扫描器
        rd = new Random(); // 初始化随机器
        map = new int[high][width]; // 初始地图大小
        maps = new ArrayList<>(); // 初始地图集合
    }

    /**
     * 有参构造方法 默认地图的大小为 10*10 如果用户设定的地图大小小于 3*3,则使用默认地图大小
     *
     * @param high  初始地图的高
     * @param width 初始地图的宽
     */
    public Txz(Integer high, Integer width) {
        sc = new Scanner(System.in); // 初始化扫描器
        rd = new Random(); // 初始化随机器
        // 地图大小最小必须3*3
        if (high > 2 && width > 2) {
            this.high = high; // 改变地图高为用户设定的值
            this.width = width; // 改变地图宽为用户设定的值
        }
        map = new int[this.high][this.width]; // 初始地图大小

        maps = new ArrayList<>(); // 初始地图集合
    }

    /**
     * 推箱子的启动方法
     */
    public void startTxz() {
        myRandom(); // 初始玩家,终点,箱子的位置

        map[playerX][playerY] = 1; // 玩家坐标对应的值
        map[boxX][boxY] = 2; // 箱子坐标对应的值
        map[terminusX][terminusY] = 3; // 终点坐标对应的值

        plan(); // 将初始地图加入地图集合

        // 死循环
        while (true) {
            InitializationMap(); // 初始化地图

            try {
                GoIntoAction(); // 玩家行动
                // ArrayIndexOutOfBoundsException 下标越界异常 表示玩家或者箱子移出了地图范围
            } catch (ArrayIndexOutOfBoundsException e) {
                System.err.println("提示:您已越界,游戏失败!");
                // 退出循环
                break;
            }

            // 如果为true,代表用户输入退出指令
            if (exit) {
                System.err.println("提示:您已退出游戏!");
                // 退出循环
                break;
            }

            //箱子的坐标与终点坐标重合,表示到达终点
            if (boxX == terminusX && boxY == terminusY) {
                // 恭喜过关
                CongratulationsToPass();
                // 退出循环
                break;
            }
        }
    }

    /**
     * 恭喜过关
     */
    private void CongratulationsToPass() {
        // 将过关之后的地图显示
        InitializationMap();
        myFormatPrintln(32, null, 1, "※※※※※※※※※※※※※※※");
        myFormatPrintln(32, null, 1, "※■■■■■■■■■■■■■※※");
        myFormatPrintln(32, null, 1, "※■■■■恭喜过关!■■■■※※");
        myFormatPrintln(32, null, 1, "※■■■■■■■■■■■■■※※");
        myFormatPrintln(32, null, 1, "※※※※※※※※※※※※※※※");
    }

    /**
     * 玩家行动
     */
    private void GoIntoAction() {
        myFormatPrintln(35, null, 1, "移动指示:上-w 下-s 左-a 右-d 返回上一步-z 退出游戏-e");
        myFormatPrint(35, null, 1, "请输入:");
        // 用户输入操作
        String move = sc.next();
        if ("e".equals(move)) {
            exit = true;
        } else if ("z".equals(move)) {
            // 地图集合的大小必须大于1,代表玩家已经走过(1为初始地图)
            if (maps.size() > 1) {
                // 定义一个二维数组,接收当前地图的上一个地图数据
                int[][] newMap = maps.get(maps.size() - 2);
                // 将二维数组的数据复制给地图
                for (int i = 0; i < high; i++) {
                    for (int j = 0; j < width; j++) {
                        map[i][j] = newMap[i][j];
                        // 将玩家的坐标更改为上一个地图
                        if (newMap[i][j] == 1) {
                            playerX = i;
                            playerY = j;
                        }
                        // 将箱子的坐标更改为上一个地图
                        else if (newMap[i][j] == 2) {
                            boxX = i;
                            boxY = j;
                        }
                        // 终点坐标是不变的,无需更改
                    }
                }

                // 将当前地图从地图集合中移除
                maps.remove(maps.size() - 1);
            } else {
                System.err.println("已退到初始状态,不可再退!");
                // 要求用户重新输入操作
                GoIntoAction();
            }
        }
        // 判断是否是上,下,左,右指令
        else if (!"w".equals(move) && !"s".equals(move) && !"a".equals(move) && !"d".equals(move)) {
            System.err.println("指令错误,请重新输入!");
            // 要求用户重新输入操作
            GoIntoAction();
        } else {
            // 如果玩家坐标和终点坐标重合
            if (map[playerX][playerY] == map[terminusX][terminusY]) {
                // 将判断改为true
                pd = true;
            } else {
                // 将判断改为false
                pd = false;
            }
            // 上
            if ("w".equals(move)) {
                // 如果玩家的x坐标减1,等于箱子的坐标,表示箱子在玩家上方
                if (map[playerX - 1][playerY] == map[boxX][boxY]) {
                    // 箱子x坐标减1
                    boxX--;
                    // 表示箱子向上移动一格
                    map[boxX][boxY] = 2;
                }
                // 判断玩家,终点坐标是否重合
                easy();
                // 玩家x坐标减1
                playerX--;
                // 表示玩家向上移动一格
                map[playerX][playerY] = 1;
            }
            // 下
            else if ("s".equals(move)) {
                // 如果玩家的x坐标加1,等于箱子的坐标,表示箱子在玩家下方
                if (map[playerX + 1][playerY] == map[boxX][boxY]) {
                    // 箱子x坐标加1
                    boxX++;
                    // 表示箱子向下移动一格
                    map[boxX][boxY] = 2;
                }
                // 判断玩家,终点坐标是否重合
                easy();
                // 玩家x坐标加1
                playerX++;
                // 表示玩家向下移动一格
                map[playerX][playerY] = 1;
            }
            // 左
            else if ("a".equals(move)) {
                // 如果玩家的y坐标减1,等于箱子的坐标,表示箱子在玩家左方
                if (map[playerX][playerY - 1] == map[boxX][boxY]) {
                    // 箱子y坐标减1
                    boxY--;
                    // 表示箱子向左移动一格
                    map[boxX][boxY] = 2;
                }
                // 判断玩家,终点坐标是否重合
                easy();
                // 玩家y坐标减1
                playerY--;
                // 表示玩家向左移动一格
                map[playerX][playerY] = 1;
            }
            // 右
            else if ("d".equals(move)) {
                // 如果玩家的y坐标加1,等于箱子的坐标,表示箱子在玩家右方
                if (map[playerX][playerY + 1] == map[boxX][boxY]) {
                    // 箱子y坐标加1
                    boxY++;
                    // 表示箱子向右移动一格
                    map[boxX][boxY] = 2;
                }
                // 判断玩家,终点坐标是否重合
                easy();
                // 玩家y坐标减1
                playerY++;
                // 表示玩家向右移动一格
                map[playerX][playerY] = 1;
            }

            // 将更新的地图加入地图集合
            plan();
        }
    }

    /**
     * 判断玩家坐标是否和终点坐标重合
     */
    private void easy() {
        // 如果为true,代表玩家坐标已经和终点坐标重合,玩家移动后,需要将终点重新显示
        if (pd) {
            map[playerX][playerY] = 3;
        } else {
            map[playerX][playerY] = 0;
        }
    }

    /**
     * 将地图加入地图集合
     */
    private void plan() {
        // 定义一个二维数组
        int[][] newMap = new int[high][width];

        // 将当前地图的数据复制给新定义的二维数组
        for (int i = 0; i < high; i++) {
            for (int j = 0; j < width; j++) {
                newMap[i][j] = map[i][j];
            }
        }

        // 将复制的二维数组加入地图集合
        maps.add(newMap);
    }

    /**
     * 初始化地图
     */
    private void InitializationMap() {
        myFormatPrintln(31, null, 1, "***************************************");
        // 记录玩家步数,需要减去初始化地图
        myFormatPrintln(31, null, 1, "步数:" + (maps.size() - 1));

        // 初始化地图
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                if (map[i][j] == 1) {//玩家
                    myFormatPrint(31, null, 1, "♀ ");
                } else if (map[i][j] == 2) {//箱子
                    myFormatPrint(34, null, 1, "■ ");
                } else if (map[i][j] == 3) {//终点
                    myFormatPrint(33, null, 1, "★ ");
                } else {//地图
                    myFormatPrint(32, null, 1, "□ ");
                }
            }
            System.out.println();
        }
    }

    /**
     * 初始化玩家,终点,箱子的位置
     */
    private void myRandom() {
        //随机玩家,终点,箱子的x
        int x = rd.nextInt(high);
        playerX = x;
        x = rd.nextInt(high);
        terminusX = x;
        //箱子的x不能是0或最后一个元素
        x = rd.nextInt(high - 2) + 1;
        boxX = x;

        // 存储玩家,终点,箱子y
        List<Integer> randoms = new ArrayList<>();
        for (int i = 0; i < width; i++) {
            randoms.add(i);
        }

        //随机玩家的y
        int i = rd.nextInt(randoms.size());
        Integer y = randoms.get(i);
        playerY = y;

        //如果玩家的x等于终点或箱子的x,则移除已占用的y
        if (playerX == terminusX || playerX == boxX) {
            randoms.remove(i);
        }

        //随机终点的y
        i = rd.nextInt(randoms.size());
        y = randoms.get(i);
        terminusY = y;

        //如果终点的x等于箱子的x,则移除已占用的y
        if (terminusX == boxX) {
            randoms.remove(i);
        }

        //箱子的y不能是0或最后一个元素,需要移除
        Integer z = 0;
        randoms.remove(z);
        z = width - 1;
        randoms.remove(z);

        //判断y坐标的集合是否为空,不为空才可随机箱子的y
        if(randoms.size() > 0){
            //随机箱子的y
            i = rd.nextInt(randoms.size());
            y = randoms.get(i);
            boxY = y;
        }
        else{
            myRandom();
        }
    }

    /**
     * 格式化输出
     *
     * @param fontColor       字体颜色
     * @param backgroundColor 背景颜色
     * @param fontStyle       字体样式
     * @param content         输出内容
     */
    private void myFormatPrint(Integer fontColor, Integer backgroundColor, Integer fontStyle, String content) {
        if (null == backgroundColor && null == fontStyle) {
            System.out.format("\33[%d;%s", fontColor, content);
        } else if (null == backgroundColor) {
            System.out.format("\33[%d;%dm%s", fontColor, fontStyle, content);
        } else if (null == fontStyle) {
            System.out.format("\33[%d;%d;%s", fontColor, backgroundColor, content);
        } else {
            System.out.format("\33[%d;%d;%dm%s", fontColor, backgroundColor, fontStyle, content);
        }
    }

    /**
     * 格式化输出 换行
     *
     * @param fontColor       字体颜色
     * @param backgroundColor 背景颜色
     * @param fontStyle       字体样式
     * @param content         输出内容
     */
    private void myFormatPrintln(Integer fontColor, Integer backgroundColor, Integer fontStyle, String content) {
        if (null == backgroundColor && null == fontStyle) {
            System.out.format("\33[%d;%s%n", fontColor, content);
        } else if (null == backgroundColor) {
            System.out.format("\33[%d;%dm%s%n", fontColor, fontStyle, content);
        } else if (null == fontStyle) {
            System.out.format("\33[%d;%d;%s%n", fontColor, backgroundColor, content);
        } else {
            System.out.format("\33[%d;%d;%dm%s%n", fontColor, backgroundColor, fontStyle, content);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

予神佚名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值