1. 程式人生 > >JAVA面向物件設計例項之一發牌比較大小

JAVA面向物件設計例項之一發牌比較大小

程式功能闡述如下:

由電腦隨機從撲克牌堆中抽取前兩張牌,一張屬於使用者,一張屬於電腦,比較其大小:

      大小規則:數字規則:

                           2<3<4<5<6<7<8<9<10<J<Q<K<小王<大王

                            花色規則:

                            方塊<梅花<紅桃<黑桃

      比較規則:數字優先,同數字,花色優先。

專案截圖:

針對這個專案,我們先把思路做一下整理:

在這個專案中用到了資料,我們先從資料入手,進行資料的分析:

對於發牌比大小,資料就是牌。

單純說牌,還有一個前提是比較大小.那麼在資料進行設計的時候,比較簡單和直接的設計就是:

按照牌大小順序排好。

我們先看我們定的規則:

1、黑桃>紅桃>梅花>方塊

                 2、無論任何花色2<3<4<5<6<7<8<9<10<J<Q<K<A

                 3、大王最大,其次是小王

           我們在排這個列表的時候可以根據方塊2、梅花2、紅桃2、黑桃2、方塊3、….黑桃A 、小王、大王這個順序來組織和排序資料。

           排完以後,諸如:方塊2、梅花2、紅桃2 、黑桃2等內容都可以是一個String型別,根據String型別的特點:一個String就是一個char陣列,在堆記憶體裡有一定的空間儲存。54張牌就要有54個堆記憶體空間來儲存。在對這個堆記憶體空間操作的過程中,也對字串進行處理,而String的處理其實就是在String會進行陣列複製,進而浪費記憶體。

           針對這一問題,我們可以採用技術:讀寫分離。

           把字串做為一個變數也好,靜態也罷,只是儲存著牌的資訊,也不能比較大小,真正比較大小還需要我們的整型資料,我們能不能把牌的資訊和整型資料結合起來,一一對應,一個整型資料對應一個牌的資訊,當我們使用這個牌的時候,再進行對應關係的對映,我們的操作只針對這個整型的一個集合。這就構成了我們的讀寫分離,讀的是牌的資訊和整型數的對應關係,寫或者說操作的都是整型的列表或集合。

                那麼整型庫的型別可以定義成ArrayList<Integer>

                 整型庫與牌資訊的對應關係我們應用Map集合:

Map<Integer,String>

                 一副牌理好以後,我們需要洗牌,也就是打亂牌。

             打亂牌始終對ArrayList中的Integer操作,取得這張牌也可以對ArrayList的Integer操作,比較也是對ArrayList的Integer操作。這一期間都是對Integer操作,直到需要對應關係的時候我們直接找那個key對應的String對映。

           這樣資料的思路出來了:

           也就是我們可以定義一個數據類,比如這個類叫PuKe。這裡至少先有兩個成員變數:

一個list列表,裡面存0-----53的整數。

           一個Map 集合裡面存0—53和方塊2----大王的對應關係

           初始化的時候可以對這兩個成員變數進行賦值:

           就是把花色牌和比較的數字一一對應。

           這樣我們得到的程式碼可以是:

           先定義兩個成員變數:

            

      再進行初始化:

            

        初始化以後進行賦值:

                 思路:我們可以把花色和點數進行迴圈匹配出牌面來,用一個標誌整數位的值來進行累加計算整型值。

                 這樣把資料放在列表中就變成以下形式:

        這個資料裡缺少大王和小王,我們再把大王和小王對應的數值也放進去。

        

        在資料PuKe類的建構函式裡有了以下程式碼以後,我們可以用map的keySet遍歷方法:

        

        可以在主類中呼叫一下,看一下結果是不是我們想象中的樣子:

                        

            

            

            

        放在Map集合中的結果已經完成,也是我們期望的順序。下面我們要進行的就是集合中的資料打散,進行洗牌的操作。

洗牌實際上就是把紙牌集合隨機進行兩兩交換,進行若干次,就可以把集合中的元素順序弄亂。由於我們採用讀寫分離,實際上我們打亂的是Integer整型資料的集合。

實際的程式碼實現如下:

            

    當然,由於collections工具類的引用,這段程式也可以用工具類實現:

            

        把集合打散後,相當於我們已經完成了撲克牌集合的準備。下一步我們要做的事就是能夠從牌頂拿出一張牌給玩家,再拿出一張牌給電腦,然後比較大小。

        從牌庫頂拿一張牌我們需要寫方法get

        

        但要注意的是,我們每次拿的牌是不一樣的,才能保證電腦和玩家的牌不同,我們就得需要定義一個index變數,這個變數存放的就是牌庫的索引值,每次拿牌索引值增加,就可以保證每次拿到不同的牌,不過前提是這個值不會因為程式的初始化而變化,所以用靜態變數來定義這個index值。

