File indexing completed on 2024-05-05 08:04:59
0001 # -*- coding: utf-8 -*- 0002 0003 """Copyright (C) 2009-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de> 0004 0005 SPDX-License-Identifier: GPL-2.0 0006 0007 """ 0008 0009 # See the user manual for a description of how to define rulesets. 0010 # Names and descriptions must be english and may only contain ascii chars. 0011 # The KDE translation teams will "automatically" translate name and 0012 # description into many languages. 0013 0014 from rule import PredefinedRuleset 0015 from mi18n import i18nE, i18n 0016 0017 0018 class ClassicalChinese(PredefinedRuleset): 0019 0020 """classical chinese rules, standard rules. Serves as a basis 0021 for local variants. This should be defined such that the 0022 sum of the differences to the local variants is minimized.""" 0023 0024 def __init__(self, name=None): 0025 PredefinedRuleset.__init__( 0026 self, 0027 name or i18nE('Classical Chinese standard')) 0028 0029 def _initRuleset(self): 0030 """set the description""" 0031 self.description = i18n('Classical Chinese') 0032 0033 def addManualRules(self): 0034 """those are actually winner rules but in the kajongg scoring mode they must be selected manually""" 0035 # applicable only if we have a concealed meld and a declared kong: 0036 self.winnerRules.createRule( 0037 'Last Tile Taken from Dead Wall', 0038 'FLastTileFromDeadWall||Olastsource=e', doubles=1, 0039 description=i18n('The dead wall is also called kong box: The last 16 tiles of the wall ' 0040 'used as source of replacement tiles')) 0041 self.winnerRules.createRule( 0042 'Last Tile is Last Tile of Wall', 0043 'FIsLastTileFromWall||Olastsource=z', doubles=1, 0044 description=i18n('Winner said Mah Jong with the last tile taken from the living end of the wall')) 0045 self.winnerRules.createRule( 0046 'Last Tile is Last Tile of Wall Discarded', 0047 'FIsLastTileFromWallDiscarded||Olastsource=Z', doubles=1, 0048 description=i18n('Winner said Mah Jong by claiming the last tile taken from the living end of the ' 0049 'wall, discarded by another player')) 0050 self.winnerRules.createRule( 0051 'Robbing the Kong', r'FRobbingKong||Olastsource=k', doubles=1, 0052 description=i18n('Winner said Mah Jong by claiming the 4th tile of a kong another player ' 0053 'just declared'), debug=True) 0054 self.winnerRules.createRule( 0055 'Mah Jongg with Original Call', 0056 'FMahJonggWithOriginalCall||Oannouncements=a', doubles=1, 0057 description=i18n( 0058 'Just before the first discard, a player can declare Original Call meaning she needs only one ' 0059 'tile to complete the hand and announces she will not alter the hand in any way (except bonus tiles)')) 0060 self.winnerRules.createRule( 0061 'Dangerous Game', 'FDangerousGame||Opayforall', 0062 description=i18n('In some situations discarding a tile that has a high chance to help somebody to win ' 0063 'is declared to be dangerous, and if that tile actually makes somebody win, the discarder ' 0064 'pays the winner for all')) 0065 self.winnerRules.createRule( 0066 'Twofold Fortune', 'FTwofoldFortune||Oannouncements=t', 0067 limits=1, description=i18n('Kong after Kong: Declare Kong and a second Kong with the replacement ' 0068 'tile and Mah Jong with the second replacement tile')) 0069 # limit hands: 0070 self.winnerRules.createRule( 0071 'Blessing of Heaven', 'FBlessingOfHeaven||Olastsource=1', limits=1, 0072 description=i18n('East says Mah Jong with the unmodified dealt tiles')) 0073 self.winnerRules.createRule( 0074 'Blessing of Earth', 'FBlessingOfEarth||Olastsource=1', limits=1, 0075 description=i18n('South, West or North says Mah Jong with the first tile discarded by East')) 0076 self.winnerRules.createRule( 0077 'East won nine times in a row', 'FEastWonNineTimesInARow||Orotate', limits=1, 0078 description=i18n('If that happens, East gets a limit score and the winds rotate')) 0079 0080 def addPenaltyRules(self): 0081 """as the name says""" 0082 self.penaltyRules.createRule( 0083 'False Naming of Discard, Claimed for Mah Jongg and False Declaration of Mah Jongg', 0084 'Oabsolute payers=2 payees=2', points=-300) 0085 0086 def addHandRules(self): 0087 """as the name says""" 0088 self.handRules.createRule( 0089 'Own Flower and Own Season', 0090 'FOwnFlowerOwnSeason', 0091 doubles=1) 0092 self.handRules.createRule('All Flowers', 'FAllFlowers', doubles=1) 0093 self.handRules.createRule('All Seasons', 'FAllSeasons', doubles=1) 0094 self.handRules.createRule( 0095 'Three Concealed Pongs', 0096 'FThreeConcealedPongs', 0097 doubles=1) 0098 self.handRules.createRule( 0099 'Long Hand', r'FLongHand||Oabsolute', points=0, 0100 description=i18n('The hand contains too many tiles')) 0101 0102 def addParameterRules(self): 0103 """as the name says""" 0104 self.parameterRules.createRule( 0105 'Points Needed for Mah Jongg', 0106 'intminMJPoints', 0107 parameter=0) 0108 self.parameterRules.createRule( 0109 'Minimum number of doubles needed for Mah Jongg', 0110 'intminMJDoubles', parameter=0) 0111 self.parameterRules.createRule( 0112 'Points for a Limit Hand', 0113 'intlimit||Omin=1', 0114 parameter=500) 0115 self.parameterRules.createRule( 0116 'Play with the roof off', 'boolroofOff', parameter=False, 0117 description=i18n('Play with no upper scoring limit')) 0118 self.parameterRules.createRule( 0119 'Claim Timeout', 0120 'intclaimTimeout', 0121 parameter=10) 0122 self.parameterRules.createRule( 0123 'Size of Kong Box', 'intkongBoxSize', parameter=16, 0124 description=i18n('The Kong Box is used for replacement tiles when declaring kongs')) 0125 self.parameterRules.createRule( 0126 'Play with Bonus Tiles', 'boolwithBonusTiles', parameter=True, 0127 description=i18n('Bonus tiles increase the luck factor')) 0128 self.parameterRules.createRule( 0129 'Minimum number of rounds in game', 0130 'intminRounds', 0131 parameter=4) 0132 self.parameterRules.createRule( 0133 'number of allowed chows', 'intmaxChows', parameter=4, 0134 description=i18n('The number of chows a player may build')) 0135 self.parameterRules.createRule( 0136 'must declare calling hand', 0137 'boolmustDeclareCallingHand', parameter=False, 0138 description=i18n('Mah Jongg is only allowed after having declared to have a calling hand')) 0139 self.parameterRules.createRule( 0140 'Standard Rotation', 0141 'FStandardRotation||Orotate||Ointernal') 0142 0143 def loadRules(self): 0144 """define the rules""" 0145 self.addParameterRules() # must be first! 0146 self.addPenaltyRules() 0147 self.addHandRules() 0148 self.addManualRules() 0149 self.winnerRules.createRule( 0150 'Last Tile Completes Pair of 2..8', 0151 'FLastTileCompletesPairMinor', 0152 points=2) 0153 self.winnerRules.createRule( 0154 'Last Tile Completes Pair of Terminals or Honors', 0155 'FLastTileCompletesPairMajor', points=4) 0156 self.winnerRules.createRule( 0157 'Last Tile is Only Possible Tile', 0158 'FLastOnlyPossible', 0159 points=2) 0160 self.winnerRules.createRule( 0161 'Won with Last Tile Taken from Wall', 0162 'FLastFromWall', 0163 points=2) 0164 0165 self.winnerRules.createRule( 0166 'Zero Point Hand', 'FZeroPointHand', doubles=1, 0167 description=i18n('The hand has 0 basis points excluding bonus tiles')) 0168 self.winnerRules.createRule('No Chow', 'FNoChow', doubles=1) 0169 self.winnerRules.createRule( 0170 'Only Concealed Melds', 0171 'FOnlyConcealedMelds', 0172 doubles=1) 0173 self.winnerRules.createRule( 0174 'False Color Game', 'FFalseColorGame', doubles=1, 0175 description=i18n('Only same-colored tiles (only bamboo/stone/character) ' 0176 'plus any number of winds and dragons')) 0177 self.winnerRules.createRule( 0178 'True Color Game', 'FTrueColorGame', doubles=3, 0179 description=i18n('Only same-colored tiles (only bamboo/stone/character)')) 0180 self.winnerRules.createRule( 0181 'Concealed True Color Game', 'FConcealedTrueColorGame', 0182 limits=1, description=i18n('All tiles concealed and of the same suit, no honors')) 0183 self.winnerRules.createRule( 0184 'Only Terminals and Honors', 'FOnlyMajors', doubles=1, 0185 description=i18n('Only winds, dragons, 1 and 9')) 0186 self.winnerRules.createRule('Only Honors', 'FOnlyHonors', limits=1, 0187 description=i18n('Only winds and dragons')) 0188 self.winnerRules.createRule( 0189 'Hidden Treasure', 'FHiddenTreasure', limits=1, 0190 description=i18n('Only hidden Pungs or Kongs, last tile from wall')) 0191 self.winnerRules.createRule( 0192 'Heads and Tails', 'FAllTerminals', limits=1, 0193 description=i18n('Only 1 and 9')) 0194 self.winnerRules.createRule( 0195 'Fourfold Plenty', 'FFourfoldPlenty', limits=1, 0196 description=i18n('4 Kongs')) 0197 self.winnerRules.createRule( 0198 'Three Great Scholars', 'FThreeGreatScholars', limits=1, 0199 description=i18n('3 Pungs or Kongs of dragons')) 0200 self.winnerRules.createRule('Four Blessings Hovering over the Door', 0201 'FFourBlessingsHoveringOverTheDoor', limits=1, 0202 description=i18n('4 Pungs or Kongs of winds')) 0203 self.winnerRules.createRule('Imperial Jade', 'FAllGreen', limits=1, 0204 description=i18n('Only green tiles: Green dragon and Bamboo 2,3,4,6,8')) 0205 self.winnerRules.createRule('Gathering the Plum Blossom from the Roof', 0206 'FGatheringPlumBlossomFromRoof', limits=1, 0207 description=i18n('Mah Jong with stone 5 from the dead wall')) 0208 self.winnerRules.createRule( 0209 'Plucking the Moon from the Bottom of the Sea', 'FPluckingMoon', limits=1, 0210 description=i18n('Mah Jong with the last tile from the wall being a stone 1')) 0211 self.winnerRules.createRule( 0212 'Scratching a Carrying Pole', 'FScratchingPole', limits=1, 0213 description=i18n('Robbing the Kong of bamboo 2')) 0214 0215 # only hands matching an mjRule can win. Keep this list as short as 0216 # possible. If a special hand matches the standard pattern, do not put it here 0217 # All mjRule functions must have a winningTileCandidates() method 0218 self.mjRules.createRule( 0219 'Standard Mah Jongg', 0220 'FStandardMahJongg', 0221 points=20) 0222 # option internal makes it not show up in the ruleset editor 0223 self.mjRules.createRule( 0224 'Nine Gates', 'FNineGates', limits=1, 0225 description=i18n( 0226 'A concealed hand in one color 1112345678999 plus last tile of this suit (from wall or discarded)')) 0227 self.mjRules.createRule( 0228 'Thirteen Orphans', 'FThirteenOrphans||Omayrobhiddenkong', limits=1, 0229 description=i18n('13 single tiles: All dragons, winds, 1, 9 and a 14th tile building a pair ' 0230 'with one of them')) 0231 0232 # doubling melds: 0233 self.meldRules.createRule('Pung/Kong of Dragons', 'FDragonPungKong', 0234 explainTemplate='{meldName}', doubles=1) 0235 self.meldRules.createRule('Pung/Kong of Own Wind', 'FOwnWindPungKong', 0236 explainTemplate='{meldType} of Own Wind ({value})', doubles=1) 0237 self.meldRules.createRule( 0238 'Pung/Kong of Round Wind', 'FRoundWindPungKong', 0239 explainTemplate='{meldType} of Round Wind ({value})', doubles=1) 0240 0241 # exposed melds: 0242 self.meldRules.createRule('Exposed Kong', 'FExposedMinorKong', 0243 explainTemplate='{meldName}', points=8) 0244 self.meldRules.createRule( 0245 'Exposed Kong of Terminals', 'FExposedTerminalsKong', 0246 explainTemplate='{meldName}', points=16) 0247 self.meldRules.createRule( 0248 'Exposed Kong of Honors', 'FExposedHonorsKong', 0249 explainTemplate='{meldName}', points=16) 0250 0251 self.meldRules.createRule('Exposed Pung', 'FExposedMinorPung', 0252 explainTemplate='{meldName}', points=2) 0253 self.meldRules.createRule( 0254 'Exposed Pung of Terminals', 'FExposedTerminalsPung', 0255 explainTemplate='{meldName}', points=4) 0256 self.meldRules.createRule( 0257 'Exposed Pung of Honors', 'FExposedHonorsPung', 0258 explainTemplate='{meldName}', points=4) 0259 0260 # concealed melds: 0261 self.meldRules.createRule('Concealed Kong', 'FConcealedMinorKong', 0262 explainTemplate='{meldName}', points=16) 0263 self.meldRules.createRule( 0264 'Concealed Kong of Terminals', 'FConcealedTerminalsKong', 0265 explainTemplate='{meldName}', points=32) 0266 self.meldRules.createRule( 0267 'Concealed Kong of Honors', 'FConcealedHonorsKong', 0268 explainTemplate='{meldName}', points=32) 0269 0270 self.meldRules.createRule('Concealed Pung', 'FConcealedMinorPung', 0271 explainTemplate='{meldName}', points=4) 0272 self.meldRules.createRule( 0273 'Concealed Pung of Terminals', 'FConcealedTerminalsPung', 0274 explainTemplate='{meldName}', points=8) 0275 self.meldRules.createRule( 0276 'Concealed Pung of Honors', 'FConcealedHonorsPung', 0277 explainTemplate='{meldName}', points=8) 0278 0279 self.meldRules.createRule('Pair of Own Wind', 'FOwnWindPair', 0280 explainTemplate='Pair of Own Wind ({value})', points=2) 0281 self.meldRules.createRule('Pair of Round Wind', 'FRoundWindPair', 0282 explainTemplate='Pair of Round Wind ({value})', points=2) 0283 self.meldRules.createRule('Pair of Dragons', 'FDragonPair', 0284 explainTemplate='{meldName}', points=2) 0285 0286 # bonus tiles: 0287 self.meldRules.createRule('Flower', 'FFlower', 0288 explainTemplate='{meldName}', points=4) 0289 self.meldRules.createRule('Season', 'FSeason', 0290 explainTemplate='{meldName}', points=4) 0291 0292 0293 class ClassicalChineseDMJL(ClassicalChinese): 0294 0295 """classical chinese rules, German rules""" 0296 0297 def __init__(self, name=None): 0298 ClassicalChinese.__init__( 0299 self, 0300 name or i18nE('Classical Chinese DMJL')) 0301 0302 def _initRuleset(self): 0303 """set the description""" 0304 ClassicalChinese._initRuleset(self) 0305 self.description = i18n( 0306 'Classical Chinese as defined by the Deutsche Mah Jongg Liga (DMJL) e.V.') 0307 0308 def loadRules(self): 0309 ClassicalChinese.loadRules(self) 0310 # the squirming snake is only covered by standard mahjongg rule if 0311 # tiles are ordered 0312 self.mjRules.createRule( 0313 'Squirming Snake', 'FSquirmingSnake', limits=1, 0314 description=i18n('All tiles of same color. Pung or Kong of 1 and 9, pair of 2, 5 or 8 and two ' 0315 'Chows of the remaining values')) 0316 self.handRules.createRule( 0317 'Little Three Dragons', 'FLittleThreeDragons', doubles=1, 0318 description=i18n('2 Pungs or Kongs of dragons and 1 pair of dragons')) 0319 self.handRules.createRule( 0320 'Big Three Dragons', 'FBigThreeDragons', doubles=2, 0321 description=i18n('3 Pungs or Kongs of dragons')) 0322 self.handRules.createRule( 0323 'Little Four Joys', 'FLittleFourJoys', doubles=1, 0324 description=i18n('3 Pungs or Kongs of winds and 1 pair of winds')) 0325 self.handRules.createRule('Big Four Joys', 'FBigFourJoys', doubles=2, 0326 description=i18n('4 Pungs or Kongs of winds')) 0327 0328 self.winnerRules['OnlyHonors'].doubles = 2 0329 0330 self.penaltyRules.createRule( 0331 'False Naming of Discard, Claimed for Chow', 0332 points=-50) 0333 self.penaltyRules.createRule( 0334 'False Naming of Discard, Claimed for Pung/Kong', 0335 points=-100) 0336 self.penaltyRules.createRule( 0337 'False Declaration of Mah Jongg by One Player', 0338 'Oabsolute payees=3', points=-300) 0339 self.penaltyRules.createRule( 0340 'False Declaration of Mah Jongg by Two Players', 0341 'Oabsolute payers=2 payees=2', points=-300) 0342 self.penaltyRules.createRule( 0343 'False Declaration of Mah Jongg by Three Players', 0344 'Oabsolute payers=3', points=-300) 0345 self.penaltyRules.createRule( 0346 'False Naming of Discard, Claimed for Mah Jongg', 0347 'Oabsolute payees=3', points=-300) 0348 0349 0350 class ClassicalChineseBMJA(ClassicalChinese): 0351 0352 """classical chinese rules, British rules""" 0353 0354 def __init__(self, name=None): 0355 ClassicalChinese.__init__( 0356 self, 0357 name or i18nE('Classical Chinese BMJA')) 0358 0359 def _initRuleset(self): 0360 """set the description""" 0361 ClassicalChinese._initRuleset(self) 0362 self.description = i18n( 0363 'Classical Chinese as defined by the British Mah-Jong Association') 0364 0365 def addParameterRules(self): 0366 """those differ for BMJA from standard""" 0367 ClassicalChinese.addParameterRules(self) 0368 self.parameterRules['kongBoxSize'].parameter = 14 0369 self.parameterRules['maxChows'].parameter = 1 0370 self.parameterRules['limit'].parameter = 1000 0371 self.parameterRules['mustDeclareCallingHand'].parameter = True 0372 0373 def loadRules(self): 0374 ClassicalChinese.loadRules(self) 0375 del self.winnerRules['ZeroPointHand'] 0376 originalCall = self.winnerRules.pop('MahJonggwithOriginalCall') 0377 self.winnerRules.createRule( 0378 'Original Call', originalCall.definition, doubles=1, 0379 description=originalCall.description) 0380 del self.mjRules['NineGates'] 0381 self.mjRules.createRule( 0382 'Gates of Heaven', 'FGatesOfHeaven', limits=1, 0383 description=i18n('All tiles concealed of same color: Values 1112345678999' 0384 ' with one pair from 2 to 8 (last tile from wall or discarded)')) 0385 self.mjRules.createRule( 0386 'Wriggling Snake', 'FWrigglingSnake', limits=1, 0387 description=i18n('Pair of 1s and a run from 2 to 9 in the same suit with each of the winds')) 0388 self.mjRules.createRule( 0389 'Triple Knitting', 'FTripleKnitting', limits=0.5, 0390 description=i18n('Four sets of three tiles in the different suits and a pair: No Winds or Dragons')) 0391 self.mjRules.createRule('Knitting', 'FKnitting', limits=0.5, 0392 description=i18n('7 pairs of tiles in any 2 out of 3 suits; no Winds or Dragons')) 0393 self.mjRules.createRule( 0394 'All pair honors', 'FAllPairHonors', limits=0.5, 0395 description=i18n('7 pairs of 1s/9s/Winds/Dragons')) 0396 del self.handRules['OwnFlowerandOwnSeason'] 0397 del self.handRules['ThreeConcealedPongs'] 0398 self.meldRules.createRule('Own Flower', 'FOwnFlower', doubles=1) 0399 self.meldRules.createRule('Own Season', 'FOwnSeason', doubles=1) 0400 del self.winnerRules['LastTileTakenfromDeadWall'] 0401 del self.winnerRules['HiddenTreasure'] 0402 del self.winnerRules['FalseColorGame'] 0403 del self.winnerRules['ConcealedTrueColorGame'] 0404 del self.winnerRules['Eastwonninetimesinarow'] 0405 del self.winnerRules['LastTileCompletesPairof28'] 0406 del self.winnerRules['LastTileCompletesPairofTerminalsorHonors'] 0407 del self.winnerRules['LastTileisOnlyPossibleTile'] 0408 del self.winnerRules['TrueColorGame'] 0409 del self.winnerRules['ThreeGreatScholars'] 0410 self.winnerRules.createRule( 0411 'Buried Treasure', 'FBuriedTreasure', limits=1, 0412 description=i18n('Concealed pungs of one suit with winds/dragons and a pair')) 0413 self.winnerRules.createRule('Purity', 'FPurity', doubles=3, 0414 description=i18n('Only same-colored tiles (no chows, dragons or winds)')) 0415 self.winnerRules.createRule( 0416 'Three Great Scholars', 'FThreeGreatScholars||Onochow', limits=1, 0417 description=i18n('3 Pungs or Kongs of dragons plus any pung/kong and a pair')) 0418 orphans = self.mjRules.pop('ThirteenOrphans') 0419 self.mjRules.createRule( 0420 'The 13 Unique Wonders', 0421 orphans.definition, 0422 limits=1, 0423 description=orphans.description) 0424 self.handRules['AllFlowers'].score.doubles = 2 0425 self.handRules['AllSeasons'].score.doubles = 2 0426 self.penaltyRules.createRule( 0427 'False Naming of Discard, Claimed for Chow/Pung/Kong', 0428 points=-50) 0429 self.penaltyRules.createRule( 0430 'False Declaration of Mah Jongg by One Player', 0431 'Oabsolute payees=3', limits=-0.5) 0432 self.winnerRules.createRule( 0433 'False Naming of Discard, Claimed for Mah Jongg', 0434 'FFalseDiscardForMJ||Opayforall') 0435 0436 self.loserRules.createRule( 0437 'Calling for Only Honors', 0438 'FCallingHand||Ohand=OnlyHonors', 0439 limits=0.4) 0440 self.loserRules.createRule( 0441 'Calling for Wriggling Snake', 0442 'FCallingHand||Ohand=WrigglingSnake', 0443 limits=0.4) 0444 self.loserRules.createRule( 0445 'Calling for Triple Knitting', 0446 'FCallingHand||Ohand=TripleKnitting', 0447 limits=0.2) 0448 self.loserRules.createRule( 0449 'Calling for Gates of Heaven', 'FCallingHand||Ohand=GatesofHeaven', 0450 limits=0.4) 0451 self.loserRules.createRule( 0452 'Calling for Knitting', 0453 'FCallingHand||Ohand=Knitting', 0454 limits=0.2) 0455 self.loserRules.createRule( 0456 'Calling for Imperial Jade', 0457 'FCallingHand||Ohand=ImperialJade', 0458 limits=0.4) 0459 self.loserRules.createRule( 0460 'Calling for The 13 Unique Wonders', 'FCallingHand||Ohand=The13UniqueWonders', 0461 limits=0.4) 0462 self.loserRules.createRule( 0463 'Calling for Three Great Scholars', 'FCallingHand||Ohand=ThreeGreatScholars', 0464 limits=0.4) 0465 self.loserRules.createRule( 0466 'Calling for All pair honors', 0467 'FCallingHand||Ohand=Allpairhonors', 0468 limits=0.2) 0469 self.loserRules.createRule( 0470 'Calling for Heads and Tails', 0471 'FCallingHand||Ohand=HeadsandTails', 0472 limits=0.4) 0473 self.loserRules.createRule( 0474 'Calling for Four Blessings Hovering over the Door', 0475 'FCallingHand||Ohand=FourBlessingsHoveringovertheDoor', limits=0.4) 0476 self.loserRules.createRule( 0477 'Calling for Buried Treasure', 0478 'FCallingHand||Ohand=BuriedTreasure', 0479 limits=0.4) 0480 self.loserRules.createRule( 0481 'Calling for Fourfold Plenty', 0482 'FCallingHand||Ohand=FourfoldPlenty', 0483 limits=0.4) 0484 self.loserRules.createRule( 0485 'Calling for Purity', 0486 'FCallingHand||Ohand=Purity', 0487 doubles=3) 0488 0489 def load(): 0490 """load predefined rulesets. 0491 add new predefined rulesets here. 0492 """ 0493 assert not PredefinedRuleset.classes 0494 PredefinedRuleset.classes.add(ClassicalChineseDMJL) 0495 PredefinedRuleset.classes.add(ClassicalChineseBMJA)