Java 多米诺骨牌记忆游戏:揭示机制与游戏结束逻辑修复教程

Java 多米诺骨牌记忆游戏:揭示机制与游戏结束逻辑修复教程

本教程旨在解决Java多米诺骨牌记忆游戏中,匹配成功的多米诺骨牌无法保持揭示状态,且游戏无法正常结束的问题。核心解决方案包括:正确重写 Domino 类的 equals() 和 hashCode() 方法以实现基于内容的比较,而非内存地址比较;以及在 MemoryLane 类的 guess() 方法中调用 setRevealed() 方法来更新多米诺骨牌的显示状态。通过这些修正,游戏将能够正确识别匹配,并按照预期逻辑结束。

问题分析:多米诺骨牌未正确揭示与游戏未结束的原因

在提供的多米诺骨牌记忆游戏代码中,存在两个主要问题导致游戏功能不完整:

多米诺骨牌匹配判断不准确: MemoryLane 类中的 guess 方法使用 board[i] == board[k] 来判断两个多米诺骨牌是否匹配。在 Java 中,对于对象类型,== 运算符比较的是两个引用是否指向内存中的同一个对象实例,而不是它们的内容是否相等。因此,即使两个多米诺骨牌具有相同的 top 和 bottom 值,如果它们是不同的对象实例,== 也会返回 false。这导致了即使玩家猜对了,多米诺骨牌也无法被正确识别为匹配。多米诺骨牌状态未更新: Domino 类中包含 setRevealed(boolean revealed) 方法用于设置多米诺骨牌的揭示状态,但在 MemoryLane 类的 guess 方法中,当匹配成功时,并未调用此方法来将匹配的多米诺骨牌设置为已揭示。这使得 isRevealed() 方法始终返回 false(因为 revealed 成员变量的默认值为 false),从而导致 MemoryLane 的 gameOver() 方法无法正确判断所有多米诺骨牌是否都被揭示,进而游戏无法结束。

解决方案一:正确实现对象比较——重写 equals() 和 hashCode()

为了使 Domino 对象能够基于其内容(即 top 和 bottom 值)进行比较,我们需要在 Domino 类中重写 equals() 方法。同时,根据 Java 规范,如果重写了 equals() 方法,也必须重写 hashCode() 方法,以维护它们之间的契约:如果两个对象通过 equals() 方法比较是相等的,那么它们的 hashCode() 方法必须产生相同的整数结果。

