Skip to content

Commit d23e29d

Browse files
committed
fix(mahjong): allow chow without pong/gong and relax hu pair
1 parent d7d0a95 commit d23e29d

File tree

3 files changed

+104
-6
lines changed

3 files changed

+104
-6
lines changed

rlcard/games/mahjong/judger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ def judge_hu(self, player):
133133
continue
134134
tmp_set_count = 0
135135
tmp_hand = hand.copy()
136-
if count_dict[each] == 2:
137-
for _ in range(count_dict[each]):
136+
if count_dict[each] >= 2:
137+
for _ in range(2):
138138
tmp_hand.pop(tmp_hand.index(each))
139139
tmp_set_count, _set = self.cal_set(tmp_hand)
140140
used.extend(_set)

rlcard/games/mahjong/round.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,16 @@ def proceed_round(self, players, action):
7373
self.last_player = self.current_player
7474
self.current_player = player.player_id
7575
else:
76-
self.last_player = self.current_player
77-
self.current_player = (self.current_player + 1) % 4
78-
self.dealer.deal_cards(players[self.current_player], 1)
76+
(chow_act, chow_player, chow_cards) = self.judger.judge_chow(self.dealer, players, self.last_player)
77+
if chow_act:
78+
self.valid_act = chow_act
79+
self.last_cards = chow_cards
80+
self.last_player = self.current_player
81+
self.current_player = chow_player.player_id
82+
else:
83+
self.last_player = self.current_player
84+
self.current_player = (self.current_player + 1) % 4
85+
self.dealer.deal_cards(players[self.current_player], 1)
7986

8087
#hand_len = [len(p.hand) for p in players]
8188
#pile_len = [sum([len([c for c in p]) for p in pp.pile]) for pp in players]
@@ -107,4 +114,3 @@ def get_state(self, players, player_id):
107114
state['players_pile'] = {p.player_id: p.pile for p in players}
108115
state['action_cards'] = players[player_id].hand # For doing action (pong, chow, gong)
109116
return state
110-
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import unittest
2+
3+
from rlcard.games.mahjong.card import MahjongCard
4+
from rlcard.games.mahjong.game import MahjongGame
5+
from rlcard.games.mahjong.player import MahjongPlayer
6+
from rlcard.games.mahjong.utils import init_deck
7+
8+
9+
def _take_card(deck, card_str):
10+
for index, card in enumerate(deck):
11+
if card.get_str() == card_str:
12+
return deck.pop(index)
13+
raise AssertionError("Card not found in deck: {}".format(card_str))
14+
15+
16+
def _fill_hand(deck, size, seed_cards):
17+
hand = list(seed_cards)
18+
while len(hand) < size:
19+
hand.append(deck.pop())
20+
return hand
21+
22+
23+
def _make_card(code):
24+
if len(code) == 2 and code[0] in ("B", "C", "D") and code[1].isdigit():
25+
suit = {"B": "bamboo", "C": "characters", "D": "dots"}[code[0]]
26+
trait = code[1]
27+
else:
28+
suit = "winds" if code in {"East", "South", "West", "North"} else "dragons"
29+
trait = code.lower()
30+
card = MahjongCard(suit, trait)
31+
if suit in {"bamboo", "characters", "dots"}:
32+
card.set_index_num(int(trait) - 1)
33+
else:
34+
card.set_index_num(0)
35+
return card
36+
37+
38+
class TestMahjongRegressions(unittest.TestCase):
39+
40+
def test_chow_available_without_pong_gong(self):
41+
game = MahjongGame()
42+
game.init_game()
43+
44+
deck = init_deck()
45+
discard_card = _take_card(deck, "characters-9")
46+
deck = [card for card in deck if card.get_str() != "characters-9"]
47+
48+
chow_cards = [
49+
_take_card(deck, "characters-7"),
50+
_take_card(deck, "characters-8"),
51+
]
52+
53+
game.players[0].hand = _fill_hand(deck, 14, [discard_card])
54+
game.players[1].hand = _fill_hand(deck, 13, chow_cards)
55+
game.players[2].hand = _fill_hand(deck, 13, [])
56+
game.players[3].hand = _fill_hand(deck, 13, [])
57+
game.dealer.deck = deck
58+
game.dealer.table = []
59+
game.round.current_player = 0
60+
game.round.valid_act = False
61+
62+
game.round.proceed_round(game.players, discard_card)
63+
64+
state = game.get_state(game.round.current_player)
65+
self.assertEqual(state["valid_act"], ["chow", "stand"])
66+
67+
def test_hu_allows_pair_from_triplet(self):
68+
game = MahjongGame()
69+
game.init_game()
70+
71+
player = MahjongPlayer(0, game.np_random)
72+
player.hand = [
73+
_make_card("C5"),
74+
_make_card("C6"),
75+
_make_card("C7"),
76+
_make_card("D7"),
77+
_make_card("D7"),
78+
_make_card("D7"),
79+
_make_card("D8"),
80+
_make_card("D9"),
81+
]
82+
player.pile = [
83+
[_make_card("B9"), _make_card("B9"), _make_card("B9")],
84+
[_make_card("B5"), _make_card("B5"), _make_card("B5")],
85+
]
86+
87+
win, _ = game.judger.judge_hu(player)
88+
self.assertTrue(win)
89+
90+
91+
if __name__ == "__main__":
92+
unittest.main()

0 commit comments

Comments
 (0)