mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-03-12 04:07:01 -04:00
Compare commits
5 commits
9773eee2d6
...
72386af5e6
Author | SHA1 | Date | |
---|---|---|---|
|
72386af5e6 | ||
|
a57f1eae38 | ||
|
6f0c6e00e1 | ||
|
512d3ea466 | ||
|
e7e9f0ff87 |
20 changed files with 209 additions and 20 deletions
27
html-src/rules/noumea.html
Normal file
27
html-src/rules/noumea.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<h1>Noumea</h1>
|
||||
<p>
|
||||
One-Deck game type. 1 decks. 2 redeals.
|
||||
|
||||
<h3>Object</h3>
|
||||
<p>
|
||||
Move all cards to the foundations.
|
||||
|
||||
<h3>Rules</h3>
|
||||
<p>
|
||||
The four aces are dealt to the foundations, and 20 cards
|
||||
are dealt to reserve piles. The reserve piles can hold a
|
||||
single card and are automatically filled from the waste or
|
||||
talon when empty.
|
||||
<p>
|
||||
There is no building on the tableau piles, so you can
|
||||
only move cards to the foundations.
|
||||
<p>
|
||||
When there are no moves left, you can deal cards three at
|
||||
a time from the talon, and move them to an appropriate
|
||||
foundation. Two redeals are allowed, so you can go through
|
||||
the deck three times. The game is won if all cards are
|
||||
moved to the foundations.
|
||||
|
||||
<h3>Notes</h3>
|
||||
<p>
|
||||
<i>Autodrop</i> is disabled for this game.
|
|
@ -35,7 +35,8 @@ from pysollib.app_stat_result import GameStatResult
|
|||
from pysollib.app_statistics import Statistics
|
||||
from pysollib.cardsetparser import read_cardset_config
|
||||
from pysollib.gamedb import GAME_DB, GI, loadGame
|
||||
from pysollib.help import destroy_help_html, help_about, raise_help_html
|
||||
from pysollib.help import (destroy_help_html, help_about, raise_help_html,
|
||||
unraise_help_html)
|
||||
from pysollib.images import Images, SubsampledImages
|
||||
from pysollib.mfxutil import Struct, destruct
|
||||
from pysollib.mfxutil import USE_PIL
|
||||
|
@ -58,6 +59,9 @@ from pysollib.pysoltk import loadImage, wm_withdraw
|
|||
from pysollib.pysoltk import raise_find_card_dialog
|
||||
from pysollib.pysoltk import raise_full_picture_dialog
|
||||
from pysollib.pysoltk import raise_solver_dialog
|
||||
from pysollib.pysoltk import unraise_find_card_dialog
|
||||
from pysollib.pysoltk import unraise_full_picture_dialog
|
||||
from pysollib.pysoltk import unraise_solver_dialog
|
||||
from pysollib.resource import CSI, CardsetManager
|
||||
from pysollib.resource import Music, MusicManager
|
||||
from pysollib.resource import Sample, SampleManager
|
||||
|
@ -525,6 +529,12 @@ class Application:
|
|||
raise_solver_dialog(self.game)
|
||||
raise_help_html(self.game)
|
||||
|
||||
def unraiseAll(self):
|
||||
unraise_find_card_dialog()
|
||||
unraise_full_picture_dialog()
|
||||
unraise_solver_dialog()
|
||||
unraise_help_html()
|
||||
|
||||
def loadImages1(self):
|
||||
# load dialog images
|
||||
dirname = os.path.join("images", "logos")
|
||||
|
|
|
@ -591,6 +591,8 @@ class Game(object):
|
|||
self.initBindings()
|
||||
# self.top.bind('<ButtonPress>', self.top._sleepEvent)
|
||||
# self.top.bind('<3>', self.top._sleepEvent)
|
||||
self.top.bind("<FocusOut>", self.top._focusOutEvent)
|
||||
self.top.bind("<FocusIn>", self.top._focusInEvent)
|
||||
# update display properties
|
||||
self.canvas.busy = True
|
||||
# geometry
|
||||
|
|
|
@ -594,7 +594,7 @@ class GI:
|
|||
tuple(range(19000, 19012)) + tuple(range(22303, 22311)) +
|
||||
tuple(range(22353, 22361))),
|
||||
('fc-3.1', tuple(range(961, 971))),
|
||||
('dev', tuple(range(971, 978)) + tuple(range(5419, 5421)) +
|
||||
('dev', tuple(range(971, 979)) + tuple(range(5419, 5421)) +
|
||||
tuple(range(16683, 16685)) + tuple(range(18005, 18007)) +
|
||||
(44, 526,)),
|
||||
)
|
||||
|
|
|
@ -366,7 +366,7 @@ r(5419, "Lizard", layout="0aadaafaahaajhbe" +
|
|||
"hkhakiokihkjakko" +
|
||||
"kkvklakmvknakook" +
|
||||
"ohkpakqhllolmhln" +
|
||||
"amaamkammamohnlo" +
|
||||
"ambamkammamohnlo" +
|
||||
"nmhnnaokaomaoohp" +
|
||||
"lopmhpnaqjaqlaqn" +
|
||||
"hrkorlhrmasjasla" +
|
||||
|
@ -384,21 +384,19 @@ r(5419, "Lizard", layout="0aadaafaahaajhbe" +
|
|||
r(5420, "Candy", layout="0daadaccaebagbai" +
|
||||
"aakdcbccdbcfbcha" +
|
||||
"cjcecbeebegaeibg" +
|
||||
"dbgfaghbieaigakd" +
|
||||
"akfakhhlfambamda" +
|
||||
"mfamhamjhnchneon" +
|
||||
"fhnghniaobaodaof" +
|
||||
"aohaojhpcipeipgh" +
|
||||
"piaqbaqdaqfvqfaq" +
|
||||
"haqjhrcireirghri" +
|
||||
"asbasdasfashasjh" +
|
||||
"tchteotfhtghtiau" +
|
||||
"baudaufauhaujhvf" +
|
||||
"awdawfawhayebyga" +
|
||||
"AdbAfbAhaCcbCebC" +
|
||||
"gcCiaEbbEdbEfcEh" +
|
||||
"dEjaGabGcbGecGgd" +
|
||||
"GidGk")
|
||||
"dbgfaghbieaigakc" +
|
||||
"akeakgakiamaamcb" +
|
||||
"mebmgamiamkaoabo" +
|
||||
"cboebogboiaokopf" +
|
||||
"aqabqcbqebqgbqia" +
|
||||
"qkorfasabscbsebs" +
|
||||
"gbsiaskauaaucbue" +
|
||||
"bugauiaukawcawea" +
|
||||
"wgawiayebygaAdbA" +
|
||||
"fbAhaCcbCebCgcCi" +
|
||||
"aEbbEdbEfcEhdEja" +
|
||||
"GabGcbGecGgdGidG" +
|
||||
"k")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
|
|
@ -299,6 +299,9 @@ class Quatorze(MonteCarlo):
|
|||
return (stack1.id // 5 == stack2.id // 5 or
|
||||
stack1.id % 5 == stack2.id % 5)
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return card1.rank + card2.rank == 12
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Simple Pairs
|
||||
|
@ -364,6 +367,10 @@ class BlockTen(SimplePairs):
|
|||
def isGameWon(self):
|
||||
return len(self.s.foundations[0].cards) == 48
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return (card1.rank + card2.rank == 8 or
|
||||
(9 < card1.rank == card2.rank > 9))
|
||||
|
||||
|
||||
class SimpleTens(BlockTen):
|
||||
def isGameWon(self):
|
||||
|
@ -1108,6 +1115,10 @@ class AcesSquare(MonteCarlo):
|
|||
return (stack1.id // 4 == stack2.id // 4 or
|
||||
stack1.id % 4 == stack2.id % 4)
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return (card1.suit == card2.suit and
|
||||
card1.rank != card2.rank != 0)
|
||||
|
||||
|
||||
# register the game
|
||||
registerGame(GameInfo(89, MonteCarlo, "Monte Carlo",
|
||||
|
|
|
@ -861,6 +861,9 @@ class Fifteens(Elevens):
|
|||
self._dropReserve()
|
||||
self.leaveState(old_state)
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return card1.rank + card2.rank == 13
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Eighteens
|
||||
|
@ -953,6 +956,9 @@ class Eighteens(Fifteens):
|
|||
self._dropReserve()
|
||||
self.leaveState(old_state)
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return False # How?
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Neptune
|
||||
|
@ -982,6 +988,10 @@ class Neptune(Thirteens):
|
|||
def isGameWon(self):
|
||||
return len(self.s.talon.cards) == 0
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return (card1.rank == card2.rank - 1 or
|
||||
card1.rank == card2.rank + 1)
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Eight Cards
|
||||
|
@ -1074,6 +1084,9 @@ class EightCards(Thirteens):
|
|||
# save vars (for undo/redo)
|
||||
return [self.draws]
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return card1.rank + card2.rank == 9
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Triple Alliance
|
||||
|
@ -1402,6 +1415,10 @@ class ElevenTriangle(Apophis):
|
|||
INVERT = True
|
||||
MAX_ROUNDS = 1
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return (card1.rank + card2.rank == 9 or
|
||||
(9 < card1.rank == card2.rank > 9))
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Cheops
|
||||
|
@ -1828,6 +1845,9 @@ class Hurricane(Pyramid):
|
|||
self.s.talon.moveMove(1, stack)
|
||||
self.leaveState(old_state)
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return card1.rank + card2.rank == 12
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Ides of March
|
||||
|
@ -1860,6 +1880,10 @@ class IdesOfMarch(Hurricane):
|
|||
RowStack_Class = IdesOfMarch_RowStack
|
||||
Reserve_Class = IdesOfMarch_Reserve
|
||||
|
||||
def shallHighlightMatch(self, stack1, card1, stack2, card2):
|
||||
return (card1.rank + card2.rank == 13 or
|
||||
card1.rank + card2.rank == 0)
|
||||
|
||||
|
||||
# register the game
|
||||
registerGame(GameInfo(38, Pyramid, "Pyramid",
|
||||
|
|
|
@ -231,6 +231,58 @@ class Kingdom(RoyalCotillion):
|
|||
self.s.talon.dealCards() # deal first card to WasteStack
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Noumea
|
||||
# ************************************************************************
|
||||
|
||||
class Noumea(RoyalCotillion):
|
||||
Foundation_Class = SS_FoundationStack
|
||||
|
||||
def createGame(self):
|
||||
# create layout
|
||||
l, s = Layout(self), self.s
|
||||
|
||||
# set window
|
||||
self.setSize(l.XM + 5*l.XS, l.YM + 6*l.YS)
|
||||
|
||||
# create stacks
|
||||
x, y, = l.XM + .5 * l.XS, l.YM
|
||||
for i in range(4):
|
||||
s.foundations.append(self.Foundation_Class(x, y, self, i))
|
||||
x += l.XS
|
||||
x, y, = l.XM, y + l.YS
|
||||
for j in range(4):
|
||||
for i in range(5):
|
||||
s.reserves.append(ReserveStack(x, y, self, max_accept=0))
|
||||
x += l.XS
|
||||
x = l.XM
|
||||
y += l.YS
|
||||
x, y = l.XM + 1.5 * l.XS, l.YM + 5 * l.YS
|
||||
s.talon = WasteTalonStack(x, y, self, max_rounds=3, num_deal=3)
|
||||
l.createText(s.talon, "sw")
|
||||
x += l.XS
|
||||
s.waste = WasteStack(x, y, self)
|
||||
l.createText(s.waste, "se")
|
||||
|
||||
# define stack-groups
|
||||
l.defaultStackGroups()
|
||||
|
||||
#
|
||||
# game overrides
|
||||
#
|
||||
|
||||
def _shuffleHook(self, cards):
|
||||
# move Aces to top of the Talon (i.e. first cards to be dealt)
|
||||
return self._shuffleHookMoveToTop(
|
||||
cards, lambda c: (c.rank == ACE, c.suit))
|
||||
|
||||
def startGame(self):
|
||||
self.s.talon.dealRow(rows=self.s.foundations, frames=0)
|
||||
self.startDealSample()
|
||||
self.s.talon.dealRow(rows=self.s.reserves)
|
||||
self.s.talon.dealCards() # deal first card to WasteStack
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Alhambra
|
||||
# * Granada
|
||||
|
@ -1624,3 +1676,5 @@ registerGame(GameInfo(943, RosamundsBower, "Rosamund's Bower",
|
|||
altnames=("Rosamund",)))
|
||||
registerGame(GameInfo(952, BigAlhambra, "Big Alhambra",
|
||||
GI.GT_3DECK_TYPE, 3, 2, GI.SL_BALANCED))
|
||||
registerGame(GameInfo(978, Noumea, "Noumea",
|
||||
GI.GT_1DECK_TYPE, 1, 2, GI.SL_MOSTLY_LUCK))
|
||||
|
|
|
@ -175,6 +175,13 @@ def raise_help_html(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_help_html():
|
||||
try:
|
||||
help_html_viewer.parent.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def destroy_help_html():
|
||||
try:
|
||||
help_html_viewer.destroy()
|
||||
|
|
|
@ -73,6 +73,10 @@ def raise_find_card_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_find_card_dialog():
|
||||
pass
|
||||
|
||||
|
||||
def destroy_find_card_dialog():
|
||||
pass
|
||||
'''
|
||||
|
|
|
@ -112,6 +112,10 @@ def raise_full_picture_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_full_picture_dialog():
|
||||
pass
|
||||
|
||||
|
||||
def destroy_full_picture_dialog():
|
||||
pass
|
||||
'''
|
||||
|
|
|
@ -50,6 +50,10 @@ def raise_solver_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_solver_dialog():
|
||||
pass
|
||||
|
||||
|
||||
def destroy_solver_dialog():
|
||||
global solver_dialog
|
||||
solver_dialog = None
|
||||
|
|
|
@ -54,5 +54,9 @@ def raise_find_card_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_find_card_dialog():
|
||||
pass
|
||||
|
||||
|
||||
def destroy_find_card_dialog():
|
||||
pass
|
||||
|
|
|
@ -50,7 +50,11 @@ def connect_game_full_picture_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def raise_find_card_dialog(game):
|
||||
def raise_full_picture_dialog(game):
|
||||
pass
|
||||
|
||||
|
||||
def unraise_full_picture_dialog():
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ def raise_solver_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_solver_dialog():
|
||||
pass
|
||||
|
||||
|
||||
def destroy_solver_dialog():
|
||||
pass
|
||||
# solver_dialog = None
|
||||
|
|
|
@ -95,3 +95,10 @@ def raise_solver_dialog(game):
|
|||
solver_dialog.top.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def unraise_solver_dialog():
|
||||
try:
|
||||
solver_dialog.top.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
@ -254,6 +254,13 @@ def raise_find_card_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_find_card_dialog():
|
||||
try:
|
||||
find_card_dialog.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def destroy_find_card_dialog():
|
||||
global find_card_dialog
|
||||
try:
|
||||
|
|
|
@ -146,6 +146,13 @@ def raise_full_picture_dialog(game):
|
|||
pass
|
||||
|
||||
|
||||
def unraise_full_picture_dialog():
|
||||
try:
|
||||
full_picture_dialog.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def destroy_full_picture_dialog():
|
||||
global full_picture_dialog
|
||||
try:
|
||||
|
|
|
@ -133,6 +133,14 @@ class MfxRoot(tkinter.Tk):
|
|||
#
|
||||
#
|
||||
|
||||
def _focusInEvent(self, *args):
|
||||
if self.app:
|
||||
self.app.raiseAll()
|
||||
|
||||
def _focusOutEvent(self, *args):
|
||||
if self.app:
|
||||
self.app.unraiseAll()
|
||||
|
||||
def update(self):
|
||||
tkinter.Tk.update(self)
|
||||
|
||||
|
|
|
@ -19,7 +19,10 @@ def main():
|
|||
def _make_test(make_exe):
|
||||
subprocess.check_call([make_exe, "test", "rules"])
|
||||
|
||||
os.chdir('../')
|
||||
if (os.path.exists("./linux-install.py")
|
||||
and not (os.path.exists("./scripts/linux-install.py"))
|
||||
and not (os.path.exists("Makefile"))):
|
||||
os.chdir('../')
|
||||
|
||||
try:
|
||||
_make_test("gmake")
|
||||
|
|
Loading…
Add table
Reference in a new issue