以下是 Domino 类中 equals() 和 hashCode() 方法的正确实现:

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() {        return revealed; // 简化了原有的 if-else 结构    }    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) {        if (this == obj) { // 检查是否是同一个对象实例            return true;        }        if (obj == null || getClass() != obj.getClass()) { // 检查是否为null或类型不匹配            return false;        }        final Domino other = (Domino) obj; // 类型转换        if (this.getTop() != other.getTop()) { // 比较 top 值            return false;        }        if (this.getBottom() != other.getBottom()) { // 比较 bottom 值            return false;        }        return true; // 如果 top 和 bottom 都相等,则认为对象相等    }}

说明:

equals(Object obj):首先检查是否为同一个对象引用(this == obj),如果是则直接返回 true。然后检查传入对象是否为 null 或类型不匹配(getClass() != obj.getClass()),如果是则返回 false。将 obj 强制转换为 Domino 类型。最后,比较 top 和 bottom 属性是否相等。hashCode():使用 top 和 bottom 属性计算哈希值。一种常见的做法是使用一个质数(如59)乘以当前哈希值并加上字段值,以分散哈希码并减少碰撞。

解决方案二:确保匹配多米诺骨牌保持揭示状态

在 MemoryLane 类的 guess 方法中,当两个多米诺骨牌被正确匹配时,需要调用它们的 setRevealed(true) 方法,将它们的状态设置为已揭示。

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

以下是 MemoryLane 类中 guess 方法的修正:

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  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 方法进行内容比较        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 = ""; // 使用空字符串初始化,避免 String 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); // 当所有多米诺骨牌都已揭示时,游戏结束    }    // 调试方法,显示所有多米诺骨牌的真实值(可选,原答案中包含)    public String debug() {        String text = "";        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 = "";        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;    }}

说明:

guess(int i, int k): 现在使用 board[i].equals(board[k]) 进行比较,这将正确判断两个多米诺骨牌的内容是否相等。如果判断为匹配成功,则 board[i].setRevealed(true) 和 board[k].setRevealed(true) 将被调用,从而更新这些多米诺骨牌的 revealed 状态。gameOver() 方法现在能够正确统计已揭示的多米诺骨牌数量,并在所有多米诺骨牌都被揭示时返回 true,从而使游戏正常结束。

注意事项与总结

equals() 与 hashCode() 契约: 再次强调,当您在 Java 中重写 equals() 方法时,务必同时重写 hashCode() 方法。这是 Java 集合框架(如 HashMap、HashSet)正确工作的基础,否则可能导致对象在集合中行为异常。对象比较的正确性: 理解 == 运算符和 equals() 方法在对象比较上的区别至关重要。== 比较引用地址,而 equals() 比较对象内容(如果被正确重写)。代码可读性与维护: 在 Domino 类的 isRevealed() 方法中,将 if (revealed) return true; return false; 简化为 return revealed; 可以提高代码的简洁性。同样,在 String text = new String(); 处,直接使用 String text = “”; 更为简洁高效。驱动类不变性: 由于 MemoryLaneDriver 类被设定为不可修改,所有的修正都必须集中在 Domino 和 MemoryLane 这两个核心业务逻辑类中,这正是本教程所遵循的原则。

通过以上修正,您的多米诺骨牌记忆游戏将能够正确地识别匹配、揭示多米诺骨牌,并最终判断游戏胜利,提供完整的游戏体验。

以上就是Java 多米诺骨牌记忆游戏:揭示机制与游戏结束逻辑修复教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/144349.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
java框架与人工智能集成后的道德和伦理问题?
上一篇 2025年12月2日 00:39:11
GoREST服务中正确处理URL查询参数的方法
下一篇 2025年12月2日 00:39:14

相关推荐

  • composer require-dev和require有什么不同_Composer Require与Require-Dev区别解析

    require用于声明项目运行必需的依赖,如框架、数据库组件和第三方SDK,这些包会随项目部署到生产环境;2. require-dev用于声明仅在开发和测试阶段需要的工具,如PHPUnit、PHPStan、Faker等,不会默认部署到生产环境;3. 安装时composer install根据环境决定…

    2026年5月10日
    1000
  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • 理解编程指令:当结果正确,但实现方式不符要求时

    本文探讨了在编程实践中,即使程序输出了正确的结果,但若其实现方式未能严格遵循既定指令,仍可能被视为“不正确”的问题。我们将通过具体示例,对比直接求和与累加求和两种实现策略,强调理解和遵守编程规范的重要性,以确保代码的健壮性、可维护性及符合项目要求。 在软件开发过程中,我们经常会遇到这样的情况:编写的…

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • php常量怎么用_PHP常量(define/const)定义与使用方法

    PHP中可通过define函数和const关键字定义常量,用于存储不可变值。define适用于全局作用域,支持动态名称和条件定义,如define(‘SITE_NAME’, ‘MyWebsite’);const在编译时生效,语法简洁但限制多,只能在类或全…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 前端缓存策略与JavaScript存储管理

    根据数据特性选择合适的存储方式并制定清晰的读写与清理逻辑,能显著提升前端性能;合理运用Cookie、localStorage、sessionStorage、IndexedDB及Cache API,结合缓存策略与定期清理机制,可在保证用户体验的同时避免安全与性能隐患。 前端缓存和JavaScript存…

    2026年5月10日
    200
  • HTML5网页如何实现手势操作 HTML5网页移动端交互的处理技巧

    首先利用原生touch事件实现滑动判断,再通过preventDefault解决滚动冲突,接着引入Hammer.js处理复杂手势,最后通过优化点击区域、避免事件冲突和增加视觉反馈提升体验。 在移动端浏览器中,HTML5网页可以通过触摸事件实现手势操作,提升用户体验。虽然原生JavaScript提供了基…

    2026年5月10日
    000
  • 如何插入查询结果数据_SQL插入Select查询结果方法

    如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法

    使用INSERT INTO…SELECT语句可高效插入数据,通过NOT EXISTS、LEFT JOIN、MERGE语句或唯一约束避免重复;表结构不一致时可通过别名、类型转换、默认值或计算字段处理;结合存储过程可提升可维护性,支持参数化与动态SQL。 将查询结果数据插入到另一个表中,可以…

    2026年5月10日 用户投稿
    000
  • JavaScript 闭包:理解闭包原理与内存泄漏问题

    闭包是函数访问其外部作用域变量的能力,即使外部函数已执行完毕。如 inner 函数引用 outer 中的 count,形成闭包,使变量持久存在。闭包本身无害,但可能因延长变量生命周期导致内存泄漏,例如事件监听器引用大对象时。若未及时清理 DOM 事件或定时器,闭包会阻止垃圾回收,造成内存占用过高。解…

    2026年5月10日
    100
  • JavaScript 动态菜单点击高亮效果实现教程

    本教程详细介绍了如何使用 JavaScript 实现动态菜单的点击高亮功能。通过事件委托和状态管理,当用户点击菜单项时,被点击项会高亮显示(绿色),同时其他菜单项恢复默认样式(白色)。这种方法避免了不必要的DOM操作,提高了性能和代码可维护性,确保了无论点击方向如何,功能都能稳定运行。 动态菜单高亮…

    2026年5月10日
    200
  • JavaScript函数中插入加载动画(Spinner)的正确方法

    本文旨在解决在JavaScript函数中插入加载动画(Spinner)时遇到的异步问题。通过引入async/await和Promise.all,确保在数据处理完成前后正确显示和隐藏加载动画,提升用户体验。我们将提供两种实现方案,并详细解释其原理和优势。 在Web开发中,当执行耗时操作时,显示加载动画…

    2026年5月10日
    100
  • 动态更新圆形进度条:JavaScript成绩计算器集成指南

    本文档旨在指导开发者如何将JavaScript成绩计算系统与动态圆形进度条集成,实现可视化展示平均成绩。我们将详细讲解如何修改现有的JavaScript代码,使其在计算出平均分后,能够动态更新圆形进度条的进度,从而提供更直观的用户体验。本文档包含详细的代码示例和注意事项,帮助开发者轻松实现这一功能。…

    2026年5月10日
    000
  • Go语言接口与切片:如何识别和操作[]interface{}

    本文将深入探讨Go语言中如何识别和操作`[]interface{}`类型的切片。我们将介绍类型断言(Type Assertion)的关键作用,并通过`switch`语句演示如何安全地检测`[]interface{}`类型,并进而遍历其内部元素。文章旨在提供清晰的示例代码和专业指导,帮助开发者有效地处…

    2026年5月10日
    000
  • JavaScript计算器开发:解决数值显示与初始化问题

    本教程深入探讨了使用JavaScript构建计算器时常见的数值显示异常问题,特别是由于类属性未初始化导致的`Cannot read properties of undefined`错误。我们将详细分析问题根源,并通过在构造函数中调用初始化方法来解决该问题,同时优化显示逻辑,确保计算器功能稳定且界面显…

    2026年5月10日
    000
  • 使用 Ajax 和 FormData 实现文件上传及文本数据提交的完整教程

    本文旨在解决在使用 Ajax 和 FormData 进行文件上传时,遇到的 $_POST 和 $_FILES 为空的问题。通过详细的代码示例和解释,我们将展示如何正确地构建 FormData 对象,并通过 Ajax 将文件和文本数据发送到服务器端,同时避免常见的错误配置,确保数据能够成功地被 PHP…

    2026年5月10日
    000
  • JavaScript 高效判断页面所有复选框状态的技巧与实践

    本文旨在提供一套高效且专业的javascript方法,用于判断网页中所有复选框的选中状态。我们将探讨如何利用`array.some()`快速确定是否有未选中的复选框(进而判断是否全部选中),以及如何使用`array.filter()`统计选中和未选中的复选框数量。通过优化dom元素选择和数组操作,提…

    2026年5月10日
    000
  • 解决Persistent UTM代码导致链接意外添加问号的问题

    本文旨在解决在使用JavaScript持久化UTM参数时,链接在没有UTM参数的情况下被意外添加问号的问题。通过分析问题代码,找出错误原因,并提供修正后的代码示例,确保只有当存在UTM参数时,链接才会被添加相应的参数。同时,强调了代码的健壮性和可维护性,避免不必要的修改和潜在的错误。 在使用Java…

    2026年5月10日
    200
  • 从 JavaScript 获取 URL 并在 PHP DataGrid 中使用

    本文档旨在指导开发者如何从 JavaScript 函数中获取 URL,并将其动态应用于 PHP DataGrid。通过前端 JavaScript 动态生成 API 地址,并将其传递给后端的 PHP DataGrid,实现数据根据用户会话动态加载。 动态配置 DataGrid 的 URL 在构建动态 …

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信