java简单模拟五子棋(存盘退出和续上盘)

需求

编写一个五子棋程序, 要有存盘退出和续上盘的功能,怎么保存棋盘数据?

tip:为了方便,不需要输入密码什么的,只要实现五子棋,存盘退出和续上盘就可以

棋盘为: 43*42

思考

 思考:
        1、保存和记忆功能。也就是整个程序退出之后,会把内存的数据记忆到硬盘中
            * 将数据保存到一个txt中

        2、初始化时:
            *  路径下已经有了txt了
                * txt是空的,这是第一局
                * 如果txt中已经有了历史数据,从txt中读取历史数据,用来初始化内存即可
            * 路径下没有有了txt了,这是第一局,那么从头开始初始化(棋盘)
                *  五子棋可以用一个二维数组表示, 为了方便,暂时将数组初始化为47*44,初始时所有数据都是0
                (两个第一局啊,可以综合下)

        3、下棋中:
            * 1表示白方,2表示黑方,保证两方交替执行(不知道别人是怎么做的,反正我保证,因此下棋时只需要告诉x, y的坐标)
                * 需要一个标志来记录下一局是谁下, 初始化一个flag = 1(白字先行),当下完一个棋子之后flag=2, 在一个flag=1
                *  为了方便,我这里规则x,y的(0, 0)为左上角,就是和二维数组的索引一样
            * 棋子的数量是有限的, 当填满整个棋盘时退出,因此每次下完一个棋子就要判断棋盘是不是满了

        4、有关退出:
            退出有两种情况
            * 异常退出(这个想不出来有什么情况)
            * 不想下了:
                当有人(关闭程序---这个没法,因为我这里是cmd型)输入字母q时表示他不想下了:
                    * 问他是否真的要退出
                        * 如果是:
                            * 问他是不是要保存此次的棋盘,
                                * 如果是,保存到txt中:
                                    * 如果txt不存在,创造txt,并且将当前棋势写入txt
                                    * 如果已经存在txt,清空上次的内容,并且将当前棋势写入txt(覆盖写)
                                * 如果不是,清空txt
                        * 如果不是:继续让他输入坐标
           * 胜负已分: 也就是棋盘满了,这个时候(因为不懂怎么下围棋的,而且因为是轮流下的12的数量是一样的)就直接输出“当前局已经结束”,
           然后将txt中的内容清除直接退出就好(当前局已经结束,下一句一定是新的一局)
                * 如何判断棋盘是否已经满了: 二维数组元素最多只可以有row * line个,(初始化一个count),记录当前棋子数。。。。

                txt中存储的内容: 二维数组,当前棋子数,下一次谁下。
                    用txt不方便,这里我用yaml
                    flag: 1
                    count:2,
                    array: ******



           总结:用到的知识
            *   操作文本
                * 检查路径下文本是否存在
                * 判断文本内容是否为空
                * 从文本冲读取内容
                * 覆盖写入文本
                * 清空文本内容
                * 解析写入yaml
            * 操作二维数组
                * 二维数组初始化
                * 填充二维数组

准备知识

1、学习yaml

博客

