Java 記憶游戲多米諾牌顯示與游戲結(jié)束邏輯修復(fù)教程

Java 記憶游戲多米諾牌顯示與游戲結(jié)束邏輯修復(fù)教程

本教程旨在解決Java記憶游戲項(xiàng)目中多米諾牌無(wú)法正確顯示已猜中牌面及游戲無(wú)法正常結(jié)束的問(wèn)題。核心解決方案包括重寫(xiě)Domino類(lèi)的equals和hashCode方法以實(shí)現(xiàn)對(duì)象內(nèi)容的正確比較,以及在MemoryLane類(lèi)的guess方法中調(diào)用setRevealed方法來(lái)更新多米諾牌的顯示狀態(tài),從而確保游戲邏輯的完整性和正確性。

問(wèn)題分析

在提供的java記憶游戲代碼中,存在兩個(gè)主要問(wèn)題導(dǎo)致游戲無(wú)法按預(yù)期運(yùn)行:

  1. 多米諾牌匹配判斷不準(zhǔn)確: MemoryLane類(lèi)中的guess方法使用board[i] == board[k]來(lái)判斷兩個(gè)多米諾牌是否匹配。在Java中,==運(yùn)算符對(duì)于對(duì)象類(lèi)型而言,比較的是兩個(gè)引用是否指向內(nèi)存中的同一個(gè)對(duì)象實(shí)例,而不是它們所代表的邏輯內(nèi)容是否相等。因此,即使兩張多米諾牌(即兩個(gè)Domino對(duì)象)的top和bottom值相同,只要它們是不同的對(duì)象實(shí)例,==比較就會(huì)返回false。
  2. 多米諾牌狀態(tài)未更新: 當(dāng)玩家成功猜對(duì)一對(duì)多米諾牌時(shí),程序并未調(diào)用Domino對(duì)象的setRevealed(true)方法來(lái)將其標(biāo)記為已揭示。這導(dǎo)致以下連鎖問(wèn)題:
    • Domino類(lèi)的isRevealed()方法始終返回false(因?yàn)閞evealed成員變量從未被設(shè)置為true)。
    • MemoryLane類(lèi)的toString()方法無(wú)法正確顯示已匹配的多米諾牌(因?yàn)樗蕾?lài)isRevealed()的狀態(tài))。
    • MemoryLane類(lèi)的gameOver()方法始終返回false(因?yàn)樗y(tǒng)計(jì)的是已揭示的多米諾牌數(shù)量,而這個(gè)數(shù)量始終為零),導(dǎo)致游戲無(wú)法結(jié)束。

此外,Domino類(lèi)中原有的equals方法也存在邏輯錯(cuò)誤,它比較的是top == bottom,這實(shí)際上是檢查多米諾牌是否為雙牌(如[1|1]),而不是比較兩個(gè)不同的Domino對(duì)象是否相等。

解決方案

針對(duì)上述問(wèn)題,我們需要對(duì)Domino類(lèi)和MemoryLane類(lèi)進(jìn)行修改。

1. 修復(fù) Domino 類(lèi):重寫(xiě) equals() 和 hashCode() 方法

為了使MemoryLane類(lèi)中的guess方法能夠正確地比較兩個(gè)Domino對(duì)象的內(nèi)容(即它們的top和bottom值),我們需要在Domino類(lèi)中重寫(xiě)equals(Object obj)方法。同時(shí),根據(jù)Java的約定,如果重寫(xiě)了equals()方法,就必須同時(shí)重寫(xiě)hashCode()方法,以確保對(duì)象在哈希表(如HashMap、HashSet)中能正確工作,并維護(hù)equals和hashCode之間的契約:如果兩個(gè)對(duì)象通過(guò)equals()方法比較為相等,那么它們的hashCode()方法必須返回相同的值。

Domino 類(lèi)修改示例:

立即學(xué)習(xí)Java免費(fèi)學(xué)習(xí)筆記(深入)”;

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() {         // 簡(jiǎn)化原始邏輯:直接返回revealed狀態(tài)         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. 檢查是否為同一個(gè)對(duì)象引用         if (this == obj) {             return true;         }         // 2. 檢查傳入對(duì)象是否為NULL或類(lèi)型不匹配         if (obj == null || !(obj instanceof Domino)) {             return false;         }         // 3. 將傳入對(duì)象向下轉(zhuǎn)型         final Domino other = (Domino) obj;         // 4. 比較關(guān)鍵屬性(top和bottom)         if (this.getTop() != other.getTop()) {             return false;         }         if (this.getBottom() != other.getBottom()) {             return false;         }         return true; // 所有屬性都匹配,則認(rèn)為對(duì)象相等     } }

注意事項(xiàng):

  • equals方法的實(shí)現(xiàn)遵循了標(biāo)準(zhǔn)的約定:自反性、對(duì)稱(chēng)性、傳遞性、一致性以及對(duì)null的判斷。
  • hashCode方法的實(shí)現(xiàn)確保了與equals方法的一致性,即相等的對(duì)象具有相同的哈希碼。

2. 修復(fù) MemoryLane 類(lèi):更新 guess() 方法

在MemoryLane類(lèi)的guess方法中,我們需要將對(duì)象引用比較==替換為內(nèi)容比較equals(),并在匹配成功時(shí)調(diào)用Domino對(duì)象的setRevealed(true)方法。

MemoryLane 類(lèi)修改示例:

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對(duì)象的內(nèi)容         if (board[i].equals(board[k])) {             // 如果匹配成功,則設(shè)置這兩個(gè)多米諾牌為已揭示             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);     }      // 可選:添加一個(gè)debug方法用于查看所有牌面,便于測(cè)試     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 類(lèi):

MemoryLaneDriver 類(lèi)無(wú)需任何修改,因?yàn)樗ㄟ^(guò)MemoryLane類(lèi)的公共接口進(jìn)行交互,而我們對(duì)MemoryLane和Domino類(lèi)的修改都保持了其公共接口不變(或僅在內(nèi)部邏輯上進(jìn)行了優(yōu)化)。

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()) {             // 可選:在實(shí)際游戲中可以移除或注釋掉此行,它用于調(diào)試時(shí)顯示所有牌面             // 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");     } }

總結(jié)

通過(guò)以上修改,我們解決了記憶游戲中的核心邏輯問(wèn)題:

  1. 正確識(shí)別匹配: 重寫(xiě)Domino類(lèi)的equals方法,使得MemoryLane.guess方法能夠基于多米諾牌的實(shí)際數(shù)值(top和bottom)進(jìn)行準(zhǔn)確比較。
  2. 正確更新?tīng)顟B(tài): 在guess方法中,當(dāng)檢測(cè)到匹配時(shí),調(diào)用setRevealed(true)將匹配的多米諾牌狀態(tài)更新為已揭示。
  3. 正確顯示與游戲結(jié)束: Domino.isRevealed()現(xiàn)在能返回正確狀態(tài),進(jìn)而MemoryLane.toString()能夠正確顯示已揭示的牌面,并且MemoryLane.gameOver()能夠準(zhǔn)確判斷游戲是否所有牌都已揭示,從而使游戲能夠正常結(jié)束。

這個(gè)案例強(qiáng)調(diào)了在Java中處理自定義對(duì)象比較時(shí),正確重寫(xiě)equals()和hashCode()方法的重要性,以及理解對(duì)象狀態(tài)管理在游戲邏輯中的關(guān)鍵作用。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊10 分享