這樣程式碼變成:

            

                

            這樣我們就實現了一個拿牌的過程。

            不過我們拿到的是數字,在外面呼叫後,一定會進行數字對應的牌面的轉換,我們就需要把map這個存放牌值的集合進行封裝後的getter,setter方法,供外面呼叫後把數字轉成相對應的牌面。

            

                

        整個資料類我們已經完成了,下面我們就要進行遊戲角色類的設定了。

        對於遊戲角色類,我們不難分析,由電腦和使用者端同時拿一張牌,然後比較大小,從這個要求中,就會明白,我們需要電腦類、使用者類,由於這兩個類都需要從資料牌庫類中取牌,方法也是一樣的,所以我們可以找到他們的共同父類,我們暫且叫選手類。

        在選手類中我們不難分析,他們應該有成員變數就是他們各自的名字,我們可以簡單處理,初始化的時候就把名字進行賦值,然後有一個方法從資料牌庫中拿牌,拿到牌後轉化成我們需要的牌面資訊。

        

        

        以上是選手類的相關程式碼:

        電腦類和使用者類直接繼承於選手類即可,不用做方法的重寫,但從繼承的相關理論中我們知道,構造器不能繼承過來,我們在子類繼承中把構造器用super關鍵字來繼承過來,這樣子類就有自己的名字了,再進行比較牌面。

        於是電腦類Computer就為:

        

        使用者類就成為了:

            

            

        參與的角度類建立成功後,我們建立操作類,就是遊戲的整個執行過程類:

        一般的遊戲過程類都包括:遊戲初始化方法,遊戲執行方法,遊戲判斷方法和遊戲結束方法,

         於是這個執行過程類就包括:

             Init() 方法 game()方法  judge()方法  gameover()方法

        而對於這個遊戲,init()可以實現發牌,發完牌直接比較,judge()方法,最後再gameover方法,不需要game()方法

我們可以寫一個執行過程類的介面,讓開發者都遵循我們統一的命名標準和規範。

        

    接下來我們定義一個操作類實現這個介面

        

                

            在這個操作類中,我們只需要實現init()、judge()和gameover方法即可。

            Init()方法中例項牌庫、電腦、使用者,然後電腦和使用者從牌庫中取牌。

                

       這裡定義成員變數的Computer、Player、Puke 三個變數的原因是由於這三個成員變數在init()方法、judge()方法和gameover方法中都要呼叫,所以定義一個全域性的成員變數。

        new Computer和new Player的過程中直接給這三個成員變數的name賦值,即參與遊戲的兩個角色,然後new PuKe()是把撲克牌產生,並呼叫PuKe中的shuffle方法打亂。再由Computer成員變數comp呼叫其父類的方法fetch一張牌,再由Player成員變數player呼叫其父類的方法fetch一張牌,然後執行judge();

          這是上面程式碼的相關邏輯。

          然後我們看judge()的完成。

        在judge方法中,我們明顯需要得到一個量,這個量就是撲克牌對應的整型值,而這個值我們也放在了撲克牌類中的ArrayList列表中,我們即然要取這個值,就需要知道電腦類、玩家類中fetch方法中獲取的牌對應的整型值是多少,我們沒有定義這個獲取方法,因此需要把電腦類和玩家類的父類再增加一個成員變數,這個變數就是key,我們通過fetch()方法獲取了牌之後,還要把key值儲存一下,然後定義getter方法讓外界可以呼叫,這樣judge就可以進行key值的比較了,繼而來決定牌的大小。

        先看改寫的選手類:

        增加key值:

                

        定義getter方法,外界不需要對其設定,所以不用設定setter。

                

            在fetch的時候我們把key 值也儲存下來。

                    

        這樣選手類的key值設定完成後,電腦類和使用者類的key值也設定了。

        下面我們完成操作類的judge()方法,程式碼如下:

                

        看邏輯也非常簡單。

        對比電腦的key值與玩家的key 值,大了話“玩家輸了”,小的話“玩家贏了”。

        最後呼叫gameover()方法.

                

         gameover()方法也非常簡單,就是輸出一句“遊戲結束,歡迎使用“。

        這個遊戲程式的最後,我們需要定義主類來呼叫,我們叫MainLei,這個名稱可以自己定義。在其中只要初始化一下游戲操作類,即CaoZuo類例項化和呼叫其init方法即可:

         

    至此,整個程式完成。我們可以看一下整體的程式目錄結構,養成良好的結構習慣。