手把手教你用java OOP实现猜拳游戏!好玩有用!

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: 手把手教你用java OOP实现猜拳游戏!好玩有用!

猜拳游戏

结果呈现image.png

image.png

游戏规则类

public class Rule {
   
   
    /**输入工具:为什么要把Scanner作为属性存在?
     * 因为 输入姓名 和 输入有效的数值 都要运用到输入工具 写在属性就不用在各个方法中重复写 节省内存
     */
    private final Scanner INPUT = new Scanner(System.in);
    //随机工具
    private final Random RAND = new Random();
    //正则:两个以上的汉字
    private final String NAME_REGEX = "^[\u4e00-\u9fa5]{2,}$";
    //正则:数值
    private final String DIGIT_REGEX = "^[0-9]{1,}$";
    //拳谱
    private final String FIST = "布、剪、锤";
    //拳值数组
    private final String[] FISTS;
    //无参构造 给拳值数组赋值
    public Rule() {
   
   
        FISTS = FIST.split("、");
    }

    /**
     * 获取控制台输入一个有效昵称
     * @param title 输出提示主体
     * @return String
     */
    public String getInputName(String title){
   
   
        String name = null;
        System.out.printf("请输入"+title+"昵称:");
        do{
   
   
            name = INPUT.nextLine();
            if(name.matches(NAME_REGEX))
                break;
            System.out.println("昵称必须为两个汉字以上的形式!请重新输入:");
        }while(true);
        return name;
    }

    /**
     * 从控制台获取一个输入的整数
     * @param min 取值下限
     * @param max 取值上限
     * @return
     */
    public int getInputInt(String title,int min,int max){
   
   
        int digit = 0;
        do{
   
   
            System.out.print("请输入"+title+":");
            String num = INPUT.next();
            if(num.matches(DIGIT_REGEX)){
   
   
                digit = Integer.parseInt(num);
                if(digit >= min && digit <= max){
   
   
                    break;
                }
                System.out.println("数值必须位于"+min+"~"+max+"之间,请重新输入:");
            }
        }while(true);
        return digit;
    }

    /**
     * 获取控制台输入的有效拳值对应拳值数组的下标(索引)
     * @param nickname 出拳玩家的昵称
     * @return int 拳值对应的下标
     */

    public int getInputFistIx(String nickname){
   
   
        int fist = -1;
        System.out.print(nickname+"出拳:");
        do{
   
   
            String strFist = INPUT.nextLine();
            for (int i = 0; i < FISTS.length; i++) {
   
   
                if(strFist.equals(FISTS[i])){
   
   
                    fist = i;
                    break;
                }
            }
            if(fist >= 0)
                break;
            System.out.println("拳值必须为布、剪、锤,请"+nickname+"重新出拳");
        }while(true);
        return fist;
    }

    /**
     * 单局根据拳值下标之差判断输赢
     * @param humanFist 人类玩家的拳值
     * @param machineFist 机器玩家的拳值
     * @return int(0:平局,1/2:人类玩家胜利,-1/-2:机器玩家胜利)
     */

    public int compare(int humanFist,int machineFist){
   
   
        if(humanFist*machineFist == 0&&humanFist+machineFist == 2){
   
   
            if(humanFist == 0){
   
   
                humanFist = 3;
            }
            else{
   
   
                machineFist = 3;
            }
        }
        return humanFist - machineFist;
    }

    /**
     * 获取随机生成的拳值(下标) 并且输出机器的拳
     * @param nickname 机器玩家的昵称 作为输出提示
     * @return int 0~2
     */
    public int getRandFistIX(String nickname){
   
   
        int rst = RAND.nextInt(FISTS.length);
        System.out.println(nickname+"出拳:"+FISTS[rst]);
        return rst;
    }

}

1.简单模板的提取
观察我们可以得到,我们能够从游戏规则类中提取出一些方法模板:

public xxx get(String title){
   
   
    String line = null;
    do{
   
   
        System.out.println(...)//一个与title拼接的字符串,说明输入信息
        line = INPUT.nextLine();
        if(line.matches(...)){
   
   //或者是说处于某个范围 等于某个值(条件判断)
            break;
        }
        System.out.println(...)//另一个与title拼接的字符串,说明错误原因
    }while(true);
}

我们能够看出在OOP的学习过程中存在典型的方法模板,需要积累。

2.学会用一些数学思想去优化条件判断