2、操作文件

  • 检查路径下文本是否存在
        Yaml yaml = new Yaml();//该YAML类是API的入口点:由于实现不是线程安全的,因此不同的线程必须具有自己的Yaml实例

        // 加载文档
        InputStream input = SnakeYaml.class.getClassLoader().getResourceAsStream("sparse.yaml"); // 不能是./src/main/resources/sparse.yaml
        if (input == null){      // 如果input == null则表示resources下没有customer.yaml文件
            File file = new File("./src/main/resources/sparse.yaml");
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        System.out.println(input);

开始做项目

第一版

1、这是一个不使用框架的maven工程,其项目目录

在这里插入图片描述

2、pom.xml中引入坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.oceanstar</groupId>
    <artifactId>Sparse</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.23</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

3、util.java

import java.util.Scanner;

public class util {
    private static Scanner scanner = new Scanner(System.in);

    // 一定能得到n位数
    public static String readKeyBoard(int limit) {
        String line = "";

        while (scanner.hasNext()) {
            line = scanner.nextLine();
            if (line.length() < 1 || line.length() > limit) {
                System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
                continue;
            }
            break;
        }

        return line;
    }

    public static char readConfirmSelection(){
        char c;
        for (; ; ) {
            String str = readKeyBoard(1);
            c = str.charAt(0);
            if (c != 'Y' && c != 'y' && c != 'N' && c != 'n') {
                System.out.print("选择错误,请重新输入:");
            } else
                break;
        }
        return c;
    }

    // 直到输入正确才能跳出循环
    // 参数是输入数据的范围:返回值必须在[min, max]范围内
    public static int readNumber(int min, int max){
        int i = 0;
        for (; ; ) {
            String str = readKeyBoard(2);
            try {
                i = Integer.parseInt(str);
                if (i < min || i > max){
                    throw new Exception("插入范围必须在[" + min + ", " + max + "]内");
                }
                break;
            }catch (Exception e){
                System.out.print("超出坐标范围:");
            }
        }
        return i;
    }

}

4、Chessboard.java

import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.Arrays;

public class Chessboard {
    private int flag;
    private int count;
    private int[][] array;
    private Yaml yaml = new Yaml();
    private String path = System.getProperty("user.dir") + "/src/main/resources/Chessboard.yaml";

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        if (flag != 1 && flag != 2){
            System.out.println("sorry, flag取值只能为1或者2");
            return;
        }
        this.flag = flag;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int[][] getArray() {
        return array;
    }

    public void setArray(int[][] array) {
        this.array = array;
    }

    @Override
    public String toString() {
        return "Chessboard{" +
                "flag=" + flag +
                ", count=" + count +
                ", array=" + Arrays.deepToString(array) +
                '}';
    }

    private void changeflag(){
        if (flag == 1){
            flag = 2;
        }else{
            flag = 1;
        }
    }

    private boolean canInput(int x, int y){
        return array[x][y] == 0;
    }

    // 下棋: 输入一定是正确的
    public boolean playChess(int x, int y){
        // 下棋之前检测这个位置是不是可以下
        if (!canInput(x, y)){
            return false;
        }

        // 下棋
        array[x][y] = flag;
        // 下棋之后:
        changeflag(); // 下一次轮换
        count--; // 棋子少了一个
        return true;
    }

    // 棋盘是否满了
    public boolean fullChess(){
        return count == 0;
    }

    // 确认
    public boolean isComfirm(){
        char s =  util.readConfirmSelection();
        return  s == 'Y' || s == 'y';
    }


    // 打印棋局
    public void printChessboard(){
        for (int i = 0; i < this.array.length; i++){
            for (int j = 0; j < this.array[i].length; j++){
                System.out.printf("%d\t", this.array[i][j]);
            }
            System.out.println();
        }
    }

    // 初始化时从磁盘读取保存的棋局
    public  Chessboard readChessboard() {
        File file =new File(path);
        if (!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


        Chessboard c = yaml.loadAs(inputStream, Chessboard.class);
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return  c;
    }


    public void clearInfoForFile(){
        File file =new File(path);
        FileWriter fileWriter = null;
        try {
            if(!file.exists()) {
                file.createNewFile();
            }
            fileWriter = new FileWriter(file);
            fileWriter.write("");
            fileWriter.flush();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //
    public  void wirterChessboard(){
        Chessboard c = new Chessboard();
        c.setCount(this.count);
        c.setFlag(this.flag);
        c.setArray(this.array);
        try {
            FileWriter writer = new FileWriter(path);
            yaml.dump(c, writer);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5、Alphago

import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.Scanner;

public class Alphago {
    private static  Chessboard c = new Chessboard();  // 只有一个棋盘
    private static int heng ;
    private static int zong ;


    private static void initAlphago(){
        Chessboard temp = c.readChessboard(); // 读取磁盘
        boolean  continue_chess  = false ;  // 是否继续上一次的棋局
        if (temp != null){
            System.out.print("检测到有棋局未完成, 是否继续(Y/N), 如果否, 将开始一个新的棋局:");
            continue_chess = c.isComfirm();
        }


        // 继续上一局
        if (continue_chess){
            c = temp;
        }else{  // 如果读取yaml为空,压根就没有上一次
            c.clearInfoForFile();  // 清除棋盘
            // 重新初始化一个棋盘
            c.setFlag(1);       // 白字先行
            c.setCount(heng*zong);  // 还剩下多少步
            int[][]arr = new int[heng][zong];  //  初始化棋盘
            c.setArray(arr);
        }
    }

    public static void main(String[] args) {
        System.out.print("请输入棋盘横长(0, 100):");
        heng =  util.readNumber(0, 100);
        System.out.print("请输入棋盘纵宽(0, 100):");
        zong =  util.readNumber(0, 100);
        // 初始化棋盘
        initAlphago();

       // 棋盘打印
       c.printChessboard();

       // 开始下棋
        for (; ;){
            // 输入坐标
            System.out.print("请输入x坐标(0, " + (heng-1) + "):");
            int x = util.readNumber(0, heng-1);
            System.out.print("请输入y坐标(0, " + (zong-1) + "):");
            int y = util.readNumber(0, zong-1);
            // 下棋
            if (!c.playChess(x, y)){
                System.out.println("当前位置已经有了棋子, 请另外选择位置");
                continue;
            }

            // 打印棋盘
            c.printChessboard();
            // 检测是不是棋盘满了
            if (c.fullChess()){
                System.out.println("棋盘满了, 是否开始下一局? 如果不是,将退出本程序(Y/N)");

                // 清空yaml:当前棋局结束了才清空
                c.clearInfoForFile();

                // 优化: 问是否要开始下一局
                if (!c.isComfirm()){
                    break;
                }

                // 重新初始化一个棋盘
                c.setFlag(1);       // 白字先行
                c.setCount(heng*zong);  // 还剩下多少步
                int[][]arr = new int[heng][zong];  //  初始化棋盘
                c.setArray(arr);
            }

            //还有下一次
            System.out.print("是否退出?(Y/N):");
            if (!c.isComfirm()){   // 不退出则继续下一次
                continue;
            }

           // 要退出
            System.out.print("是否保存当前棋局?(Y/N):");
            if (c.isComfirm()){  // 保存
                c.wirterChessboard();
            }
            break;
        }
    }

}


6、使用发现如果棋盘比较大,而下的棋子比较少,将会有大量的空间被浪费
在这里插入图片描述
优化:因为该二维数组中很多值都是默认0,因此记录了很多没有意义得数据,因此可以使用稀疏矩阵来优化

第二版

第1,2,3步同第一版

4、Chessboard.java

import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.Arrays;

public class Chessboard {
    private int flag; // 谁下
    private int count; // 还有几步
    private int[][] array; // 原始数组[下棋]
    private int[][] chessarr; // 稀疏数组
    /*
    *     row col  val
    *  0  heng zong 0  // 记录棋盘大小
    *  1   1 2    1    // 记录非0值
    * */
    private Yaml yaml = new Yaml();  // 用来写
    private String path = System.getProperty("user.dir") + "/src/main/resources/Chessboard.yaml";

    public int[][] getChessarr() {
        return chessarr;
    }

    public void setChessarr(int[][] chessarr) {
        this.chessarr = chessarr;
    }

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        if (flag != 1 && flag != 2){
            System.out.println("sorry, flag取值只能为1或者2");
            return;
        }
        this.flag = flag;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int[][] getArray() {
        return array;
    }

    public void setArray(int[][] array) {
        this.array = array;
    }

    @Override
    public String toString() {
        return "Chessboard{" +
                "flag=" + flag +
                ", count=" + count +
                ", array=" + Arrays.deepToString(array) +
                ", chessarr=" + Arrays.deepToString(chessarr) +
                '}';
    }

    private void changeflag(){
        if (flag == 1){
            flag = 2;
        }else{
            flag = 1;
        }
    }

    private boolean canInput(int x, int y){
        return array[x][y] == 0;
    }

    // 下棋: 输入一定是正确的
    public boolean playChess(int x, int y){
        // 下棋之前检测这个位置是不是可以下
        if (!canInput(x, y)){
            return false;
        }

        // 下棋
        array[x][y] = flag;
        // 下棋之后:
        changeflag(); // 下一次轮换
        count--; // 棋子少了一个
        return true;
    }

    // 棋盘是否满了
    public boolean fullChess(){
        return count == 0;
    }

    // 确认
    public boolean isComfirm(){
        char s =  util.readConfirmSelection();
        return  s == 'Y' || s == 'y';
    }


    // 打印棋局
    public void printChessboard(){
        for (int i = 0; i < this.array.length; i++){
            for (int j = 0; j < this.array[i].length; j++){
                System.out.printf("%d\t", this.array[i][j]);
            }
            System.out.println();
        }
    }

    // --------------初始化时从磁盘读取保存的棋局
    public  Chessboard readChessboard() {
        File file =new File(path);
        if (!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


        Chessboard c = yaml.loadAs(inputStream, Chessboard.class);
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return  c;
    }


    //-----------------清除磁盘-------------------------
    public void clearInfoForFile(){
        File file =new File(path);
        FileWriter fileWriter = null;
        try {
            if(!file.exists()) {
                file.createNewFile();
            }
            fileWriter = new FileWriter(file);
            fileWriter.write("");
            fileWriter.flush();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //------------------写入磁盘--------------------------------------------//
    public  void wirterChessboard(){
        Chessboard c = new Chessboard();
        c.setCount(this.count);
        c.setFlag(this.flag);

        // 遍历原始的二维数组,得到非0值得个数
        int sum = 0;
        for (int i = 0; i < array.length; i++){
            for (int j = 0; j < array[i].length; j++){
                if (array[i][j] != 0){
                    sum++;
                }
            }
        }

        //创建稀疏数组 chessarr[sum + 1][3]
        chessarr = new int[sum+1][3];
        // 第一行保存数组大小[至少有一行]
        chessarr[0][0] = array.length;
        chessarr[0][1] = array[0].length;
        chessarr[0][2] = -1; // 这个值随便

        int a = 1;
        // 将原始数组得非0值保存到稀疏数组中
        for (int i = 0; i < array.length; i++){
            for (int j = 0; j < array[i].length; j++){
                if (array[i][j] != 0){
                    chessarr[a][0] = i;
                    chessarr[a][1] = j;
                    chessarr[a][2] = array[i][j];
                    a++;
                }
            }
        }

        c.setChessarr(chessarr);

        try {
            FileWriter writer = new FileWriter(path);
            yaml.dump(c, writer);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


5、Alphago.java

import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.Arrays;
import java.util.Scanner;

public class Alphago {
    private static  Chessboard c = new Chessboard();  // 只有一个棋盘
    private static int heng ;
    private static int zong ;



    private static void initAlphago(){
        Chessboard temp = c.readChessboard(); // 读取磁盘
        boolean  continue_chess  = false ;  // 是否继续上一次的棋局
        if (temp != null){
            System.out.print("检测到有棋局未完成, 是否继续(Y/N), 如果否, 将开始一个新的棋局:");
            continue_chess = c.isComfirm();
        }
        c.clearInfoForFile();  // 清除棋盘

        if (!continue_chess){
            // 重新初始化一个棋盘
            System.out.print("请输入棋盘横长(0, 100):");
            heng = util.readNumber(0, 100);
            System.out.print("请输入棋盘纵宽(0, 100):");
            zong = util.readNumber(0, 100);

            c.setFlag(1);       // 白字先行
            c.setCount(heng*zong);  // 还剩下多少步
            int[][]arr = new int[heng][zong];  //  初始化棋盘
            c.setArray(arr);
        }else{

            c.setFlag(temp.getFlag());
            c.setCount(temp.getCount());

            int[][] aa = temp.getChessarr();
            // aa 至少有一行
            heng = aa[0][0];
            zong = aa[0][1];
            int[][]chess = new int[heng][zong];  //  初始化棋盘
            for (int i = 1; i < aa.length; i++){
                chess[aa[i][0]][aa[i][1]] = aa[i][2];
            }
            c.setArray(chess);

        }
    }

    public static void main(String[] args) {


        // 初始化棋盘
        initAlphago();

        // 棋盘打印
        c.printChessboard();

        // 开始下棋
        for (; ;){
            // 输入坐标
            System.out.print("请输入x坐标(0, " + (heng-1) + "):");
            int x = util.readNumber(0, heng-1);
            System.out.print("请输入y坐标(0, " + (zong-1) + "):");
            int y = util.readNumber(0, zong-1);
            // 下棋
            if (!c.playChess(x, y)){
                System.out.println("当前位置已经有了棋子, 请另外选择位置");
                continue;
            }

            // 打印棋盘
            c.printChessboard();
            // 检测是不是棋盘满了
            if (c.fullChess()){
                System.out.println("棋盘满了, 是否开始下一局? 如果不是,将退出本程序(Y/N)");

                // 清空yaml:当前棋局结束了才清空
                c.clearInfoForFile();

                // 优化: 问是否要开始下一局
                if (!c.isComfirm()){
                    break;
                }

                // 重新初始化一个棋盘
                c.setFlag(1);       // 白字先行
                c.setCount(heng*zong);  // 还剩下多少步
                int[][]arr = new int[heng][zong];  //  初始化棋盘
                c.setArray(arr);
            }

            //还有下一次
            System.out.print("是否退出?(Y/N):");
            if (!c.isComfirm()){   // 不退出则继续下一次
                continue;
            }

            // 要退出
            System.out.print("是否保存当前棋局?(Y/N):");
            if (c.isComfirm()){  // 保存
                c.wirterChessboard(); // 保存
            }
            break;
        }
    }

}

总结

基本介绍

在这里插入图片描述
在这里插入图片描述

应用实例

在这里插入图片描述

在这里插入图片描述

BIBI

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值