[Java]文字版傷心小棧

HeartsPlayer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package pokerGames;
 
import java.util.*;
 
/**
 * @author 幻冽(Magic Lea)
 */
public class Card {
    //花色:梅花0,方塊1,愛心2,黑桃3
 
    private CardPattern patternForCard;
    private int numberForCard;
    public final int offset;//最大的牌是2,那麼offset=2(依此類推)
 
    public Card() {
        this(CardPattern.CLUB, 3, 1);//預設給梅花二,offset=1
    }
 
    public Card(int code, int offset) {//輸入代碼的建構式
        this(CardPattern.codeToPattern((code - offset - 1) / 13), ((code - offset - 1) % 13) + 1 + offset, offset);
    }
 
    public Card(String patternForCard, int numberForCard, int offset) {//輸入牌花色(字串)和數字的建構式
        this(CardPattern.valueOf(patternForCard), numberForCard, offset);
    }
 
    public Card(CardPattern patternForCard, int numberForCard, int offset) {//主要的建構式
        this.patternForCard = patternForCard;
        this.numberForCard = numberForCard;
        this.offset = offset;
    }
 
    public CardPattern getPatternForCard() {//取得牌的花色
        return patternForCard;
    }
 
    public void setPatternForCard(CardPattern patternForCard) {//設定牌的花色
        this.patternForCard = patternForCard;
    }
 
    public int getNumberForCard() {//取得牌位移後的數字
        return this.numberForCard;
    }
 
    public void setNumberForCard(int numberForCard) {//設定牌為位移的數字
        this.numberForCard = numberForCard;
    }
 
    public boolean equals(Card card) {//比較兩張牌是否同發色同數字同位移
        if (this.offset == card.offset) {
            if (this.numberForCard == card.getNumberForCard()) {
                if (this.patternForCard == card.getPatternForCard()) {
                    return true;
                }
            }
        }
        return false;
    }
 
    public int toCode() {//卡片轉代碼
        return this.patternForCard.ordinal() * 13 + this.getNumberForCard();
    }
 
    public String toString() {//卡片轉成文字
        String numberForDisplay;
        int realNumber = this.numberForCard;
        if (realNumber > 13) {//把位移過的卡片位移回來
            realNumber -= 13;
        }
        switch (realNumber) {//用通俗的說法輸出
            case 1:
                numberForDisplay = " A";
                break;
            case 11:
                numberForDisplay = " J";
                break;
            case 12:
                numberForDisplay = " Q";
                break;
            case 13:
                numberForDisplay = " K";
                break;
            default:
                numberForDisplay = String.format("%2d", this.numberForCard);
        }
        return this.getPatternForCard().getDescription() + numberForDisplay;
    }
}
 
enum CardPattern {//牌的花色
 
    CLUB, DIAMOND, HEART, SPADE, NULL;
 
    public String getDescription() {//獲得牌組的中文
        switch (this.ordinal()) {
            //梅花0,方塊1,愛心2,黑桃3
            case 0:
                return "梅花";
            case 1:
                return "方塊";
            case 2:
                return "愛心";
            case 3:
                return "黑桃";
            default:
                return null;
        }
    }
 
    public static CardPattern codeToPattern(int code) {//代號轉花色
 
        switch (code) {
            case 0:
                return Enum.valueOf(CardPattern.class, "CLUB");
 
            case 1:
                return Enum.valueOf(CardPattern.class, "DIAMOND");
 
            case 2:
                return Enum.valueOf(CardPattern.class, "HEART");
 
            case 3:
                return Enum.valueOf(CardPattern.class, "SPADE");
 
            default:
                return Enum.valueOf(CardPattern.class, "NULL");
        }
    }
}
 
class CardComparator implements Comparator {
//給TreeSet用的排序
 
    @Override
    public int compare(T c1, T c2) {
        return c1.toCode() - c2.toCode();
    }
}

Player.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package pokerGames;
 
/**
 * @author 幻冽(Magic Lea)
 */
public class Hearts {
 
    static int offset = 1;//此遊戲用到的位移
    private int game;//局
    private HeartsPlayer playerOne;//第一位玩家
    private boolean heartBreak;//紅心破碎
    private int patternOfRound;//這回合的花色
    private HeartsPlayer firstPlayerOfRound;//這回合先出牌的玩家
    private int round;//回合
    private Card[] cardsOfRound;//這回合已經出的牌
 
    public Hearts() {
        game = 0;
        playerOne = new HumanHeartPlayer(new ComAHeartsPlayer("王老虎", new ComAHeartsPlayer("謝老闆", new ComAHeartsPlayer("派大猩"))));
        heartBreak = false;
        patternOfRound = CardPattern.NULL.ordinal();
        firstPlayerOfRound = null;
        round = 0;
        Player.circularize(playerOne);
 
    }
 
    public Card[] getCardsOfRound() {
        return cardsOfRound;
    }
 
    private HeartsPlayer startByWho(Card card) {//有梅花2的先開始
        HeartsPlayer tempPlayer = playerOne;
        do {
            if (tempPlayer.haveThisCard(card)) {
                return tempPlayer;
            }
            tempPlayer = tempPlayer.getNextPlayer();
        } while (tempPlayer != playerOne);
        System.err.println("看到鬼!大家都沒有這張牌!");
        return null;
    }
 