if(humanFist*machineFist == 0&&humanFist+machineFist == 2){
   
   

因为拳值只可能为0,1,2,而分别代表着布剪锤,即0<1,1<2,2<0,所以如果非一布一锤的情况,值大即胜利,但是当同时出现2和0的时候,谁是0谁就胜利,通过这个优化的条件判断来确定了这种情况。

3.对于这种比较类,我们一般通过程序逻辑自定义比较规则,并将其详细地写在注释中,便于看代码。

4.关键点:将不可比较的拳类,构造出拳值数组,通过输入的字符串与拳值数组匹配得到下标转化为可比较的拳值。

游戏角色类

public class Role extends Rule{
   
   
    private String nickname;

    public Role(String title) {
   
   
        this.nickname = getInputName(title);
    }/* 先传到同包子类的方法中 获取一个昵称 再对属性赋值
     而到ROLE这一层还无法确定是要输入的是人类还是机器人的昵称 所以要给构造方法同样的title参数
     以便于让human和machine的类调用
     */

    /**
     * 获取角色昵称
     * @return
     */

    public String getNickname() {
   
   
        return nickname;
    }//作为提取角色昵称的出口 打破private获取数据的限制

    /**
     * 角色的标准方法:出拳
     * 由于人类角色和机器角色出拳的方式不同 在此处做方法的定义
     * * @return int(拳值对应的下标 是判断输赢的依据)
     */

    public int showFist(){
   
   
        return -1;
    }
}

1.showFist()抽象方法的差异化实现

机器角色类

public class Machine extends Role {
   
   

    public Machine(){
   
   
        super("机器角色");
    }

    /**
     * 重写实现机器角色出拳:随机
     */
    @Override
    public int showFist() {
   
   
        return getRandFistIX(getNickname());
    }
}

人类角色类

public class Human extends Role{
   
   

    //可以或缺 不写也能在子类的构造中自动调用父类的构造
    public Human(){
   
   
        super("人类角色");
    }

    /**
     * 重写实现人类角色出拳
     * @return
     */
    @Override
    public int showFist() {
   
   
        return getInputFistIx(getNickname());//此处可以不用super 原因在于在human里面并没有getNickname() 会自动追踪到父类
    }
}

裁判类

public class Judge extends Rule{
   
   
    /**
     * 裁判掌握的信息 就是 属性
     */
    private String name;

    /**
     * 获取裁判名字
     * @return String
     */
    public String getName() {
   
   
        return name;
    }
    /**
     * 游戏总局数
     */
    private int totalSets;

    /**
     * 获取游戏的总局数
     * @return int
     */
    public int getTotalSets() {
   
   
        return totalSets;
    }

    /**
     * 游戏数据:为了简洁,设计成整形的数组,也可以设计成三个变量,但不够简洁
     */

    private int[] data;
    public Judge(){
   
   
        name = getInputName("裁判");
        totalSets = getInputInt("总局数",3,10);
        data = new int[3]; // data [人类玩家胜局数,机器玩家胜局数,平局数]
    }

    /**
     *
     * 裁判执裁判断单局输赢 完成所有游戏数据的赋值
     * @param humanName
     * @param humanFistInt
     * @param machineName
     * @param machineFistInt
     * @return
     */
    public void judge(String humanName,int humanFistInt,String machineName,int machineFistInt){
   
   
        String whoWin = "胜";
        switch(compare(humanFistInt,machineFistInt)){
   
   
            case 1:
                data[0]++;
                whoWin = humanName + whoWin;
                break;
            case 0:
                data[2]++;
                whoWin = "平局";
                break;
            case -1:
                data[1]++;
                whoWin = machineName + whoWin;
                break;
        }
        System.out.println("本局["+whoWin+"]");
    }
    public void finalJudge(String humanName,String machineName){
   
   
        String whoWin = "胜";
        final int rst = data[0] - data[1];
        if(rst > 0){
   
   
            whoWin += humanName;
        }else if(rst == 0){
   
   
            whoWin = "平局";
        }else{
   
   
            whoWin += machineName;
        }
        System.out.println("-------最终结果-------");
        System.out.println("本次比赛共:"+totalSets+"局");
        System.out.println("人类玩家胜:"+data[0]+"局");
        System.out.println("机器玩家胜:"+data[1]+"局");
        System.out.println("平:"+data[2]+"局");
        System.out.println("最终"+whoWin);
    }
}

1.学习这种字符串拼接方式

String whoWin = "胜";
whoWin = humanName + whoWin;

游戏主类

public class FistGame {
   
   
    //建立游戏角色
    /**
     * 人类角色对象(引用)
     */
    private Human human;
    /**
     * 机器角色对象(引用)
     */
    private Machine machine;
    /**
     * 裁判角色对象(引用)
     */
    private Judge judge;

    /**
     * 游戏业务
     */
    public FistGame(){
   
   
        human = new Human();
        machine = new Machine();
        judge = new Judge();
    }
    public void start(){
   
   
        //提取角色昵称
        final String humanName = human.getNickname();
        final String machineName = machine.getNickname();
        final String judgeName = judge.getName();
        //输出控制
        System.out.println("------- 双人猜拳游戏 -------");
        System.out.println("------- "+humanName+" VS "+machineName+" -------");
        System.out.println("------- 本场裁判 [ "+judgeName+" ]");
        //游戏进程
        final int totalSets = judge.getTotalSets();
        for (int i = 1; i <= totalSets; i++) {
   
   
            System.out.println("第"+i+"局:");
            //双方分别出拳
            final int humanFistInt = human.showFist();
            final int machineFistInt = machine.showFist();
            //裁判针对当局执行裁决
            judge.judge(humanName,humanFistInt,machineName,machineFistInt);
            //输出空行,控制输出格式
            System.out.println();
        }
        //最终执裁
        judge.finalJudge(humanName,machineName);
    }


}

1.执裁过程是先单局再多局,只有先通过单局给到data数组数据,多局执裁才能利用data数组进行结果输出。

笔者认为,这道题是一道非常好的练习OOP的题目(当然也可以适用于其他语言),首先需要有游戏主类、规则类,再考虑游戏角色,既有Role类与具体角色的继承关系,差异化行为实现,又有考虑到人类和机器角色之间一些共性行为和差异化行为(比如说人类是通过输入的拳类来获取拳值,而机器是通过随机生成拳值。)
2.将角色对象作为类属性,并通过构造方法新创建对象,调用各自的方法。(详见面向对象知识总结之组合关系),因为游戏主类包含了人类,机器,裁判三者,并且游戏主类由多个其他类的对象组成,组成了更复杂的对象结构,所以此处选择该方式。
(请记住一个原则:多用组合 少用继承)

目录
相关文章
|
13天前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
2月前
|
设计模式 人工智能 前端开发
现代 Java 实现数字华容道与石头迷阵游戏的项目实战及项目开发指南
本项目基于Java 17+,采用JavaFX与MVC架构,实战开发数字华容道/石头迷阵游戏。内容涵盖技术选型、核心逻辑、现代GUI设计、动画实现及项目打包发布,结合sealed class、record等新特性,打造简洁可维护的游戏代码结构。
98 0
|
3月前
|
机器学习/深度学习 存储 Java
Java 大视界 -- Java 大数据机器学习模型在游戏用户行为分析与游戏平衡优化中的应用(190)
本文探讨了Java大数据与机器学习模型在游戏用户行为分析及游戏平衡优化中的应用。通过数据采集、预处理与聚类分析,开发者可深入洞察玩家行为特征,构建个性化运营策略。同时,利用回归模型优化游戏数值与付费机制,提升游戏公平性与用户体验。
|
9月前
|
Java
Java实现贪吃蛇游戏
本文介绍了如何使用Java实现一个简单的贪吃蛇游戏。
326 4
|
9月前
|
IDE Java API
Java游戏开发基础:从零开始制作一个简单的2D游戏
本文介绍了使用Java开发一个简单的2D避障游戏的基础流程。
522 10
|
9月前
|
Java 数据安全/隐私保护 开发者
【潜意识Java】深入理解 Java 面向对象编程(OOP)
本文介绍了Java中的面向对象编程(OOP)核心概念,包括封装、继承、多态和抽象。封装通过访问控制保护数据,提高安全性;继承支持代码复用,减少冗余;多态实现灵活的行为调用;抽象则隐藏细节,简化接口设计。掌握这些概念有助于编写高效、灵活且易于维护的代码。文章通过实例详细讲解了每个概念在Java中的应用,并总结了它们的优势。
354 3
|
12月前
|
开发框架 IDE Java
java制作游戏,如何使用libgdx,入门级别教学
本文是一篇入门级教程,介绍了如何使用libgdx游戏开发框架创建一个简单的游戏项目,包括访问libgdx官网、设置项目、下载项目生成工具,并在IDE中运行生成的项目。
461 1
java制作游戏,如何使用libgdx,入门级别教学
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
152 1
|
Java 索引
Java实现扑克牌游戏 | 随机发牌 ( 过程拆分详解+完整代码 )
Java实现扑克牌游戏 | 随机发牌 ( 过程拆分详解+完整代码 )
331 3
使用java编写猜数字游戏
使用java编写猜数字游戏