mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-15 02:54:09 -04:00
Compare commits
25 commits
408a8fbb08
...
bb8785e76b
Author | SHA1 | Date | |
---|---|---|---|
|
bb8785e76b | ||
|
38def5a0e7 | ||
|
18a460a1e7 | ||
|
7eb29a216f | ||
|
b518678d8d | ||
|
41c2633fcd | ||
|
3de9955879 | ||
|
db348ee91b | ||
|
fcc55dfe56 | ||
|
697f15c9df | ||
|
d9efba4456 | ||
|
14d4c0c509 | ||
|
fa85fbdadd | ||
|
e49c3a153f | ||
|
1ee67d9ca8 | ||
|
c96d25d628 | ||
|
556ceed9a6 | ||
|
2a04901a77 | ||
|
faf8341c5e | ||
|
f998b53d79 | ||
|
fee9f6e20e | ||
|
653e84b049 | ||
|
d04601ad1c | ||
|
730ecf775b | ||
|
8e4ed1e157 |
20 changed files with 476 additions and 387 deletions
|
@ -1,6 +1,14 @@
|
||||||
[[news]]
|
[[news]]
|
||||||
=== News
|
=== News
|
||||||
|
|
||||||
|
* _22 June, 2020:_ There is a new stable release
|
||||||
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.10.0/[PySolFC
|
||||||
|
v2.10.0]. New in this release:
|
||||||
|
** Fix moving cards in the Scorpion Tail game.
|
||||||
|
** Make use of https://pypi.org/project/pysol-cards/[the pysol-cards PyPI module]
|
||||||
|
** One can optionally load the Freecell Solver and the Black Hole Solver using their DLLs.
|
||||||
|
** Test Windows Version in the installer: https://github.com/shlomif/PySolFC/issues/161
|
||||||
|
** Pause when showing statistics: https://github.com/shlomif/PySolFC/pull/162
|
||||||
* _5 March, 2020:_ There is a new stable release
|
* _5 March, 2020:_ There is a new stable release
|
||||||
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.8.0/[PySolFC
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.8.0/[PySolFC
|
||||||
v2.8.0]. New in this release:
|
v2.8.0]. New in this release:
|
||||||
|
|
|
@ -15,10 +15,10 @@ pysollib_dir = '../'
|
||||||
builtins._ = lambda x: x
|
builtins._ = lambda x: x
|
||||||
builtins.n_ = lambda x: x
|
builtins.n_ = lambda x: x
|
||||||
|
|
||||||
import pysollib.games # noqa: F402,I100,I202
|
import pysollib.games # noqa: E402,F402,I100,I202
|
||||||
import pysollib.games.mahjongg # noqa: F402
|
import pysollib.games.mahjongg # noqa: E402,F402
|
||||||
import pysollib.games.special # noqa: F401,F402
|
import pysollib.games.special # noqa: E402,F401,F402
|
||||||
import pysollib.games.ultra # noqa: F401,F402
|
import pysollib.games.ultra # noqa: E402,F401,F402
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.mkdir('html')
|
os.mkdir('html')
|
||||||
|
|
|
@ -1072,7 +1072,7 @@ Please select a %(correct_type)s type cardset.
|
||||||
def _readCardsetConfig(self, dirname, filename):
|
def _readCardsetConfig(self, dirname, filename):
|
||||||
with open(filename, "r") as f:
|
with open(filename, "r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
lines = [l.strip() for l in lines]
|
lines = [line.strip() for line in lines]
|
||||||
if not lines[0].startswith("PySol"):
|
if not lines[0].startswith("PySol"):
|
||||||
return None
|
return None
|
||||||
config = CardsetConfig()
|
config = CardsetConfig()
|
||||||
|
|
|
@ -398,6 +398,7 @@ class GameStatsStruct(NewStruct):
|
||||||
# did this game already update the demo stats ?
|
# did this game already update the demo stats ?
|
||||||
demo_updated = attr.ib(default=0)
|
demo_updated = attr.ib(default=0)
|
||||||
update_time = attr.ib()
|
update_time = attr.ib()
|
||||||
|
|
||||||
@update_time.default
|
@update_time.default
|
||||||
def _foofoo(self):
|
def _foofoo(self):
|
||||||
return time.time() # for updateTime()
|
return time.time() # for updateTime()
|
||||||
|
@ -431,6 +432,7 @@ class GameGlobalStatsStruct(NewStruct):
|
||||||
# did this game already update the player stats ?
|
# did this game already update the player stats ?
|
||||||
updated = attr.ib(default=_GLOBAL_U_PLAY)
|
updated = attr.ib(default=_GLOBAL_U_PLAY)
|
||||||
start_time = attr.ib()
|
start_time = attr.ib()
|
||||||
|
|
||||||
@start_time.default
|
@start_time.default
|
||||||
def _foofoo(self):
|
def _foofoo(self):
|
||||||
return time.time() # for updateTime()
|
return time.time() # for updateTime()
|
||||||
|
@ -457,6 +459,7 @@ class GameMoves(NewStruct):
|
||||||
index = attr.ib(default=0)
|
index = attr.ib(default=0)
|
||||||
state = attr.ib(default=S_PLAY)
|
state = attr.ib(default=S_PLAY)
|
||||||
|
|
||||||
|
|
||||||
# used when loading a game
|
# used when loading a game
|
||||||
@attr.s
|
@attr.s
|
||||||
class GameLoadInfo(NewStruct):
|
class GameLoadInfo(NewStruct):
|
||||||
|
|
|
@ -142,27 +142,30 @@ class Golf(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
playcards = 5
|
playcards = 5
|
||||||
w1, w2 = 8*l.XS+l.XM, 2*l.XS
|
w1, w2 = 8*layout.XS+layout.XM, 2*layout.XS
|
||||||
if w2 + 52*l.XOFFSET > w1:
|
if w2 + 52*layout.XOFFSET > w1:
|
||||||
l.XOFFSET = int((w1 - w2) / 52)
|
layout.XOFFSET = int((w1 - w2) / 52)
|
||||||
self.setSize(w1, l.YM+3*l.YS+(playcards-1)*l.YOFFSET+l.TEXT_HEIGHT)
|
self.setSize(
|
||||||
|
w1,
|
||||||
|
layout.YM+3*layout.YS +
|
||||||
|
(playcards-1)*layout.YOFFSET+layout.TEXT_HEIGHT)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y = l.XM + l.XS // 2, l.YM
|
x, y = layout.XM + layout.XS // 2, layout.YM
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
s.rows.append(Golf_RowStack(x, y, self))
|
s.rows.append(Golf_RowStack(x, y, self))
|
||||||
x = x + l.XS
|
x = x + layout.XS
|
||||||
x, y = l.XM, self.height - l.YS
|
x, y = layout.XM, self.height - layout.YS
|
||||||
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
||||||
l.createText(s.talon, "n")
|
layout.createText(s.talon, "n")
|
||||||
x = x + l.XS
|
x = x + layout.XS
|
||||||
s.waste = self.Waste_Class(x, y, self)
|
s.waste = self.Waste_Class(x, y, self)
|
||||||
s.waste.CARD_XOFFSET = l.XOFFSET
|
s.waste.CARD_XOFFSET = layout.XOFFSET
|
||||||
l.createText(s.waste, "n")
|
layout.createText(s.waste, "n")
|
||||||
# the Waste is also our only Foundation in this game
|
# the Waste is also our only Foundation in this game
|
||||||
s.foundations.append(s.waste)
|
s.foundations.append(s.waste)
|
||||||
|
|
||||||
|
@ -251,24 +254,24 @@ class Elevator(RelaxedGolf):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
self.setSize(9*l.XS+l.XM, 4*l.YS+l.YM)
|
self.setSize(9*layout.XS+layout.XM, 4*layout.YS+layout.YM)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
x = l.XM + (8-i) * l.XS // 2
|
x = layout.XM + (8-i) * layout.XS // 2
|
||||||
y = l.YM + i * l.YS // 2
|
y = layout.YM + i * layout.YS // 2
|
||||||
for j in range(i+1):
|
for j in range(i+1):
|
||||||
s.rows.append(Elevator_RowStack(x, y, self))
|
s.rows.append(Elevator_RowStack(x, y, self))
|
||||||
x = x + l.XS
|
x = x + layout.XS
|
||||||
x, y = l.XM, l.YM
|
x, y = layout.XM, layout.YM
|
||||||
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
||||||
l.createText(s.talon, "s")
|
layout.createText(s.talon, "s")
|
||||||
x = x + l.XS
|
x = x + layout.XS
|
||||||
s.waste = self.Waste_Class(x, y, self)
|
s.waste = self.Waste_Class(x, y, self)
|
||||||
l.createText(s.waste, "s")
|
layout.createText(s.waste, "s")
|
||||||
# the Waste is also our only Foundation in this game
|
# the Waste is also our only Foundation in this game
|
||||||
s.foundations.append(s.waste)
|
s.foundations.append(s.waste)
|
||||||
|
|
||||||
|
@ -331,38 +334,38 @@ class BlackHole(Game):
|
||||||
|
|
||||||
def createGame(self, playcards=5):
|
def createGame(self, playcards=5):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
w = max(2*l.XS, l.XS+(playcards-1)*l.XOFFSET)
|
w = max(2*layout.XS, layout.XS+(playcards-1)*layout.XOFFSET)
|
||||||
self.setSize(l.XM + 5*w, l.YM + 4*l.YS)
|
self.setSize(layout.XM + 5*w, layout.YM + 4*layout.YS)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
y = l.YM
|
y = layout.YM
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
x = l.XM + i*w
|
x = layout.XM + i*w
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
y = y + l.YS
|
y = y + layout.YS
|
||||||
for j in (0, 1, 3, 4):
|
for j in (0, 1, 3, 4):
|
||||||
x = l.XM + j*w
|
x = layout.XM + j*w
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
y = y + l.YS
|
y = y + layout.YS
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
x = l.XM + i*w
|
x = layout.XM + i*w
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
for r in s.rows:
|
for r in s.rows:
|
||||||
r.CARD_XOFFSET = l.XOFFSET
|
r.CARD_XOFFSET = layout.XOFFSET
|
||||||
r.CARD_YOFFSET = 0
|
r.CARD_YOFFSET = 0
|
||||||
x, y = l.XM + 2*w, l.YM + 3*l.YS//2
|
x, y = layout.XM + 2*w, layout.YM + 3*layout.YS//2
|
||||||
s.foundations.append(BlackHole_Foundation(x, y, self, suit=ANY_SUIT,
|
s.foundations.append(BlackHole_Foundation(x, y, self, suit=ANY_SUIT,
|
||||||
dir=0, mod=13, max_move=0, max_cards=52))
|
dir=0, mod=13, max_move=0, max_cards=52))
|
||||||
l.createText(s.foundations[0], "s")
|
layout.createText(s.foundations[0], "s")
|
||||||
x, y = l.XM + 4*w, self.height - l.YS
|
x, y = layout.XM + 4*w, self.height - layout.YS
|
||||||
s.talon = InitialDealTalonStack(x, y, self)
|
s.talon = InitialDealTalonStack(x, y, self)
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
#
|
#
|
||||||
# game overrides
|
# game overrides
|
||||||
|
@ -415,33 +418,34 @@ class FourLeafClovers(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
h = l.YS + 6*l.YOFFSET
|
h = layout.YS + 6*layout.YOFFSET
|
||||||
self.setSize(l.XM + 7*l.XS, l.YM + 2*h)
|
self.setSize(layout.XM + 7*layout.XS, layout.YM + 2*h)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
y = l.YM
|
y = layout.YM
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
x = l.XM + i*l.XS
|
x = layout.XM + i*layout.XS
|
||||||
s.rows.append(
|
s.rows.append(
|
||||||
UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK))
|
UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK))
|
||||||
y = l.YM+h
|
y = layout.YM+h
|
||||||
for i in range(6):
|
for i in range(6):
|
||||||
x = l.XM + i*l.XS
|
x = layout.XM + i*layout.XS
|
||||||
s.rows.append(
|
s.rows.append(
|
||||||
UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK))
|
UD_RK_RowStack(x, y, self, mod=13, base_rank=NO_RANK))
|
||||||
stack = FourLeafClovers_Foundation(l.XM+6*l.XS, self.height-l.YS, self,
|
stack = FourLeafClovers_Foundation(
|
||||||
suit=ANY_SUIT, dir=0, mod=13,
|
layout.XM+6*layout.XS, self.height-layout.YS, self,
|
||||||
max_move=0, max_cards=52)
|
suit=ANY_SUIT, dir=0, mod=13,
|
||||||
|
max_move=0, max_cards=52)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
l.createText(stack, 'n')
|
layout.createText(stack, 'n')
|
||||||
x, y = l.XM + 7*l.XS, self.height - l.YS
|
x, y = layout.XM + 7*layout.XS, self.height - layout.YS
|
||||||
s.talon = InitialDealTalonStack(x, y, self)
|
s.talon = InitialDealTalonStack(x, y, self)
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRowsAndDealSingleRow(3)
|
self._startDealNumRowsAndDealSingleRow(3)
|
||||||
|
@ -459,36 +463,36 @@ class AllInARow(BlackHole):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
h = l.YM+l.YS+4*l.YOFFSET
|
h = layout.YM+layout.YS+4*layout.YOFFSET
|
||||||
self.setSize(l.XM+7*l.XS, 3*l.YM+2*h+l.YS)
|
self.setSize(layout.XM+7*layout.XS, 3*layout.YM+2*h+layout.YS)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y = l.XM, l.YM
|
x, y = layout.XM, layout.YM
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
x, y = l.XM, l.YM+h
|
x, y = layout.XM, layout.YM+h
|
||||||
for i in range(6):
|
for i in range(6):
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
for r in s.rows:
|
for r in s.rows:
|
||||||
r.CARD_XOFFSET, r.CARD_YOFFSET = 0, l.YOFFSET
|
r.CARD_XOFFSET, r.CARD_YOFFSET = 0, layout.YOFFSET
|
||||||
|
|
||||||
x, y = l.XM, self.height-l.YS
|
x, y = layout.XM, self.height-layout.YS
|
||||||
stack = BlackHole_Foundation(
|
stack = BlackHole_Foundation(
|
||||||
x, y, self, ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52,
|
x, y, self, ANY_SUIT, dir=0, mod=13, max_move=0, max_cards=52,
|
||||||
base_rank=ANY_RANK)
|
base_rank=ANY_RANK)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
stack.CARD_XOFFSET, stack.CARD_YOFFSET = (self.width-l.XS)//51, 0
|
stack.CARD_XOFFSET, stack.CARD_YOFFSET = (self.width-layout.XS)//51, 0
|
||||||
l.createText(stack, 'n')
|
layout.createText(stack, 'n')
|
||||||
x = self.width-l.XS
|
x = self.width-layout.XS
|
||||||
s.talon = InitialDealTalonStack(x, y, self)
|
s.talon = InitialDealTalonStack(x, y, self)
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRowsAndDealSingleRow(3)
|
self._startDealNumRowsAndDealSingleRow(3)
|
||||||
|
@ -502,25 +506,25 @@ class AllInARow(BlackHole):
|
||||||
class Robert(Game):
|
class Robert(Game):
|
||||||
|
|
||||||
def createGame(self, max_rounds=3, num_deal=1):
|
def createGame(self, max_rounds=3, num_deal=1):
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+4*l.XS, l.YM+2*l.YS)
|
self.setSize(layout.XM+4*layout.XS, layout.YM+2*layout.YS)
|
||||||
x, y = l.XM+3*l.XS//2, l.YM
|
x, y = layout.XM+3*layout.XS//2, layout.YM
|
||||||
stack = BlackHole_Foundation(x, y, self, ANY_SUIT,
|
stack = BlackHole_Foundation(x, y, self, ANY_SUIT,
|
||||||
dir=0, mod=13, max_move=0, max_cards=52)
|
dir=0, mod=13, max_move=0, max_cards=52)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
l.createText(stack, 'ne')
|
layout.createText(stack, 'ne')
|
||||||
x, y = l.XM+l.XS, l.YM+l.YS
|
x, y = layout.XM+layout.XS, layout.YM+layout.YS
|
||||||
s.talon = WasteTalonStack(x, y, self,
|
s.talon = WasteTalonStack(x, y, self,
|
||||||
max_rounds=max_rounds, num_deal=num_deal)
|
max_rounds=max_rounds, num_deal=num_deal)
|
||||||
l.createText(s.talon, 'nw')
|
layout.createText(s.talon, 'nw')
|
||||||
if max_rounds > 0:
|
if max_rounds > 0:
|
||||||
l.createRoundText(self.s.talon, 'se', dx=l.XS)
|
layout.createRoundText(self.s.talon, 'se', dx=layout.XS)
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
s.waste = WasteStack(x, y, self)
|
s.waste = WasteStack(x, y, self)
|
||||||
l.createText(s.waste, 'ne')
|
layout.createText(s.waste, 'ne')
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
|
@ -559,19 +563,21 @@ class DiamondMine_RowStack(RK_RowStack):
|
||||||
class DiamondMine(Game):
|
class DiamondMine(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+13*l.XS, l.YM+2*l.YS+15*l.YOFFSET)
|
self.setSize(
|
||||||
|
layout.XM+13*layout.XS,
|
||||||
|
layout.YM+2*layout.YS+15*layout.YOFFSET)
|
||||||
|
|
||||||
x, y = l.XM+6*l.XS, l.YM
|
x, y = layout.XM+6*layout.XS, layout.YM
|
||||||
s.foundations.append(SS_FoundationStack(x, y, self,
|
s.foundations.append(SS_FoundationStack(x, y, self,
|
||||||
base_rank=ANY_RANK, suit=DIAMOND, mod=13))
|
base_rank=ANY_RANK, suit=DIAMOND, mod=13))
|
||||||
x, y = l.XM, l.YM+l.YS
|
x, y = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(13):
|
for i in range(13):
|
||||||
s.rows.append(DiamondMine_RowStack(x, y, self))
|
s.rows.append(DiamondMine_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self)
|
s.talon = InitialDealTalonStack(layout.XM, self.height-layout.YS, self)
|
||||||
|
|
||||||
l.defaultAll()
|
layout.defaultAll()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
|
@ -600,26 +606,28 @@ class DiamondMine(Game):
|
||||||
class Dolphin(Game):
|
class Dolphin(Game):
|
||||||
|
|
||||||
def createGame(self, rows=8, reserves=4, playcards=6):
|
def createGame(self, rows=8, reserves=4, playcards=6):
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+rows*l.XS, l.YM+3*l.YS+playcards*l.YOFFSET)
|
self.setSize(
|
||||||
|
layout.XM+rows*layout.XS,
|
||||||
|
layout.YM+3*layout.YS+playcards*layout.YOFFSET)
|
||||||
|
|
||||||
dx = (self.width-l.XM-(reserves+1)*l.XS)//3
|
dx = (self.width-layout.XM-(reserves+1)*layout.XS)//3
|
||||||
x, y = l.XM+dx, l.YM
|
x, y = layout.XM+dx, layout.YM
|
||||||
for i in range(reserves):
|
for i in range(reserves):
|
||||||
s.reserves.append(ReserveStack(x, y, self))
|
s.reserves.append(ReserveStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
x += dx
|
x += dx
|
||||||
max_cards = 52*self.gameinfo.decks
|
max_cards = 52*self.gameinfo.decks
|
||||||
s.foundations.append(RK_FoundationStack(x, y, self,
|
s.foundations.append(RK_FoundationStack(x, y, self,
|
||||||
base_rank=ANY_RANK, mod=13, max_cards=max_cards))
|
base_rank=ANY_RANK, mod=13, max_cards=max_cards))
|
||||||
l.createText(s.foundations[0], 'ne')
|
layout.createText(s.foundations[0], 'ne')
|
||||||
x, y = l.XM, l.YM+l.YS
|
x, y = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
s.rows.append(BasicRowStack(x, y, self))
|
s.rows.append(BasicRowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self)
|
s.talon = InitialDealTalonStack(layout.XM, self.height-layout.YS, self)
|
||||||
|
|
||||||
l.defaultAll()
|
layout.defaultAll()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRows(5)
|
self._startDealNumRows(5)
|
||||||
|
@ -663,26 +671,27 @@ class Waterfall(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
rows = 8
|
rows = 8
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+rows*l.XS, l.YM+2*l.YS+20*l.YOFFSET)
|
self.setSize(
|
||||||
|
layout.XM+rows*layout.XS, layout.YM+2*layout.YS+20*layout.YOFFSET)
|
||||||
|
|
||||||
x, y = l.XM, l.YM
|
x, y = layout.XM, layout.YM
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
s.rows.append(RK_RowStack(x, y, self))
|
s.rows.append(RK_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
x, y = l.XM+(rows-1)*l.XS//2, self.height-l.YS
|
x, y = layout.XM+(rows-1)*layout.XS//2, self.height-layout.YS
|
||||||
s.foundations.append(Waterfall_Foundation(x, y, self, suit=ANY_SUIT,
|
s.foundations.append(Waterfall_Foundation(x, y, self, suit=ANY_SUIT,
|
||||||
max_cards=104))
|
max_cards=104))
|
||||||
stack = s.foundations[0]
|
stack = s.foundations[0]
|
||||||
tx, ty, ta, tf = l.getTextAttr(stack, 'se')
|
tx, ty, ta, tf = layout.getTextAttr(stack, 'se')
|
||||||
font = self.app.getFont('canvas_default')
|
font = self.app.getFont('canvas_default')
|
||||||
stack.texts.misc = MfxCanvasText(self.canvas, tx, ty,
|
stack.texts.misc = MfxCanvasText(self.canvas, tx, ty,
|
||||||
anchor=ta, font=font)
|
anchor=ta, font=font)
|
||||||
x, y = self.width-l.XS, self.height-l.YS
|
x, y = self.width-layout.XS, self.height-layout.YS
|
||||||
s.talon = DealRowTalonStack(x, y, self)
|
s.talon = DealRowTalonStack(x, y, self)
|
||||||
l.createText(s.talon, 'sw')
|
layout.createText(s.talon, 'sw')
|
||||||
|
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRowsAndDealSingleRow(3)
|
self._startDealNumRowsAndDealSingleRow(3)
|
||||||
|
@ -721,30 +730,30 @@ class Vague(Game):
|
||||||
base_rank=ANY_RANK, mod=13)]
|
base_rank=ANY_RANK, mod=13)]
|
||||||
|
|
||||||
def createGame(self, rows=3, columns=6):
|
def createGame(self, rows=3, columns=6):
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
decks = self.gameinfo.decks
|
decks = self.gameinfo.decks
|
||||||
maxrows = max(columns, 2+decks*4)
|
maxrows = max(columns, 2+decks*4)
|
||||||
self.setSize(l.XM+maxrows*l.XS, l.YM+(rows+1)*l.YS)
|
self.setSize(layout.XM+maxrows*layout.XS, layout.YM+(rows+1)*layout.YS)
|
||||||
|
|
||||||
x, y = l.XM, l.YM
|
x, y = layout.XM, layout.YM
|
||||||
s.talon = TalonStack(x, y, self)
|
s.talon = TalonStack(x, y, self)
|
||||||
l.createText(s.talon, 'ne')
|
layout.createText(s.talon, 'ne')
|
||||||
|
|
||||||
x, y = l.XM+2*l.XS, l.YM
|
x, y = layout.XM+2*layout.XS, layout.YM
|
||||||
for found in self.Foundation_Classes:
|
for found in self.Foundation_Classes:
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
s.foundations.append(found(x, y, self, suit=i))
|
s.foundations.append(found(x, y, self, suit=i))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
|
|
||||||
y = l.YM+l.YS
|
y = layout.YM+layout.YS
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
x = l.XM + (maxrows-columns)*l.XS//2
|
x = layout.XM + (maxrows-columns)*layout.XS//2
|
||||||
for j in range(columns):
|
for j in range(columns):
|
||||||
s.rows.append(Vague_RowStack(x, y, self))
|
s.rows.append(Vague_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
y += l.YS
|
y += layout.YS
|
||||||
|
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
|
@ -804,49 +813,51 @@ class DevilsSolitaire_WasteStack(WasteStack):
|
||||||
class DevilsSolitaire(Game):
|
class DevilsSolitaire(Game):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+9*l.XS, l.YM+3*l.YS+7*l.YOFFSET+2*l.TEXT_HEIGHT)
|
self.setSize(
|
||||||
|
layout.XM+9*layout.XS,
|
||||||
|
layout.YM+3*layout.YS+7*layout.YOFFSET+2*layout.TEXT_HEIGHT)
|
||||||
|
|
||||||
x, y = l.XM+4*l.XS, l.YM
|
x, y = layout.XM+4*layout.XS, layout.YM
|
||||||
stack = DevilsSolitaire_Foundation(
|
stack = DevilsSolitaire_Foundation(
|
||||||
x, y, self, suit=ANY_SUIT, base_rank=ANY_RANK, mod=13)
|
x, y, self, suit=ANY_SUIT, base_rank=ANY_RANK, mod=13)
|
||||||
tx, ty, ta, tf = l.getTextAttr(stack, 'nw')
|
tx, ty, ta, tf = layout.getTextAttr(stack, 'nw')
|
||||||
font = self.app.getFont('canvas_default')
|
font = self.app.getFont('canvas_default')
|
||||||
stack.texts.misc = MfxCanvasText(self.canvas, tx, ty,
|
stack.texts.misc = MfxCanvasText(self.canvas, tx, ty,
|
||||||
anchor=ta, font=font)
|
anchor=ta, font=font)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
|
|
||||||
x, y = self.width-l.XS, l.YM
|
x, y = self.width-layout.XS, layout.YM
|
||||||
stack = AbstractFoundationStack(
|
stack = AbstractFoundationStack(
|
||||||
x, y, self,
|
x, y, self,
|
||||||
suit=ANY_SUIT, max_move=0, max_cards=104,
|
suit=ANY_SUIT, max_move=0, max_cards=104,
|
||||||
max_accept=0, base_rank=ANY_RANK)
|
max_accept=0, base_rank=ANY_RANK)
|
||||||
l.createText(stack, 'nw')
|
layout.createText(stack, 'nw')
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
|
|
||||||
x, y = l.XM, l.YM+l.YS
|
x, y = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
s.rows.append(Vague_RowStack(x, y, self))
|
s.rows.append(Vague_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
s.rows.append(Vague_RowStack(x, y, self))
|
s.rows.append(Vague_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
|
|
||||||
x, y = l.XM+4*l.XS, l.YM+l.YS
|
x, y = layout.XM+4*layout.XS, layout.YM+layout.YS
|
||||||
stack = OpenStack(x, y, self)
|
stack = OpenStack(x, y, self)
|
||||||
stack.CARD_YOFFSET = l.YOFFSET
|
stack.CARD_YOFFSET = layout.YOFFSET
|
||||||
s.reserves.append(stack)
|
s.reserves.append(stack)
|
||||||
|
|
||||||
x, y = l.XM+4.5*l.XS, self.height-l.YS
|
x, y = layout.XM+4.5*layout.XS, self.height-layout.YS
|
||||||
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
|
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
|
||||||
l.createText(s.talon, 'n')
|
layout.createText(s.talon, 'n')
|
||||||
l.createRoundText(s.talon, 'nnn')
|
layout.createRoundText(s.talon, 'nnn')
|
||||||
x -= l.XS
|
x -= layout.XS
|
||||||
s.waste = DevilsSolitaire_WasteStack(x, y, self)
|
s.waste = DevilsSolitaire_WasteStack(x, y, self)
|
||||||
l.createText(s.waste, 'n')
|
layout.createText(s.waste, 'n')
|
||||||
|
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
|
@ -903,15 +914,15 @@ class ThreeFirTrees_RowStack(Golf_RowStack):
|
||||||
|
|
||||||
|
|
||||||
class FirTree_GameMethods:
|
class FirTree_GameMethods:
|
||||||
def _createFirTree(self, l, x0, y0):
|
def _createFirTree(self, layout, x0, y0):
|
||||||
rows = []
|
rows = []
|
||||||
# create stacks
|
# create stacks
|
||||||
for i in range(11):
|
for i in range(11):
|
||||||
x = x0 + ((i+1) % 2) * l.XS // 2
|
x = x0 + ((i+1) % 2) * layout.XS // 2
|
||||||
y = y0 + i * l.YS // 4
|
y = y0 + i * layout.YS // 4
|
||||||
for j in range((i % 2) + 1):
|
for j in range((i % 2) + 1):
|
||||||
rows.append(ThreeFirTrees_RowStack(x, y, self))
|
rows.append(ThreeFirTrees_RowStack(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
# compute blocking
|
# compute blocking
|
||||||
n = 0
|
n = 0
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
@ -931,21 +942,23 @@ class ThreeFirTrees(Golf, FirTree_GameMethods):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+max(7*l.XS, 2*l.XS+26*l.XOFFSET), l.YM+5*l.YS)
|
self.setSize(
|
||||||
|
layout.XM+max(7*layout.XS, 2*layout.XS+26*layout.XOFFSET),
|
||||||
|
layout.YM+5*layout.YS)
|
||||||
|
|
||||||
x0, y0 = (self.width-7*l.XS)//2, l.YM
|
x0, y0 = (self.width-7*layout.XS)//2, layout.YM
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
s.rows += self._createFirTree(l, x0, y0)
|
s.rows += self._createFirTree(layout, x0, y0)
|
||||||
x0 += 2.5*l.XS
|
x0 += 2.5*layout.XS
|
||||||
|
|
||||||
x, y = l.XM, self.height - l.YS
|
x, y = layout.XM, self.height - layout.YS
|
||||||
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
s.talon = Golf_Talon(x, y, self, max_rounds=1)
|
||||||
l.createText(s.talon, 'n')
|
layout.createText(s.talon, 'n')
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
s.waste = self.Waste_Class(x, y, self)
|
s.waste = self.Waste_Class(x, y, self)
|
||||||
s.waste.CARD_XOFFSET = l.XOFFSET//4
|
s.waste.CARD_XOFFSET = layout.XOFFSET//4
|
||||||
l.createText(s.waste, 'n')
|
layout.createText(s.waste, 'n')
|
||||||
# the Waste is also our only Foundation in this game
|
# the Waste is also our only Foundation in this game
|
||||||
s.foundations.append(s.waste)
|
s.foundations.append(s.waste)
|
||||||
|
|
||||||
|
@ -975,34 +988,35 @@ class NapoleonTakesMoscow(Game, FirTree_GameMethods):
|
||||||
|
|
||||||
def createGame(self):
|
def createGame(self):
|
||||||
|
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
self.setSize(l.XM+10*l.XS, l.YM+3*l.YS+15*l.YOFFSET)
|
self.setSize(
|
||||||
|
layout.XM+10*layout.XS, layout.YM+3*layout.YS+15*layout.YOFFSET)
|
||||||
|
|
||||||
x, y = l.XM+l.XS, l.YM
|
x, y = layout.XM+layout.XS, layout.YM
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
s.foundations.append(SS_FoundationStack(x, y, self, suit=i//2))
|
s.foundations.append(SS_FoundationStack(x, y, self, suit=i//2))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
|
|
||||||
x, y = l.XM, l.YM+l.YS
|
x, y = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
for j in range(4):
|
for j in range(4):
|
||||||
s.rows.append(self.RowStack_Class(x, y, self))
|
s.rows.append(self.RowStack_Class(x, y, self))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
x += 2*l.XS
|
x += 2*layout.XS
|
||||||
|
|
||||||
x, y = l.XM+4*l.XS, l.YM+l.YS
|
x, y = layout.XM+4*layout.XS, layout.YM+layout.YS
|
||||||
s.reserves += self._createFirTree(l, x, y)
|
s.reserves += self._createFirTree(layout, x, y)
|
||||||
|
|
||||||
x, y = l.XM, self.height-l.YS
|
x, y = layout.XM, self.height-layout.YS
|
||||||
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
|
s.talon = WasteTalonStack(x, y, self, max_rounds=3)
|
||||||
l.createText(s.talon, 'n')
|
layout.createText(s.talon, 'n')
|
||||||
l.createRoundText(s.talon, 'nnn')
|
layout.createRoundText(s.talon, 'nnn')
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
s.waste = WasteStack(x, y, self)
|
s.waste = WasteStack(x, y, self)
|
||||||
l.createText(s.waste, 'n')
|
layout.createText(s.waste, 'n')
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self.s.talon.dealRow(rows=self.s.reserves, frames=0)
|
self.s.talon.dealRow(rows=self.s.reserves, frames=0)
|
||||||
|
@ -1031,29 +1045,31 @@ class Flake(Game):
|
||||||
|
|
||||||
def createGame(self, rows=6, playcards=18):
|
def createGame(self, rows=6, playcards=18):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
self.setSize(l.XM + rows*l.XS, l.YM + 2*l.YS + playcards*l.XOFFSET)
|
self.setSize(
|
||||||
|
layout.XM + rows*layout.XS,
|
||||||
|
layout.YM + 2*layout.YS + playcards*layout.XOFFSET)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y, = l.XM, l.YM+l.YS
|
x, y, = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
s.rows.append(UD_RK_RowStack(x, y, self, mod=13))
|
s.rows.append(UD_RK_RowStack(x, y, self, mod=13))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
|
|
||||||
x, y = l.XM + (rows-1)*l.XS//2, l.YM
|
x, y = layout.XM + (rows-1)*layout.XS//2, layout.YM
|
||||||
stack = BlackHole_Foundation(x, y, self, max_move=0, suit=ANY_SUIT,
|
stack = BlackHole_Foundation(x, y, self, max_move=0, suit=ANY_SUIT,
|
||||||
base_rank=ANY_RANK, dir=0, mod=13,
|
base_rank=ANY_RANK, dir=0, mod=13,
|
||||||
max_cards=52*self.gameinfo.decks)
|
max_cards=52*self.gameinfo.decks)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
l.createText(stack, 'ne')
|
layout.createText(stack, 'ne')
|
||||||
|
|
||||||
x, y = l.XM, self.height-l.YS
|
x, y = layout.XM, self.height-layout.YS
|
||||||
s.talon = InitialDealTalonStack(x, y, self)
|
s.talon = InitialDealTalonStack(x, y, self)
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRows(7)
|
self._startDealNumRows(7)
|
||||||
|
@ -1079,30 +1095,32 @@ class Beacon(Game):
|
||||||
|
|
||||||
def createGame(self, rows=8):
|
def createGame(self, rows=8):
|
||||||
# create layout
|
# create layout
|
||||||
l, s = Layout(self), self.s
|
layout, s = Layout(self), self.s
|
||||||
|
|
||||||
# set window
|
# set window
|
||||||
playcards = 12
|
playcards = 12
|
||||||
self.setSize(l.XM+rows*l.XS, l.YM+3*l.YS+playcards*l.YOFFSET)
|
self.setSize(
|
||||||
|
layout.XM+rows*layout.XS,
|
||||||
|
layout.YM+3*layout.YS+playcards*layout.YOFFSET)
|
||||||
|
|
||||||
# create stacks
|
# create stacks
|
||||||
x, y = l.XM + (rows-1)*l.XS//2, l.YM
|
x, y = layout.XM + (rows-1)*layout.XS//2, layout.YM
|
||||||
stack = RK_FoundationStack(x, y, self, base_rank=ANY_RANK,
|
stack = RK_FoundationStack(x, y, self, base_rank=ANY_RANK,
|
||||||
max_cards=52, mod=13)
|
max_cards=52, mod=13)
|
||||||
s.foundations.append(stack)
|
s.foundations.append(stack)
|
||||||
l.createText(stack, 'ne')
|
layout.createText(stack, 'ne')
|
||||||
|
|
||||||
x, y = l.XM, l.YM+l.YS
|
x, y = layout.XM, layout.YM+layout.YS
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
s.rows.append(RK_RowStack(x, y, self, base_rank=NO_RANK, mod=13))
|
s.rows.append(RK_RowStack(x, y, self, base_rank=NO_RANK, mod=13))
|
||||||
x += l.XS
|
x += layout.XS
|
||||||
|
|
||||||
x, y = l.XM, self.height-l.YS
|
x, y = layout.XM, self.height-layout.YS
|
||||||
s.talon = TalonStack(x, y, self)
|
s.talon = TalonStack(x, y, self)
|
||||||
l.createText(s.talon, 'se')
|
layout.createText(s.talon, 'se')
|
||||||
|
|
||||||
# define stack-groups
|
# define stack-groups
|
||||||
l.defaultStackGroups()
|
layout.defaultStackGroups()
|
||||||
|
|
||||||
def startGame(self):
|
def startGame(self):
|
||||||
self._startDealNumRowsAndDealSingleRow(3)
|
self._startDealNumRowsAndDealSingleRow(3)
|
||||||
|
|
|
@ -351,6 +351,7 @@ class Scorpion(RelaxedSpider):
|
||||||
|
|
||||||
class ScorpionTail_RowStack(Yukon_AC_RowStack, Spider_RowStack):
|
class ScorpionTail_RowStack(Yukon_AC_RowStack, Spider_RowStack):
|
||||||
canDropCards = Spider_RowStack.canDropCards
|
canDropCards = Spider_RowStack.canDropCards
|
||||||
|
canMoveCards = OpenStack.canMoveCards
|
||||||
|
|
||||||
|
|
||||||
class ScorpionTail(Scorpion):
|
class ScorpionTail(Scorpion):
|
||||||
|
|
|
@ -313,7 +313,7 @@ class IdleAces(Game):
|
||||||
l.createText(s.waste, 's')
|
l.createText(s.waste, 's')
|
||||||
x0, y0 = l.XM+2*l.XS, l.YM
|
x0, y0 = l.XM+2*l.XS, l.YM
|
||||||
k = 0
|
k = 0
|
||||||
for i, j in((2, 0), (0, 1.5), (4, 1.5), (2, 3)):
|
for i, j in ((2, 0), (0, 1.5), (4, 1.5), (2, 3)):
|
||||||
x, y = x0+i*l.XS, y0+j*l.YS
|
x, y = x0+i*l.XS, y0+j*l.YS
|
||||||
s.foundations.append(
|
s.foundations.append(
|
||||||
RK_FoundationStack(
|
RK_FoundationStack(
|
||||||
|
@ -322,7 +322,7 @@ class IdleAces(Game):
|
||||||
base_rank=KING, dir=-1, max_move=0))
|
base_rank=KING, dir=-1, max_move=0))
|
||||||
k += 1
|
k += 1
|
||||||
k = 0
|
k = 0
|
||||||
for i, j in((2, 1), (1, 1.5), (3, 1.5), (2, 2)):
|
for i, j in ((2, 1), (1, 1.5), (3, 1.5), (2, 2)):
|
||||||
x, y = x0+i*l.XS, y0+j*l.YS
|
x, y = x0+i*l.XS, y0+j*l.YS
|
||||||
s.foundations.append(
|
s.foundations.append(
|
||||||
RK_FoundationStack(
|
RK_FoundationStack(
|
||||||
|
@ -331,7 +331,7 @@ class IdleAces(Game):
|
||||||
base_rank=1, max_move=0, max_cards=12))
|
base_rank=1, max_move=0, max_cards=12))
|
||||||
k += 1
|
k += 1
|
||||||
k = 0
|
k = 0
|
||||||
for i, j in((1, 0.2), (3, 0.2), (1, 2.8), (3, 2.8)):
|
for i, j in ((1, 0.2), (3, 0.2), (1, 2.8), (3, 2.8)):
|
||||||
x, y = x0+i*l.XS, y0+j*l.YS
|
x, y = x0+i*l.XS, y0+j*l.YS
|
||||||
s.foundations.append(IdleAces_AceFoundation(x, y, self,
|
s.foundations.append(IdleAces_AceFoundation(x, y, self,
|
||||||
suit=k, max_cards=1, max_move=0))
|
suit=k, max_cards=1, max_move=0))
|
||||||
|
|
|
@ -101,7 +101,7 @@ class RussianSolitaire(Yukon):
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|
||||||
class Moosehide_RowStack(Yukon_AC_RowStack):
|
class Moosehide_RowStack(Yukon_AC_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return (c1.suit != c2.suit and c1.rank == c2.rank+1)
|
return (c1.suit != c2.suit and c1.rank == c2.rank+1)
|
||||||
|
|
||||||
def getHelp(self):
|
def getHelp(self):
|
||||||
|
@ -172,7 +172,7 @@ class Grandfather(RussianSolitaire):
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|
||||||
class Alaska_RowStack(Yukon_SS_RowStack):
|
class Alaska_RowStack(Yukon_SS_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return (c1.suit == c2.suit and
|
return (c1.suit == c2.suit and
|
||||||
((c1.rank + self.cap.dir) % self.cap.mod == c2.rank or
|
((c1.rank + self.cap.dir) % self.cap.mod == c2.rank or
|
||||||
(c2.rank + self.cap.dir) % self.cap.mod == c1.rank))
|
(c2.rank + self.cap.dir) % self.cap.mod == c1.rank))
|
||||||
|
@ -191,7 +191,7 @@ class Alaska(RussianSolitaire):
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|
||||||
class Roslin_RowStack(Yukon_AC_RowStack):
|
class Roslin_RowStack(Yukon_AC_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return (c1.color != c2.color and
|
return (c1.color != c2.color and
|
||||||
((c1.rank + self.cap.dir) % self.cap.mod == c2.rank or
|
((c1.rank + self.cap.dir) % self.cap.mod == c2.rank or
|
||||||
(c2.rank + self.cap.dir) % self.cap.mod == c1.rank))
|
(c2.rank + self.cap.dir) % self.cap.mod == c1.rank))
|
||||||
|
@ -289,7 +289,7 @@ class Abacus_Foundation(SS_FoundationStack):
|
||||||
|
|
||||||
|
|
||||||
class Abacus_RowStack(Yukon_SS_RowStack):
|
class Abacus_RowStack(Yukon_SS_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
dir, mod = -(c1.suit + 1), 13
|
dir, mod = -(c1.suit + 1), 13
|
||||||
return c1.suit == c2.suit and (c1.rank + dir) % mod == c2.rank
|
return c1.suit == c2.suit and (c1.rank + dir) % mod == c2.rank
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ class DoubleRussianSpider(RussianSpider, DoubleRussianSolitaire):
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
|
||||||
class Brisbane_RowStack(Yukon_AC_RowStack):
|
class Brisbane_RowStack(Yukon_AC_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return (c1.rank + self.cap.dir) % self.cap.mod == c2.rank
|
return (c1.rank + self.cap.dir) % self.cap.mod == c2.rank
|
||||||
|
|
||||||
def getHelp(self):
|
def getHelp(self):
|
||||||
|
|
380
pysollib/hint.py
380
pysollib/hint.py
|
@ -22,14 +22,12 @@
|
||||||
# ---------------------------------------------------------------------------##
|
# ---------------------------------------------------------------------------##
|
||||||
|
|
||||||
|
|
||||||
# imports
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
# PySol imports
|
|
||||||
from pysollib.mfxutil import destruct
|
from pysollib.mfxutil import destruct
|
||||||
from pysollib.pysolrandom import constructRandom
|
from pysollib.pysolrandom import constructRandom
|
||||||
from pysollib.settings import DEBUG, FCS_COMMAND
|
from pysollib.settings import DEBUG, FCS_COMMAND
|
||||||
|
@ -704,7 +702,6 @@ class Yukon_Hint(YukonType_Hint):
|
||||||
return score + bonus, color
|
return score + bonus, color
|
||||||
|
|
||||||
|
|
||||||
# FIXME
|
|
||||||
class FreeCellType_Hint(CautiousDefaultHint):
|
class FreeCellType_Hint(CautiousDefaultHint):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -729,10 +726,6 @@ class PySolHintLayoutImportError(Exception):
|
||||||
return self.msg + ":\n\n" + ', '.join(self.cards)
|
return self.msg + ":\n\n" + ', '.join(self.cards)
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# * FreeCell-Solver
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
class Base_Solver_Hint:
|
class Base_Solver_Hint:
|
||||||
def __init__(self, game, dialog, **game_type):
|
def __init__(self, game, dialog, **game_type):
|
||||||
self.game = game
|
self.game = game
|
||||||
|
@ -752,8 +745,9 @@ class Base_Solver_Hint:
|
||||||
self.base_rank = game_type['base_rank']
|
self.base_rank = game_type['base_rank']
|
||||||
else:
|
else:
|
||||||
self.base_rank = game.s.foundations[0].cap.base_rank
|
self.base_rank = game.s.foundations[0].cap.base_rank
|
||||||
# print 'game_type:', game_type
|
|
||||||
# print 'base_rank:', self.base_rank
|
def _setText(self, **kw):
|
||||||
|
return self.dialog.setText(**kw)
|
||||||
|
|
||||||
def config(self, **kw):
|
def config(self, **kw):
|
||||||
self.options.update(kw)
|
self.options.update(kw)
|
||||||
|
@ -761,18 +755,18 @@ class Base_Solver_Hint:
|
||||||
def _card2str_format(self, fmt, rank, suit):
|
def _card2str_format(self, fmt, rank, suit):
|
||||||
# row and reserves
|
# row and reserves
|
||||||
rank = (rank-self.base_rank) % 13
|
rank = (rank-self.base_rank) % 13
|
||||||
return fmt % {'R': "A23456789TJQK"[rank], 'S': "CSHD"[suit]}
|
return fmt.format(R="A23456789TJQK"[rank], S="CSHD"[suit])
|
||||||
|
|
||||||
def card2str1_(self, rank, suit):
|
def card2str1_(self, rank, suit):
|
||||||
# row and reserves
|
# row and reserves
|
||||||
return self._card2str_format('%(R)s%(S)s', rank, suit)
|
return self._card2str_format('{R}{S}', rank, suit)
|
||||||
|
|
||||||
def card2str1(self, card):
|
def card2str1(self, card):
|
||||||
return self.card2str1_(card.rank, card.suit)
|
return self.card2str1_(card.rank, card.suit)
|
||||||
|
|
||||||
def card2str2(self, card):
|
def card2str2(self, card):
|
||||||
# foundations
|
# foundations
|
||||||
return self._card2str_format('%(S)s-%(R)s', card.rank, card.suit)
|
return self._card2str_format('{S}-{R}', card.rank, card.suit)
|
||||||
|
|
||||||
# hard solvable: Freecell #47038300998351211829 (65539 iters)
|
# hard solvable: Freecell #47038300998351211829 (65539 iters)
|
||||||
|
|
||||||
|
@ -780,7 +774,6 @@ class Base_Solver_Hint:
|
||||||
if taken_hint and taken_hint[6]:
|
if taken_hint and taken_hint[6]:
|
||||||
return [taken_hint[6]]
|
return [taken_hint[6]]
|
||||||
h = self.hints[self.hints_index]
|
h = self.hints[self.hints_index]
|
||||||
# print 'getHints', taken_hint, h
|
|
||||||
if h is None:
|
if h is None:
|
||||||
return None
|
return None
|
||||||
ncards, src, dest = h
|
ncards, src, dest = h
|
||||||
|
@ -793,10 +786,7 @@ class Base_Solver_Hint:
|
||||||
if src is self.game.s.talon:
|
if src is self.game.s.talon:
|
||||||
if not src.cards[-1].face_up:
|
if not src.cards[-1].face_up:
|
||||||
self.game.flipMove(src)
|
self.game.flipMove(src)
|
||||||
# src.prepareStack()
|
|
||||||
# src.dealCards()
|
|
||||||
dest = self.game.s.foundations[0]
|
dest = self.game.s.foundations[0]
|
||||||
# skip = True
|
|
||||||
else:
|
else:
|
||||||
cards = src.cards[-ncards:]
|
cards = src.cards[-ncards:]
|
||||||
for f in self.game.s.foundations:
|
for f in self.game.s.foundations:
|
||||||
|
@ -808,7 +798,6 @@ class Base_Solver_Hint:
|
||||||
if skip:
|
if skip:
|
||||||
return []
|
return []
|
||||||
hint = (999999, 0, ncards, src, dest, None, thint)
|
hint = (999999, 0, ncards, src, dest, None, thint)
|
||||||
# print hint
|
|
||||||
return [hint]
|
return [hint]
|
||||||
|
|
||||||
def colonPrefixMatch(self, prefix, s):
|
def colonPrefixMatch(self, prefix, s):
|
||||||
|
@ -838,6 +827,25 @@ class Base_Solver_Hint:
|
||||||
return BytesIO(pout), BytesIO(perr)
|
return BytesIO(pout), BytesIO(perr)
|
||||||
|
|
||||||
|
|
||||||
|
use_fc_solve_lib = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import freecell_solver
|
||||||
|
fc_solve_lib_obj = freecell_solver.FreecellSolver()
|
||||||
|
use_fc_solve_lib = True
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
use_bh_solve_lib = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import black_hole_solver
|
||||||
|
bh_solve_lib_obj = black_hole_solver.BlackHoleSolver()
|
||||||
|
use_bh_solve_lib = True
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FreeCellSolver_Hint(Base_Solver_Hint):
|
class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
def _determineIfSolverState(self, line):
|
def _determineIfSolverState(self, line):
|
||||||
if re.search('^(?:Iterations count exceeded)', line):
|
if re.search('^(?:Iterations count exceeded)', line):
|
||||||
|
@ -854,8 +862,8 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
return ('preset' in game_type and
|
return ('preset' in game_type and
|
||||||
game_type['preset'] == 'simple_simon')
|
game_type['preset'] == 'simple_simon')
|
||||||
|
|
||||||
def _addBoardLine(self, l):
|
def _addBoardLine(self, line):
|
||||||
self.board += l + '\n'
|
self.board += line + '\n'
|
||||||
return
|
return
|
||||||
|
|
||||||
def _addPrefixLine(self, prefix, b):
|
def _addPrefixLine(self, prefix, b):
|
||||||
|
@ -975,8 +983,6 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
game = self.game
|
game = self.game
|
||||||
self.board = ''
|
self.board = ''
|
||||||
is_simple_simon = self._isSimpleSimon()
|
is_simple_simon = self._isSimpleSimon()
|
||||||
#
|
|
||||||
#
|
|
||||||
b = ''
|
b = ''
|
||||||
for s in game.s.foundations:
|
for s in game.s.foundations:
|
||||||
if s.cards:
|
if s.cards:
|
||||||
|
@ -1017,32 +1023,30 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
progress = self.options['progress']
|
progress = self.options['progress']
|
||||||
|
|
||||||
board = self.calcBoardString()
|
board = self.calcBoardString()
|
||||||
#
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print('--------------------\n', board, '--------------------')
|
print('--------------------\n', board, '--------------------')
|
||||||
#
|
|
||||||
args = []
|
args = []
|
||||||
# args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
if use_fc_solve_lib:
|
||||||
args += ['-m', '-p', '-opt', '-sel']
|
args += ['--reset', '-opt', ]
|
||||||
if FCS_VERSION >= (4, 20, 0):
|
else:
|
||||||
args += ['-hoi']
|
args += ['-m', '-p', '-opt', '-sel']
|
||||||
if progress:
|
if FCS_VERSION >= (4, 20, 0):
|
||||||
|
args += ['-hoi']
|
||||||
|
if (not use_fc_solve_lib) and progress:
|
||||||
args += ['--iter-output']
|
args += ['--iter-output']
|
||||||
fcs_iter_output_step = None
|
fcs_iter_output_step = None
|
||||||
if FCS_VERSION >= (4, 20, 0):
|
if FCS_VERSION >= (4, 20, 0):
|
||||||
# fcs_iter_output_step = 10000
|
|
||||||
fcs_iter_output_step = self.options['iters_step']
|
fcs_iter_output_step = self.options['iters_step']
|
||||||
args += ['--iter-output-step', str(fcs_iter_output_step)]
|
args += ['--iter-output-step', str(fcs_iter_output_step)]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
args += ['-s']
|
args += ['-s']
|
||||||
if self.options['preset'] and self.options['preset'] != 'none':
|
if self.options['preset'] and self.options['preset'] != 'none':
|
||||||
args += ['--load-config', self.options['preset']]
|
args += ['--load-config', self.options['preset']]
|
||||||
args += ['--max-iters', self.options['max_iters'],
|
args += ['--max-iters', str(self.options['max_iters']),
|
||||||
'--decks-num', game.gameinfo.decks,
|
'--decks-num', str(game.gameinfo.decks),
|
||||||
'--stacks-num', len(game.s.rows),
|
'--stacks-num', str(len(game.s.rows)),
|
||||||
'--freecells-num', len(game.s.reserves),
|
'--freecells-num', str(len(game.s.reserves)),
|
||||||
]
|
]
|
||||||
#
|
|
||||||
if 'preset' in game_type:
|
if 'preset' in game_type:
|
||||||
args += ['--preset', game_type['preset']]
|
args += ['--preset', game_type['preset']]
|
||||||
if 'sbb' in game_type:
|
if 'sbb' in game_type:
|
||||||
|
@ -1052,10 +1056,13 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
if 'esf' in game_type:
|
if 'esf' in game_type:
|
||||||
args += ['--empty-stacks-filled-by', game_type['esf']]
|
args += ['--empty-stacks-filled-by', game_type['esf']]
|
||||||
|
|
||||||
command = FCS_COMMAND+' '+' '.join([str(i) for i in args])
|
if use_fc_solve_lib:
|
||||||
pout, perr = self.run_solver(command, board)
|
fc_solve_lib_obj.input_cmd_line(args)
|
||||||
|
status = fc_solve_lib_obj.solve_board(board)
|
||||||
|
else:
|
||||||
|
command = FCS_COMMAND+' '+' '.join(args)
|
||||||
|
pout, perr = self.run_solver(command, board)
|
||||||
self.solver_state = 'unknown'
|
self.solver_state = 'unknown'
|
||||||
#
|
|
||||||
stack_types = {
|
stack_types = {
|
||||||
'the': game.s.foundations,
|
'the': game.s.foundations,
|
||||||
'stack': game.s.rows,
|
'stack': game.s.rows,
|
||||||
|
@ -1063,8 +1070,7 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
}
|
}
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
if progress:
|
if not(use_fc_solve_lib) and progress:
|
||||||
# iteration output
|
|
||||||
iter_ = 0
|
iter_ = 0
|
||||||
depth = 0
|
depth = 0
|
||||||
states = 0
|
states = 0
|
||||||
|
@ -1081,97 +1087,113 @@ class FreeCellSolver_Hint(Base_Solver_Hint):
|
||||||
elif self.colonPrefixMatch('Stored-States', s):
|
elif self.colonPrefixMatch('Stored-States', s):
|
||||||
states = self._v
|
states = self._v
|
||||||
if iter_ % 100 == 0 or fcs_iter_output_step:
|
if iter_ % 100 == 0 or fcs_iter_output_step:
|
||||||
self.dialog.setText(iter=iter_, depth=depth,
|
self._setText(iter=iter_, depth=depth, states=states)
|
||||||
states=states)
|
|
||||||
elif re.search('^(?:-=-=)', s):
|
elif re.search('^(?:-=-=)', s):
|
||||||
break
|
break
|
||||||
elif self._determineIfSolverState(s):
|
elif self._determineIfSolverState(s):
|
||||||
break
|
break
|
||||||
self.dialog.setText(iter=iter_, depth=depth, states=states)
|
self._setText(iter=iter_, depth=depth, states=states)
|
||||||
|
|
||||||
hints = []
|
hints = []
|
||||||
for sbytes in pout:
|
if use_fc_solve_lib:
|
||||||
s = six.text_type(sbytes, encoding='utf-8')
|
self._setText(
|
||||||
if DEBUG:
|
iter=fc_solve_lib_obj.get_num_times(),
|
||||||
print(s)
|
depth=0,
|
||||||
if self._determineIfSolverState(s):
|
states=fc_solve_lib_obj.get_num_states_in_collection(),
|
||||||
next
|
)
|
||||||
m = re.match('Total number of states checked is ([0-9]+)\\.', s)
|
if status == 0:
|
||||||
if m:
|
m = fc_solve_lib_obj.get_next_move()
|
||||||
iter_ = int(m.group(1))
|
while m:
|
||||||
self.dialog.setText(iter=iter_)
|
type_ = ord(m.s[0])
|
||||||
|
src = ord(m.s[1])
|
||||||
|
dest = ord(m.s[2])
|
||||||
|
hints.append([
|
||||||
|
(ord(m.s[3]) if type_ == 0
|
||||||
|
else (13 if type_ == 11 else 1)),
|
||||||
|
(game.s.rows if (type_ in [0, 1, 4, 11, ])
|
||||||
|
else game.s.reserves)[src],
|
||||||
|
(game.s.rows[dest] if (type_ in [0, 2])
|
||||||
|
else (game.s.reserves[dest]
|
||||||
|
if (type_ in [1, 3]) else None))])
|
||||||
|
|
||||||
m = re.match('This scan generated ([0-9]+) states\\.', s)
|
m = fc_solve_lib_obj.get_next_move()
|
||||||
|
|
||||||
if m:
|
|
||||||
states = int(m.group(1))
|
|
||||||
self.dialog.setText(states=states)
|
|
||||||
|
|
||||||
m = re.match('Move (.*)', s)
|
|
||||||
if not m:
|
|
||||||
continue
|
|
||||||
|
|
||||||
move_s = m.group(1)
|
|
||||||
|
|
||||||
m = re.match(
|
|
||||||
'the sequence on top of Stack ([0-9]+) to the foundations',
|
|
||||||
move_s)
|
|
||||||
|
|
||||||
if m:
|
|
||||||
ncards = 13
|
|
||||||
st = stack_types['stack']
|
|
||||||
sn = int(m.group(1))
|
|
||||||
src = st[sn]
|
|
||||||
dest = None
|
|
||||||
else:
|
else:
|
||||||
|
self.solver_state = 'unsolved'
|
||||||
|
else:
|
||||||
|
for sbytes in pout:
|
||||||
|
s = six.text_type(sbytes, encoding='utf-8')
|
||||||
|
if DEBUG:
|
||||||
|
print(s)
|
||||||
|
if self._determineIfSolverState(s):
|
||||||
|
break
|
||||||
m = re.match(
|
m = re.match(
|
||||||
'(?P<ncards>a card|(?P<count>[0-9]+) cards) '
|
'Total number of states checked is ([0-9]+)\\.', s)
|
||||||
'from (?P<source_type>stack|freecell) '
|
if m:
|
||||||
'(?P<source_idx>[0-9]+) to '
|
self._setText(iter=int(m.group(1)))
|
||||||
'(?P<dest>the foundations|(?P<dest_type>freecell|stack) '
|
|
||||||
'(?P<dest_idx>[0-9]+))\\s*', move_s)
|
|
||||||
|
|
||||||
|
m = re.match('This scan generated ([0-9]+) states\\.', s)
|
||||||
|
|
||||||
|
if m:
|
||||||
|
self._setText(states=int(m.group(1)))
|
||||||
|
|
||||||
|
m = re.match('Move (.*)', s)
|
||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ncards = m.group('ncards')
|
move_s = m.group(1)
|
||||||
if ncards == 'a card':
|
|
||||||
ncards = 1
|
|
||||||
else:
|
|
||||||
ncards = int(m.group('count'))
|
|
||||||
|
|
||||||
st = stack_types[m.group('source_type')]
|
m = re.match(
|
||||||
sn = int(m.group('source_idx'))
|
'the sequence on top of Stack ([0-9]+) to the foundations',
|
||||||
src = st[sn] # source stack
|
move_s)
|
||||||
|
|
||||||
dest_s = m.group('dest')
|
if m:
|
||||||
if dest_s == 'the foundations':
|
ncards = 13
|
||||||
# to foundation
|
st = stack_types['stack']
|
||||||
|
sn = int(m.group(1))
|
||||||
|
src = st[sn]
|
||||||
dest = None
|
dest = None
|
||||||
else:
|
else:
|
||||||
# to rows or reserves
|
m = re.match(
|
||||||
dt = stack_types[m.group('dest_type')]
|
'(?P<ncards>a card|(?P<count>[0-9]+) cards) '
|
||||||
dn = int(m.group('dest_idx'))
|
'from (?P<source_type>stack|freecell) '
|
||||||
dest = dt[dn]
|
'(?P<source_idx>[0-9]+) to '
|
||||||
|
'(?P<dest>the foundations|'
|
||||||
|
'(?P<dest_type>freecell|stack) '
|
||||||
|
'(?P<dest_idx>[0-9]+))\\s*', move_s)
|
||||||
|
|
||||||
hints.append([ncards, src, dest])
|
if not m:
|
||||||
# print src, dest, ncards
|
continue
|
||||||
|
|
||||||
|
if m.group('ncards') == 'a card':
|
||||||
|
ncards = 1
|
||||||
|
else:
|
||||||
|
ncards = int(m.group('count'))
|
||||||
|
|
||||||
|
st = stack_types[m.group('source_type')]
|
||||||
|
sn = int(m.group('source_idx'))
|
||||||
|
src = st[sn]
|
||||||
|
|
||||||
|
dest_s = m.group('dest')
|
||||||
|
if dest_s == 'the foundations':
|
||||||
|
dest = None
|
||||||
|
else:
|
||||||
|
dt = stack_types[m.group('dest_type')]
|
||||||
|
dest = dt[int(m.group('dest_idx'))]
|
||||||
|
|
||||||
|
hints.append([ncards, src, dest])
|
||||||
|
|
||||||
#
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print('time:', time.time()-start_time)
|
print('time:', time.time()-start_time)
|
||||||
# print perr.read(),
|
|
||||||
|
|
||||||
self.hints = hints
|
self.hints = hints
|
||||||
if len(hints) > 0:
|
if len(hints) > 0:
|
||||||
if self.solver_state != 'intractable':
|
if self.solver_state != 'intractable':
|
||||||
self.solver_state = 'solved'
|
self.solver_state = 'solved'
|
||||||
self.hints.append(None) # XXX
|
self.hints.append(None)
|
||||||
|
|
||||||
# print self.hints
|
if not use_fc_solve_lib:
|
||||||
|
pout.close()
|
||||||
pout.close()
|
perr.close()
|
||||||
perr.close()
|
|
||||||
|
|
||||||
|
|
||||||
class BlackHoleSolver_Hint(Base_Solver_Hint):
|
class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
|
@ -1206,96 +1228,116 @@ class BlackHoleSolver_Hint(Base_Solver_Hint):
|
||||||
game_type = self.game_type
|
game_type = self.game_type
|
||||||
|
|
||||||
board = self.calcBoardString()
|
board = self.calcBoardString()
|
||||||
#
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print('--------------------\n', board, '--------------------')
|
print('--------------------\n', board, '--------------------')
|
||||||
#
|
if use_bh_solve_lib:
|
||||||
args = []
|
# global bh_solve_lib_obj
|
||||||
# args += ['-sam', '-p', '-opt', '--display-10-as-t']
|
# bh_solve_lib_obj = bh_solve_lib_obj.new_bhs_user_handle()
|
||||||
args += ['--game', game_type['preset'], '--rank-reach-prune']
|
bh_solve_lib_obj.recycle()
|
||||||
args += ['--max-iters', self.options['max_iters']]
|
bh_solve_lib_obj.read_board(
|
||||||
if 'queens_on_kings' in game_type:
|
board=board,
|
||||||
args += ['--queens-on-kings']
|
game_type=game_type['preset'],
|
||||||
if 'wrap_ranks' in game_type:
|
place_queens_on_kings=(
|
||||||
args += ['--wrap-ranks']
|
game_type['queens_on_kings']
|
||||||
#
|
if ('queens_on_kings' in game_type) else True),
|
||||||
|
wrap_ranks=(
|
||||||
|
game_type['wrap_ranks']
|
||||||
|
if ('wrap_ranks' in game_type) else True),
|
||||||
|
)
|
||||||
|
bh_solve_lib_obj.limit_iterations(self.options['max_iters'])
|
||||||
|
else:
|
||||||
|
args = []
|
||||||
|
args += ['--game', game_type['preset'], '--rank-reach-prune']
|
||||||
|
args += ['--max-iters', str(self.options['max_iters'])]
|
||||||
|
if 'queens_on_kings' in game_type:
|
||||||
|
args += ['--queens-on-kings']
|
||||||
|
if 'wrap_ranks' in game_type:
|
||||||
|
args += ['--wrap-ranks']
|
||||||
|
|
||||||
|
command = self.BLACK_HOLE_SOLVER_COMMAND + ' ' + ' '.join(args)
|
||||||
|
|
||||||
command = self.BLACK_HOLE_SOLVER_COMMAND + ' ' + \
|
|
||||||
' '.join([str(i) for i in args])
|
|
||||||
pout, perr = self.run_solver(command, board)
|
|
||||||
#
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
# iteration output
|
|
||||||
iter_ = 0
|
|
||||||
depth = 0
|
|
||||||
states = 0
|
|
||||||
|
|
||||||
for sbytes in pout:
|
if use_bh_solve_lib:
|
||||||
s = six.text_type(sbytes, encoding='utf-8')
|
ret_code = bh_solve_lib_obj.resume_solution()
|
||||||
if DEBUG >= 5:
|
else:
|
||||||
print(s)
|
pout, perr = self.run_solver(command, board)
|
||||||
|
|
||||||
m = re.search('^(Intractable|Unsolved|Solved)!', s.rstrip())
|
for sbytes in pout:
|
||||||
if m:
|
s = six.text_type(sbytes, encoding='utf-8')
|
||||||
result = m.group(1)
|
if DEBUG >= 5:
|
||||||
break
|
print(s)
|
||||||
|
|
||||||
self.dialog.setText(iter=iter_, depth=depth, states=states)
|
m = re.search('^(Intractable|Unsolved|Solved)!', s.rstrip())
|
||||||
self.solver_state = result.lower()
|
if m:
|
||||||
|
result = m.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
self._setText(iter=0, depth=0, states=0)
|
||||||
hints = []
|
hints = []
|
||||||
for sbytes in pout:
|
if use_bh_solve_lib:
|
||||||
s = six.text_type(sbytes, encoding='utf-8')
|
self.solver_state = (
|
||||||
if DEBUG:
|
'solved' if ret_code == 0 else
|
||||||
print(s)
|
('intractable'
|
||||||
|
if bh_solve_lib_obj.ret_code_is_suspend(ret_code)
|
||||||
|
else 'unsolved'))
|
||||||
|
self._setText(iter=bh_solve_lib_obj.get_num_times())
|
||||||
|
self._setText(
|
||||||
|
states=bh_solve_lib_obj.get_num_states_in_collection())
|
||||||
|
if self.solver_state == 'solved':
|
||||||
|
m = bh_solve_lib_obj.get_next_move()
|
||||||
|
while m:
|
||||||
|
found_stack_idx = m.get_column_idx()
|
||||||
|
if len(game.s.rows) > found_stack_idx >= 0:
|
||||||
|
src = game.s.rows[found_stack_idx]
|
||||||
|
|
||||||
if s.strip() == 'Deal talon':
|
hints.append([1, src, None])
|
||||||
hints.append([1, game.s.talon, None])
|
else:
|
||||||
continue
|
hints.append([1, game.s.talon, None])
|
||||||
|
m = bh_solve_lib_obj.get_next_move()
|
||||||
|
else:
|
||||||
|
self.solver_state = result.lower()
|
||||||
|
for sbytes in pout:
|
||||||
|
s = six.text_type(sbytes, encoding='utf-8')
|
||||||
|
if DEBUG:
|
||||||
|
print(s)
|
||||||
|
|
||||||
m = re.match('Total number of states checked is ([0-9]+)\\.', s)
|
if s.strip() == 'Deal talon':
|
||||||
if m:
|
hints.append([1, game.s.talon, None])
|
||||||
iter_ = int(m.group(1))
|
continue
|
||||||
self.dialog.setText(iter=iter_)
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re.match('This scan generated ([0-9]+) states\\.', s)
|
m = re.match(
|
||||||
|
'Total number of states checked is ([0-9]+)\\.', s)
|
||||||
|
if m:
|
||||||
|
self._setText(iter=int(m.group(1)))
|
||||||
|
continue
|
||||||
|
|
||||||
if m:
|
m = re.match('This scan generated ([0-9]+) states\\.', s)
|
||||||
states = int(m.group(1))
|
|
||||||
self.dialog.setText(states=states)
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re.match(
|
if m:
|
||||||
'Move a card from stack ([0-9]+) to the foundations', s)
|
self._setText(states=int(m.group(1)))
|
||||||
if not m:
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
found_stack_idx = int(m.group(1))
|
m = re.match(
|
||||||
ncards = 1
|
'Move a card from stack ([0-9]+) to the foundations', s)
|
||||||
st = game.s.rows
|
if not m:
|
||||||
sn = found_stack_idx
|
continue
|
||||||
src = st[sn] # source stack
|
|
||||||
dest = None
|
|
||||||
|
|
||||||
hints.append([ncards, src, dest])
|
found_stack_idx = int(m.group(1))
|
||||||
# print src, dest, ncards
|
src = game.s.rows[found_stack_idx]
|
||||||
|
|
||||||
|
hints.append([1, src, None])
|
||||||
|
pout.close()
|
||||||
|
perr.close()
|
||||||
|
|
||||||
#
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print('time:', time.time()-start_time)
|
print('time:', time.time()-start_time)
|
||||||
# print perr.read(),
|
|
||||||
|
|
||||||
|
hints.append(None)
|
||||||
self.hints = hints
|
self.hints = hints
|
||||||
self.hints.append(None) # XXX
|
|
||||||
|
|
||||||
# print self.hints
|
|
||||||
|
|
||||||
pout.close()
|
|
||||||
perr.close()
|
|
||||||
|
|
||||||
|
|
||||||
class FreeCellSolverWrapper:
|
class FreeCellSolverWrapper:
|
||||||
|
|
|
@ -494,9 +494,9 @@ class SubsampledImages(Images):
|
||||||
def getShadow(self, ncards):
|
def getShadow(self, ncards):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _subsample(self, l, r):
|
def _subsample(self, images_list, r):
|
||||||
s = []
|
s = []
|
||||||
for im in l:
|
for im in images_list:
|
||||||
if im is None or r == 1:
|
if im is None or r == 1:
|
||||||
s.append(im)
|
s.append(im)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -444,10 +444,10 @@ class SelectGameDialog(object):
|
||||||
nodes = n.getContents()
|
nodes = n.getContents()
|
||||||
if type(nodes) is list:
|
if type(nodes) is list:
|
||||||
# Blaetter
|
# Blaetter
|
||||||
for l in nodes:
|
for node in nodes:
|
||||||
# print ('**game=%s' % l.text)
|
# print ('**game=%s' % node.text)
|
||||||
yield LGameNode(
|
yield LGameNode(
|
||||||
l, v, text=l.text,
|
node, v, text=node.text,
|
||||||
is_leaf=True,
|
is_leaf=True,
|
||||||
command=self.selectCmd)
|
command=self.selectCmd)
|
||||||
|
|
||||||
|
|
|
@ -458,12 +458,12 @@ class PysolMenubarTk:
|
||||||
def _createSelectMenu(self, games, menu):
|
def _createSelectMenu(self, games, menu):
|
||||||
assert isinstance(menu, gtk.Menu)
|
assert isinstance(menu, gtk.Menu)
|
||||||
self._addPopularGamesMenu(games, menu)
|
self._addPopularGamesMenu(games, menu)
|
||||||
for l, d in (
|
for label, d in (
|
||||||
(ltk2gtk('&French games'), GI.SELECT_GAME_BY_TYPE),
|
(ltk2gtk('&French games'), GI.SELECT_GAME_BY_TYPE),
|
||||||
(ltk2gtk('&Oriental games'), GI.SELECT_ORIENTAL_GAME_BY_TYPE),
|
(ltk2gtk('&Oriental games'), GI.SELECT_ORIENTAL_GAME_BY_TYPE),
|
||||||
(ltk2gtk('&Special games'), GI.SELECT_SPECIAL_GAME_BY_TYPE),
|
(ltk2gtk('&Special games'), GI.SELECT_SPECIAL_GAME_BY_TYPE),
|
||||||
):
|
):
|
||||||
self._addGamesByType(games, menu, l, d)
|
self._addGamesByType(games, menu, label, d)
|
||||||
self._addMahjonggGamesMenu(games, menu)
|
self._addMahjonggGamesMenu(games, menu)
|
||||||
sep = gtk.SeparatorMenuItem()
|
sep = gtk.SeparatorMenuItem()
|
||||||
menu.add(sep)
|
menu.add(sep)
|
||||||
|
|
|
@ -257,8 +257,8 @@ _wrap_handlers = {
|
||||||
__bindings = {}
|
__bindings = {}
|
||||||
|
|
||||||
|
|
||||||
def _wrap_event(widget, event, l):
|
def _wrap_event(widget, event, funcs_list):
|
||||||
for wrap, func in l:
|
for wrap, func in funcs_list:
|
||||||
if wrap(event):
|
if wrap(event):
|
||||||
# print "event:", wrap, func, event
|
# print "event:", wrap, func, event
|
||||||
return func(event)
|
return func(event)
|
||||||
|
|
|
@ -28,10 +28,11 @@ import re
|
||||||
import pysol_cards
|
import pysol_cards
|
||||||
assert getattr(pysol_cards, 'VERSION', (0, 0, 0)) >= (0, 8, 17), (
|
assert getattr(pysol_cards, 'VERSION', (0, 0, 0)) >= (0, 8, 17), (
|
||||||
"Newer version of https://pypi.org/project/pysol-cards is required.")
|
"Newer version of https://pypi.org/project/pysol-cards is required.")
|
||||||
import pysol_cards.random # noqa: I100
|
import pysol_cards.random # noqa: E402,I100
|
||||||
import pysol_cards.random_base # noqa: I100
|
import pysol_cards.random_base # noqa: E402,I100
|
||||||
from pysol_cards.random import LCRandom31, match_ms_deal_prefix # noqa: I100
|
from pysol_cards.random import LCRandom31 # noqa: E402,I100
|
||||||
from pysol_cards.random import CUSTOM_BIT, MS_LONG_BIT # noqa: I100
|
from pysol_cards.random import match_ms_deal_prefix # noqa: E402,I100
|
||||||
|
from pysol_cards.random import CUSTOM_BIT, MS_LONG_BIT # noqa: E402,I100
|
||||||
|
|
||||||
|
|
||||||
class CustomRandom(pysol_cards.random_base.RandomBase):
|
class CustomRandom(pysol_cards.random_base.RandomBase):
|
||||||
|
|
|
@ -32,7 +32,7 @@ PACKAGE = 'PySolFC'
|
||||||
TITLE = 'PySol'
|
TITLE = 'PySol'
|
||||||
PACKAGE_URL = 'http://pysolfc.sourceforge.net/'
|
PACKAGE_URL = 'http://pysolfc.sourceforge.net/'
|
||||||
|
|
||||||
VERSION_TUPLE = (2, 8, 0)
|
VERSION_TUPLE = (2, 10, 0)
|
||||||
VERSION = '.'.join(map(str, VERSION_TUPLE))
|
VERSION = '.'.join(map(str, VERSION_TUPLE))
|
||||||
|
|
||||||
# Tk windowing system (auto set up in init.py)
|
# Tk windowing system (auto set up in init.py)
|
||||||
|
|
|
@ -1249,6 +1249,8 @@ class Stack:
|
||||||
def startDrag(self, event, sound=True):
|
def startDrag(self, event, sound=True):
|
||||||
# print event.x, event.y
|
# print event.x, event.y
|
||||||
assert self.game.drag.stack is None
|
assert self.game.drag.stack is None
|
||||||
|
# import pdb
|
||||||
|
# pdb.set_trace()
|
||||||
i = self._findCard(event)
|
i = self._findCard(event)
|
||||||
if i < 0 or not self.canMoveCards(self.cards[i:]):
|
if i < 0 or not self.canMoveCards(self.cards[i:]):
|
||||||
return
|
return
|
||||||
|
@ -2075,6 +2077,9 @@ class OpenStack(Stack):
|
||||||
return self.basicAcceptsCards(from_stack, cards)
|
return self.basicAcceptsCards(from_stack, cards)
|
||||||
|
|
||||||
def canMoveCards(self, cards):
|
def canMoveCards(self, cards):
|
||||||
|
# import pdb
|
||||||
|
# pdb.set_trace()
|
||||||
|
# print('OpenStack.canMoveCards()', cards)
|
||||||
# default for OpenStack: we can move the top card
|
# default for OpenStack: we can move the top card
|
||||||
# (max_move defaults to 1)
|
# (max_move defaults to 1)
|
||||||
return self.basicCanMoveCards(cards)
|
return self.basicCanMoveCards(cards)
|
||||||
|
@ -2458,6 +2463,7 @@ class BasicRowStack(OpenStack):
|
||||||
# return self._getBaseCard()
|
# return self._getBaseCard()
|
||||||
|
|
||||||
def spiderCanDropCards(self, stacks):
|
def spiderCanDropCards(self, stacks):
|
||||||
|
# print('spiderCanDropCards()', stacks)
|
||||||
# drop whole sequence
|
# drop whole sequence
|
||||||
if len(self.cards) < 13:
|
if len(self.cards) < 13:
|
||||||
return (None, 0)
|
return (None, 0)
|
||||||
|
@ -2629,15 +2635,17 @@ class Yukon_AC_RowStack(BasicRowStack):
|
||||||
kwdefault(cap, max_move=999999, max_accept=999999)
|
kwdefault(cap, max_move=999999, max_accept=999999)
|
||||||
BasicRowStack.__init__(self, x, y, game, **cap)
|
BasicRowStack.__init__(self, x, y, game, **cap)
|
||||||
|
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
|
# print('Yukon_AC_RowStack._isYukonSequence()', c1, c2)
|
||||||
return ((c1.rank + self.cap.dir) % self.cap.mod == c2.rank and
|
return ((c1.rank + self.cap.dir) % self.cap.mod == c2.rank and
|
||||||
c1.color != c2.color)
|
c1.color != c2.color)
|
||||||
|
|
||||||
def acceptsCards(self, from_stack, cards):
|
def acceptsCards(self, from_stack, cards):
|
||||||
|
# print('Yukon_AC_RowStack.acceptsCards()', from_stack, cards)
|
||||||
if not self.basicAcceptsCards(from_stack, cards):
|
if not self.basicAcceptsCards(from_stack, cards):
|
||||||
return False
|
return False
|
||||||
# [topcard + card[0]] must be acceptable
|
# [topcard + card[0]] must be acceptable
|
||||||
if self.cards and not self._isSequence(self.cards[-1], cards[0]):
|
if self.cards and not self._isYukonSequence(self.cards[-1], cards[0]):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -2659,7 +2667,7 @@ class Yukon_AC_RowStack(BasicRowStack):
|
||||||
# A Yukon_SameSuit_RowStack builds down by rank and suit,
|
# A Yukon_SameSuit_RowStack builds down by rank and suit,
|
||||||
# but can move any face-up cards regardless of sequence.
|
# but can move any face-up cards regardless of sequence.
|
||||||
class Yukon_SS_RowStack(Yukon_AC_RowStack):
|
class Yukon_SS_RowStack(Yukon_AC_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return ((c1.rank + self.cap.dir) % self.cap.mod == c2.rank and
|
return ((c1.rank + self.cap.dir) % self.cap.mod == c2.rank and
|
||||||
c1.suit == c2.suit)
|
c1.suit == c2.suit)
|
||||||
|
|
||||||
|
@ -2678,7 +2686,7 @@ class Yukon_SS_RowStack(Yukon_AC_RowStack):
|
||||||
# A Yukon_Rank_RowStack builds down by rank
|
# A Yukon_Rank_RowStack builds down by rank
|
||||||
# but can move any face-up cards regardless of sequence.
|
# but can move any face-up cards regardless of sequence.
|
||||||
class Yukon_RK_RowStack(Yukon_AC_RowStack):
|
class Yukon_RK_RowStack(Yukon_AC_RowStack):
|
||||||
def _isSequence(self, c1, c2):
|
def _isYukonSequence(self, c1, c2):
|
||||||
return (c1.rank + self.cap.dir) % self.cap.mod == c2.rank
|
return (c1.rank + self.cap.dir) % self.cap.mod == c2.rank
|
||||||
|
|
||||||
def getHelp(self):
|
def getHelp(self):
|
||||||
|
@ -3126,6 +3134,8 @@ class StackWrapper:
|
||||||
# return a new stack (an instance of the stack class)
|
# return a new stack (an instance of the stack class)
|
||||||
def __call__(self, x, y, game, **cap):
|
def __call__(self, x, y, game, **cap):
|
||||||
# must preserve self.cap, so create a shallow copy
|
# must preserve self.cap, so create a shallow copy
|
||||||
|
# import pdb
|
||||||
|
# pdb.set_trace()
|
||||||
c = self.cap.copy()
|
c = self.cap.copy()
|
||||||
kwdefault(c, **cap)
|
kwdefault(c, **cap)
|
||||||
return self.stack_class(x, y, game, **c)
|
return self.stack_class(x, y, game, **c)
|
||||||
|
|
|
@ -809,8 +809,8 @@ class TopFrame(ttk.Frame):
|
||||||
# s.score_casino_result.min,
|
# s.score_casino_result.min,
|
||||||
# s.score_casino_result.max,
|
# s.score_casino_result.max,
|
||||||
# round(s.score_casino_result.average, 2), ))
|
# round(s.score_casino_result.average, 2), ))
|
||||||
for l, min, max, avr, tot, top in ll:
|
for label, min, max, avr, tot, top in ll:
|
||||||
ttk.Label(frame, text=l
|
ttk.Label(frame, text=label
|
||||||
).grid(row=row, column=0, padx=5, pady=5)
|
).grid(row=row, column=0, padx=5, pady=5)
|
||||||
ttk.Label(frame, text=str(min)
|
ttk.Label(frame, text=str(min)
|
||||||
).grid(row=row, column=1, padx=5, pady=5)
|
).grid(row=row, column=1, padx=5, pady=5)
|
||||||
|
|
|
@ -772,8 +772,8 @@ class Top_StatsDialog(MfxDialog):
|
||||||
# s.score_casino_result.min,
|
# s.score_casino_result.min,
|
||||||
# s.score_casino_result.max,
|
# s.score_casino_result.max,
|
||||||
# round(s.score_casino_result.average, 2), ))
|
# round(s.score_casino_result.average, 2), ))
|
||||||
for l, min, max, avr, tot, top in ll:
|
for label, min, max, avr, tot, top in ll:
|
||||||
tkinter.Label(frame, text=l).grid(row=row, column=0)
|
tkinter.Label(frame, text=label).grid(row=row, column=0)
|
||||||
tkinter.Label(frame, text=str(min)).grid(row=row, column=1)
|
tkinter.Label(frame, text=str(min)).grid(row=row, column=1)
|
||||||
tkinter.Label(frame, text=str(max)).grid(row=row, column=2)
|
tkinter.Label(frame, text=str(max)).grid(row=row, column=2)
|
||||||
tkinter.Label(frame, text=str(avr)).grid(row=row, column=3)
|
tkinter.Label(frame, text=str(avr)).grid(row=row, column=3)
|
||||||
|
|
|
@ -178,8 +178,8 @@ class FindCardDialog(tkinter.Toplevel):
|
||||||
item.config(state=state)
|
item.config(state=state)
|
||||||
|
|
||||||
def destroy(self, *args):
|
def destroy(self, *args):
|
||||||
for l in self.groups:
|
for group in self.groups:
|
||||||
unbind_destroy(l)
|
unbind_destroy(group)
|
||||||
unbind_destroy(self)
|
unbind_destroy(self)
|
||||||
if self.timer:
|
if self.timer:
|
||||||
after_cancel(self.timer)
|
after_cancel(self.timer)
|
||||||
|
|
|
@ -6,7 +6,9 @@ from pysol_tests.common_mocks1 import MockApp, MockCanvas, MockItem, MockTalon
|
||||||
|
|
||||||
import pysollib.stack
|
import pysollib.stack
|
||||||
from pysollib.acard import AbstractCard
|
from pysollib.acard import AbstractCard
|
||||||
from pysollib.games.spider import Scorpion_RowStack, Spider_RowStack
|
from pysollib.games.spider import ScorpionTail_RowStack
|
||||||
|
from pysollib.games.spider import Scorpion_RowStack
|
||||||
|
from pysollib.games.spider import Spider_RowStack
|
||||||
|
|
||||||
|
|
||||||
class MockGame:
|
class MockGame:
|
||||||
|
@ -41,9 +43,11 @@ class Mock_S_Game:
|
||||||
|
|
||||||
|
|
||||||
class MyTests(unittest.TestCase):
|
class MyTests(unittest.TestCase):
|
||||||
def _calc_Scorpion_stack(self):
|
def _calc_Scorpion_stack(self, isScorpionTail):
|
||||||
g = MockGame()
|
g = MockGame()
|
||||||
stack = Scorpion_RowStack(0, 0, g)
|
stack = (ScorpionTail_RowStack
|
||||||
|
if isScorpionTail
|
||||||
|
else Scorpion_RowStack)(0, 0, g)
|
||||||
for s, r in [(2, 5), (3, 7), (2, 7), (2, 0), (2, 3), (2, 4), (1, 4)]:
|
for s, r in [(2, 5), (3, 7), (2, 7), (2, 0), (2, 3), (2, 4), (1, 4)]:
|
||||||
c = AbstractCard(1000+r*100+s*10, 0, s, r, g)
|
c = AbstractCard(1000+r*100+s*10, 0, s, r, g)
|
||||||
c.face_up = True
|
c.face_up = True
|
||||||
|
@ -52,14 +56,16 @@ class MyTests(unittest.TestCase):
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
def test_canMoveCards(self):
|
def test_canMoveCards(self):
|
||||||
stack = self._calc_Scorpion_stack()
|
for isScorpionTail in [False, True]:
|
||||||
stack.canMoveCards(stack.cards[6:])
|
stack = self._calc_Scorpion_stack(isScorpionTail)
|
||||||
self.assertTrue(stack)
|
stack.canMoveCards(stack.cards[6:])
|
||||||
|
self.assertTrue(stack)
|
||||||
|
|
||||||
def test_canMoveCards_non_top(self):
|
def test_canMoveCards_non_top(self):
|
||||||
stack = self._calc_Scorpion_stack()
|
for isScorpionTail in [False, True]:
|
||||||
self.assertTrue(stack.canMoveCards(stack.cards[4:]))
|
stack = self._calc_Scorpion_stack(isScorpionTail)
|
||||||
self.assertTrue(stack)
|
self.assertTrue(stack.canMoveCards(stack.cards[4:]))
|
||||||
|
self.assertTrue(stack)
|
||||||
|
|
||||||
def _calc_Spider_stack(self):
|
def _calc_Spider_stack(self):
|
||||||
g = MockGame()
|
g = MockGame()
|
||||||
|
|
Loading…
Add table
Reference in a new issue