    private void transferCard(HeartsPlayer playerOne) {//傳牌
        //右傳,左傳,對傳,不傳
        System.out.println("開始傳牌");
        if (this.game % 4 == 0) {//4的倍數不傳牌
            System.out.println("這次不傳牌");
            return;
        }
        Card transferedCard[][] = new Card[4][3];//暫存大家要傳的牌
        for (int counter = 0; counter < 4; counter++) {//各個詢問傳什麼牌
            transferedCard[counter] = playerOne.transferWhatCard();
            playerOne = playerOne.getNextPlayer();
        }
        HeartsPlayer tempPlayer = playerOne;
        int counter = 0;
        do {
            HeartsPlayer transferedPlayer = null;
            switch (this.game % 4) {//設定傳牌對象
                case 1:
                    transferedPlayer = tempPlayer.getNextPlayer();//右傳
                    break;
                case 2:
                    transferedPlayer = tempPlayer.getLastPlayer();//左傳
                    break;
                case 3:
                    transferedPlayer = tempPlayer.getNextPlayer().getNextPlayer();//對傳
                    break;
                case 0:
                    System.err.println("不該進入這裡");
                    return;
            }
 
            for (Card card : transferedCard[counter]) {//開始傳牌
                try {
                    tempPlayer.removeCard(card);
                    transferedPlayer.addCard(card);
                } catch (NullPointerException e) {
                    System.err.println("怎麼會沒有牌呢?");
                }
            }
            tempPlayer = tempPlayer.getNextPlayer();
            ++counter;
        } while (tempPlayer != playerOne);
    }
 
    private HeartsPlayer whoWinTheRound() {//判斷此回合誰吃牌
        //輸出這回合出的卡片
        System.out.print("這回合出的牌:");
        for (Card card : getCardsOfRound()) {
            System.out.print("[" + card + "] ");
        }
        //開始判斷
        HeartsPlayer tempPlayer = firstPlayerOfRound.getNextPlayer();
        HeartsPlayer winner = firstPlayerOfRound;
        Card CardForWinner = cardsOfRound[0];
 
        int counter = 1;
        while (tempPlayer != firstPlayerOfRound) {//一張一張比大小
            if (cardsOfRound[counter].getPatternForCard() == CardForWinner.getPatternForCard()) {
                if (cardsOfRound[counter].getNumberForCard() > CardForWinner.getNumberForCard()) {
                    winner = tempPlayer;
                    CardForWinner = cardsOfRound[counter];
                }
            }
            tempPlayer = tempPlayer.getNextPlayer();
            counter++;
        }
        for (Card card : cardsOfRound) {//吃到點牌便計分
            if (card.toCode() >= 28) {
                if (card.toCode() <= 40) {//愛心1~13
                    tempPlayer.addScoreCard(card);
                    tempPlayer.addScoreCard(card);
                    tempPlayer.addScoreForPlayer(1);
                }
                if (card.toCode() == 51) {//黑桃Q
                    tempPlayer.addScoreCard(card);
                    tempPlayer.addScoreCard(card);
                    tempPlayer.addScoreForPlayer(13);
                }
            }
        }
        System.out.println("," + winner + "得牌");
        return winner;
    }
 
    private HeartsPlayer discard() {//開始出牌
        HeartsPlayer tempPlayer = firstPlayerOfRound;
        cardsOfRound = new Card[4];
        int counter = 0;
        do {
            while (!isLegally(tempPlayer, cardsOfRound[counter])) {
                cardsOfRound[counter] = tempPlayer.discardWhatCard(getCardsOfRound());
                if (!isLegally(tempPlayer, cardsOfRound[counter])) {
                    cardsOfRound[counter] = null;
                }
            }
            tempPlayer.removeCard(cardsOfRound[counter]);//出牌後移除牌
            tempPlayer = tempPlayer.getNextPlayer();
            counter++;
        } while (tempPlayer != firstPlayerOfRound);
        return whoWinTheRound();
    }
 
    private void finalThisGame(HeartsPlayer playerOne) {//結束這場傷心小棧
        int[] scores = new int[4];
        int counter = 0;
        HeartsPlayer tempPlayer = playerOne;
        HeartsPlayer[] players = playerOne.toArray();
        do {
            scores[counter] = tempPlayer.getScoreForPlayer();
            tempPlayer = tempPlayer.getNextPlayer();
            counter++;
        } while (tempPlayer != playerOne);
        for (int i = 0; i < 3; i++) {//氣泡排序名次
            for (int j = i + 1; j < 4; j++) {
                if (scores[i] > scores[j]) {
                    int tempScore = scores[i];
                    tempPlayer = players[i];
                    scores[i] = scores[j];
                    players[i] = players[j];
                    scores[j] = tempScore;
                    players[j] = tempPlayer;
                }
            }
        }
        for (int n = 0; n < 4; n++) {//輸出名次
            System.out.println("第" + (n + 1) + "名:分數 " + scores[n] + " 的玩家 " + players[n]);
        }
    }
 
