0

0

Java 记忆游戏多米诺牌显示与游戏结束逻辑修复教程

霞舞

霞舞

发布时间:2025-07-07 20:04:15

|

898人浏览过

|

来源于php中文网

原创

Java 记忆游戏多米诺牌显示与游戏结束逻辑修复教程

本教程旨在解决Java记忆游戏项目中多米诺牌无法正确显示已猜中牌面及游戏无法正常结束的问题。核心解决方案包括重写Domino类的equals和hashCode方法以实现对象内容的正确比较,以及在MemoryLane类的guess方法中调用setRevealed方法来更新多米诺牌的显示状态,从而确保游戏逻辑的完整性和正确性。

问题分析

在提供的java记忆游戏代码中,存在两个主要问题导致游戏无法按预期运行:

  1. 多米诺牌匹配判断不准确: MemoryLane类中的guess方法使用board[i] == board[k]来判断两个多米诺牌是否匹配。在Java中,==运算符对于对象类型而言,比较的是两个引用是否指向内存中的同一个对象实例,而不是它们所代表的逻辑内容是否相等。因此,即使两张多米诺牌(即两个Domino对象)的top和bottom值相同,只要它们是不同的对象实例,==比较就会返回false。
  2. 多米诺牌状态未更新: 当玩家成功猜对一对多米诺牌时,程序并未调用Domino对象的setRevealed(true)方法来将其标记为已揭示。这导致以下连锁问题:
    • Domino类的isRevealed()方法始终返回false(因为revealed成员变量从未被设置为true)。
    • MemoryLane类的toString()方法无法正确显示已匹配的多米诺牌(因为它依赖isRevealed()的状态)。
    • MemoryLane类的gameOver()方法始终返回false(因为它统计的是已揭示的多米诺牌数量,而这个数量始终为零),导致游戏无法结束。

此外,Domino类中原有的equals方法也存在逻辑错误,它比较的是top == bottom,这实际上是检查多米诺牌是否为双牌(如[1|1]),而不是比较两个不同的Domino对象是否相等。

解决方案

针对上述问题,我们需要对Domino类和MemoryLane类进行修改。

1. 修复 Domino 类:重写 equals() 和 hashCode() 方法

为了使MemoryLane类中的guess方法能够正确地比较两个Domino对象的内容(即它们的top和bottom值),我们需要在Domino类中重写equals(Object obj)方法。同时,根据Java的约定,如果重写了equals()方法,就必须同时重写hashCode()方法,以确保对象在哈希表(如HashMap、HashSet)中能正确工作,并维护equals和hashCode之间的契约:如果两个对象通过equals()方法比较为相等,那么它们的hashCode()方法必须返回相同的值。

Domino 类修改示例:

立即学习Java免费学习笔记(深入)”;

public class Domino {
    private int top, bottom;
    private boolean revealed;

    public Domino(int x, int y) {
        if (x > y) {
            top = y;
            bottom = x;
        } else {
            top = x;
            bottom = y;
        }
    }

    public int getTop() {
        return top;
    }

    public int getBottom() {
        return bottom;
    }

    public boolean isRevealed() {
        // 简化原始逻辑:直接返回revealed状态
        return revealed;
    }

    public void setRevealed(boolean revealed) {
        this.revealed = revealed;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + this.getTop();
        hash = 59 * hash + this.getBottom();
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        // 1. 检查是否为同一个对象引用
        if (this == obj) {
            return true;
        }
        // 2. 检查传入对象是否为null或类型不匹配
        if (obj == null || !(obj instanceof Domino)) {
            return false;
        }
        // 3. 将传入对象向下转型
        final Domino other = (Domino) obj;
        // 4. 比较关键属性(top和bottom)
        if (this.getTop() != other.getTop()) {
            return false;
        }
        if (this.getBottom() != other.getBottom()) {
            return false;
        }
        return true; // 所有属性都匹配,则认为对象相等
    }
}

注意事项:

  • equals方法的实现遵循了标准的约定:自反性、对称性、传递性、一致性以及对null的判断。
  • hashCode方法的实现确保了与equals方法的一致性,即相等的对象具有相同的哈希码。

2. 修复 MemoryLane 类:更新 guess() 方法

在MemoryLane类的guess方法中,我们需要将对象引用比较==替换为内容比较equals(),并在匹配成功时调用Domino对象的setRevealed(true)方法。

GradPen论文
GradPen论文

GradPen是一款AI论文智能助手,深度融合DeepSeek,为您的学术之路保驾护航,祝您写作顺利!

下载

MemoryLane 类修改示例:

import java.util.Arrays;
import java.util.Random;

public class MemoryLane {
    private Domino[] board;