    private void setPatternOfRound(CardPattern pattern) {
        this.patternOfRound = pattern.ordinal();
    }
 
    private void setFirstPlayerOfRound(HeartsPlayer firstPlayer) {
        this.firstPlayerOfRound = firstPlayer;
    }
 
    private boolean isLegally(HeartsPlayer player, Card card) {//判斷出牌的合法性
        if (card == null) {
            return false;
        } else if (player == firstPlayerOfRound) {
            if (round == 1) {
                if (card.equals(new Card("CLUB", 2, Hearts.offset))) {
                } else {
                    if (player.errorHint) {
                        System.err.println("你必須出梅花2");
                    }
                    return false;
                }
            }
            if (card.getPatternForCard() == CardPattern.HEART) {
                if (this.heartBreak == true) {
                } else {
                    if (player.errorHint) {
                        System.err.println("尚未心碎,不得出愛心");
                    }
                    return false;
                }
            }
            setPatternOfRound(card.getPatternForCard());
            return true;
        } else {
            if (player.haveThisPattern(CardPattern.codeToPattern(patternOfRound))) {
                if (CardPattern.codeToPattern(patternOfRound) == card.getPatternForCard()) {
                    return true;
                } else {
                    if (player.errorHint) {
                        System.err.println("你必須跟牌,請出一張 "
                                + CardPattern.codeToPattern(patternOfRound).getDescription());
                    }
                    return false;
 
                }
            } else {
                if (card.getPatternForCard() == CardPattern.HEART) {
                    heartBreak = true;
                }
                return true;
            }
        }
    }
 
    private void nextGame() {//換下一局
        firstPlayerOfRound = null;
        game++;
        heartBreak = false;
        patternOfRound = CardPattern.NULL.ordinal();
        HeartsPlayer tempPlayer = playerOne;
        //清除上一回合的吃到的牌
        do {
            tempPlayer.clearScoreCard();
            tempPlayer = tempPlayer.getNextPlayer();
        } while (tempPlayer != playerOne);
        //建立牌
        int[] codeForCards = new int[52];
        for (int number = 0; number < 52; number++) {
            codeForCards[number] = number + Hearts.offset + 1;
        }
        //洗牌5000次
        for (int times = 1; times <= 5000; times++) {
            int rand1 = (int) (Math.random() * 100000) % 52;
            int rand2 = (int) (Math.random() * 100000) % 52;
            int temp = codeForCards[rand1];
            codeForCards[rand1] = codeForCards[rand2];
            codeForCards[rand2] = temp;
        }
        //發牌
        tempPlayer = playerOne;
        for (int element = 0; element < 52; element++) {
            int codeForCard = codeForCards[element];
            tempPlayer.addCard(new Card(codeForCard, Hearts.offset));
            tempPlayer = tempPlayer.getNextPlayer();
        }
    }
 
    public void newMoon() {//豬羊變色
        for (HeartsPlayer player : playerOne.toArray()) {
            if (player.getScoreCards().size() == 14) {
                System.out.println("豬~羊~變~色~");
                player.addScoreForPlayer(-26);
                HeartsPlayer tempPlayer = player.getNextPlayer();
                while (tempPlayer != player) {
                    tempPlayer.addScoreForPlayer(26);
                    tempPlayer = tempPlayer.getNextPlayer();
                }
            }
        }
    }
 
    public void play() {
        while (true) {
            HeartsPlayer tempPlayer = null;
            nextGame();
            //換牌
            transferCard(playerOne);
            //由誰開始
            setFirstPlayerOfRound(startByWho(new Card("CLUB", 2, Hearts.offset)));
            //出牌
            for (round = 1; round <= 13; round++) {
                setFirstPlayerOfRound(discard());
            }
            //豬羊變色
            newMoon();
            //展示分數
            tempPlayer = playerOne;
            int counter = 0;
            int[] scores = new int[4];
            do {
                tempPlayer.showAllScoreCard();
                scores[counter] = tempPlayer.getScoreForPlayer();
                System.out.println("目前分數是:" + scores[counter]);
                System.out.println("--------------------------------------------------");
                tempPlayer = tempPlayer.getNextPlayer();
                counter++;
            } while (tempPlayer != playerOne);
            //判斷結局
            for (int score : scores) {
                if (score >= 100) {
                    finalThisGame(playerOne);
                    return;
                }
            }
        }
    }
}

PokerGames.java

1
2
3
4
5
6
7
8
9
10
11
package pokerGames;
 
/**
 * @author 幻冽(Magic Lea)
 */
public class PokerGames {
	public static void main(String[] args) {
		Hearts hearts = new Hearts();
		hearts.play();
	}
}

總結

在設計上,有保留一些擴充性,以便未來可以增加其他種撲克牌玩法。因為這次作品算是一個概念性產品,主要是實作出遊戲功能,所以遊戲介面也不太講求,AI的智慧也算稱是沒智慧。預計未來會推出圖形介面,AI的智慧也會設計的更優良,一起期待吧!

文章分類:Java|標籤:, ,

迴響已關閉