    public MemoryLane(int max) {
        board = new Domino[(max * max) + max];

        int i = 0;
        for (int top = 1; top <= max; top++) {
            for (int bot = 1; bot <= max; bot++) {
                if (top <= bot) {
                    board[i] = new Domino(top, bot);
                    i++;
                    board[i] = new Domino(top, bot);
                    i++;
                }
            }
        }
        shuffle();
    }

    private void shuffle() {
        int index;
        Random random = new Random();
        for (int i = board.length - 1; i > 0; i--) {
            index = random.nextInt(i + 1);
            if (index != i) {
                Domino temp = board[index];
                board[index] = board[i];
                board[i] = temp;
            }
        }
    }

    public boolean guess(int i, int k) {
        // 使用equals方法比较Domino对象的内容
        if (board[i].equals(board[k])) {
            // 如果匹配成功,则设置这两个多米诺牌为已揭示
            board[i].setRevealed(true);
            board[k].setRevealed(true);
            return true;
        }
        return false;
    }

    public String peek(int a, int b) {
        String text = new String();
        text += ("[" + board[a].getTop() + "] [" + board[b].getTop() + "]\n");
        text += ("[" + board[a].getBottom() + "] [" + board[b].getBottom() + "]\n");
        return text;
    }

    public boolean gameOver() {
        int count = 0;
        for (int i = 0; i < board.length; i++) {
            if (board[i].isRevealed()) {
                count++;
            }
        }
        return (count == board.length);
    }

    // 可选:添加一个debug方法用于查看所有牌面,便于测试
    public String debug() {
        String text = new String();
        for (int i = 0; i < board.length; i++) {
            text += ("[" + board[i].getTop() + "] ");
        }
        text += ('\n');
        for (int i = 0; i < board.length; i++) {
            text += ("[" + board[i].getBottom() + "] ");
        }
        return text;
    }

    @Override
    public String toString() {
        String text = new String();
        for (int i = 0; i < board.length; i++) {
            if (board[i].isRevealed()) {
                text += ("[" + board[i].getTop() + "] ");
            } else {
                text += ("[ ] ");
            }
        }
        text += ('\n');
        for (int i = 0; i < board.length; i++) {
            if (board[i].isRevealed()) {
                text += ("[" + board[i].getBottom() + "] ");
            } else {
                text += ("[ ] ");
            }
        }
        return text;
    }
}

MemoryLaneDriver 类:

MemoryLaneDriver 类无需任何修改,因为它通过MemoryLane类的公共接口进行交互,而我们对MemoryLane和Domino类的修改都保持了其公共接口不变(或仅在内部逻辑上进行了优化)。

import java.util.Scanner;

public class MemoryLaneDriver {
    public static void main(String[] args) {
        String message = "Welcome to Memory Lane!" + "\n" +
                "Choose two indexes to reveal the corresponding dominoes." + "\n" +
                "If the dominoes match, they stay revealed." + "\n" +
                "Reveal all the dominoes to win the game!" + "\n";

        System.out.println(message);

        Scanner input = new Scanner(System.in);

        MemoryLane game = new MemoryLane(2);

        long start = System.currentTimeMillis();

        while (!game.gameOver()) {
            // 可选:在实际游戏中可以移除或注释掉此行,它用于调试时显示所有牌面
            // System.out.println(game.debug());
            System.out.println(game);

            System.out.print("First:  ");
            int first = input.nextInt();

            System.out.print("Second: ");
            int second = input.nextInt();

            game.guess(first, second);
            System.out.println(game.peek(first, second) + "\n");
        }

        long stop = System.currentTimeMillis();
        long elapsed = (stop - start) / 1000;

        System.out.println(game);

        System.out.println("\nYou win!");
        System.out.println("Total time: " + elapsed + "s");
    }
}

总结

通过以上修改,我们解决了记忆游戏中的核心逻辑问题:

  1. 正确识别匹配: 重写Domino类的equals方法,使得MemoryLane.guess方法能够基于多米诺牌的实际数值(top和bottom)进行准确比较。
  2. 正确更新状态: 在guess方法中,当检测到匹配时,调用setRevealed(true)将匹配的多米诺牌状态更新为已揭示。
  3. 正确显示与游戏结束: Domino.isRevealed()现在能返回正确状态,进而MemoryLane.toString()能够正确显示已揭示的牌面,并且MemoryLane.gameOver()能够准确判断游戏是否所有牌都已揭示,从而使游戏能够正常结束。

这个案例强调了在Java中处理自定义对象比较时,正确重写equals()和hashCode()方法的重要性,以及理解对象状态管理在游戏逻辑中的关键作用。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

235

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

438

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1499

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

231

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

87

2025.10.17

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1079

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

169

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1400

2025.12.29

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号