diff --git a/pysollib/app.py b/pysollib/app.py index a0a70260..2b2a022b 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -1411,7 +1411,7 @@ Please select a %s type %s. try: loadGame(m.group(1), n) except Exception, ex: - print >> sys.stderr, "Error loading plugin " + n + ": " + str(ex) + print >> sys.stderr, _("Error loading plugin %s: %s") % (n, ex) sys.stderr.flush() sys.path = p @@ -1429,7 +1429,7 @@ Please select a %s type %s. finally: if f: f.close() lines = [l.strip() for l in lines] - if lines[0].find("PySol") != 0: + if not lines[0].startswith("PySol"): return None config = CardsetConfig() if not self._parseCardsetConfig(config, lines): diff --git a/pysollib/games/bakersgame.py b/pysollib/games/bakersgame.py index 0fe714dc..8b4d95be 100644 --- a/pysollib/games/bakersgame.py +++ b/pysollib/games/bakersgame.py @@ -320,6 +320,39 @@ class Opus(Penguin): +# /*********************************************************************** +# // Flipper +# ************************************************************************/ + +class Flipper_Row(AC_RowStack): + def canFlipCard(self): + if not OpenStack.canFlipCard(self): + return False + i = list(self.game.s.rows).index(self) + return len(self.game.s.reserves[i].cards) == 0 + + +class Flipper(Tuxedo): + + RowStack_Class = Flipper_Row + Foundation_Class = SS_FoundationStack + Hint_Class = DefaultHint + Solver_Class = None + + def fillStack(self, stack): + i = 0 + for s in self.s.reserves: + r = self.s.rows[i] + if r.cards: + if ((s.cards and r.cards[-1].face_up) or + (not s.cards and not r.cards[-1].face_up)): + r.flipMove(animation=True) + i += 1 + + shallHighlightMatch = Game._shallHighlightMatch_AC + + + # register the game registerGame(GameInfo(45, BakersGame, "Baker's Game", GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_SKILL)) @@ -339,3 +372,5 @@ registerGame(GameInfo(427, Opus, "Opus", GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(629, Tuxedo, "Tuxedo", GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(713, Flipper, "Flipper", + GI.GT_FREECELL | GI.GT_ORIGINAL, 1, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/gypsy.py b/pysollib/games/gypsy.py index 7693cec1..b43fba81 100644 --- a/pysollib/games/gypsy.py +++ b/pysollib/games/gypsy.py @@ -746,6 +746,63 @@ class BrazilianPatience(Gypsy): self.s.talon.dealRow() +# /*********************************************************************** +# // Leprechaun +# ************************************************************************/ + +class Leprechaun_Reserve(OpenStack): + def canFlipCard(self): + if not OpenStack.canFlipCard(self): + return False + i = list(self.game.s.reserves).index(self) + return len(self.game.s.foundations[i].cards) != 0 + + +class Leprechaun(Game): + + def createGame(self): + + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM+9.5*l.XS, l.YM+3*l.YS+l.TEXT_HEIGHT+12*l.YOFFSET) + + # create stacks + x, y = l.XM+1.5*l.XS, l.TEXT_HEIGHT + for i in range(8): + stack = Leprechaun_Reserve(x, y, self) + s.reserves.append(stack) + l.createText(stack, 'n') + x += l.XS + + x, y = l.XM+1.5*l.XS, l.YS+l.TEXT_HEIGHT + for i in range(8): + s.foundations.append(SS_FoundationStack(x, y, self, suit=i/2)) + x += l.XS + + x, y = l.XM+1.5*l.XS, 2*l.YS+l.TEXT_HEIGHT + for i in range(8): + s.rows.append(AC_RowStack(x, y, self)) + x += l.XS + + s.talon = DealRowTalonStack(l.XM, l.YM, self) + l.createText(s.talon, 's') + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + for i in range(4): + self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=0) + self.s.talon.dealRow(flip=0, frames=0) + self.s.talon.dealRow(flip=0, frames=0) + self.startDealSample() + self.s.talon.dealRow() + + shallHighlightMatch = Game._shallHighlightMatch_AC + + # register the game registerGame(GameInfo(1, Gypsy, "Gypsy", @@ -811,3 +868,5 @@ registerGame(GameInfo(640, BrazilianPatience, "Brazilian Patience", GI.GT_GYPSY, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(666, TrapdoorSpider, "Trapdoor Spider", GI.GT_SPIDER | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(712, Leprechaun, "Leprechaun", + GI.GT_GYPSY | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/mahjongg/mahjongg.py b/pysollib/games/mahjongg/mahjongg.py index b18dccd4..df5ae3a7 100644 --- a/pysollib/games/mahjongg/mahjongg.py +++ b/pysollib/games/mahjongg/mahjongg.py @@ -539,12 +539,12 @@ class AbstractMahjonggGame(Game): del cards[i] break # - free_stacks = [] + free_stacks = [] # none-blocked stacks for r in rows: if new_cards[r.id] is None and not is_blocked(r, new_cards): free_stacks.append(r) if len(free_stacks) < 2: - return None + return None # try another way # i = factorial(len(free_stacks))/2/factorial(len(free_stacks)-2) old_pairs = [] @@ -559,15 +559,16 @@ class AbstractMahjonggGame(Game): if (r1, r2) not in old_pairs and (r2, r1) not in old_pairs: old_pairs.append((r1, r2)) break + # add two selected cards to new_cards s1 = free_stacks[r1] s2 = free_stacks[r2] nc[s1.id] = c1 nc[s2.id] = c2 + # check if this layout is solvable (backtracking) nc = create_solvable(cards[:], nc) if nc: return nc - - return None + return None # try another way new_cards = create_solvable(cards, [None]*len(cards)) if new_cards: diff --git a/pysollib/games/spider.py b/pysollib/games/spider.py index 1a283a0b..557ec15e 100644 --- a/pysollib/games/spider.py +++ b/pysollib/games/spider.py @@ -1274,6 +1274,114 @@ class Bebop(Game): shallHighlightMatch = Game._shallHighlightMatch_RK +# /*********************************************************************** +# // The Jolly Roger +# ************************************************************************/ + +class TheJollyRoger_Foundation(AbstractFoundationStack): + + def acceptsCards(self, from_stack, cards): + if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): + return False + return isSameColorSequence(cards, self.cap.mod, self.cap.dir) + + def getBottomImage(self): + return self.game.app.images.getLetter(ACE) + + +class TheJollyRoger_RowStack(BasicRowStack): + + def acceptsCards(self, from_stack, cards): + if not BasicRowStack.acceptsCards(self, from_stack, cards): + return False + if not self.cards: + return True + c1, c2 = self.cards[-1], cards[0] + if c2.rank == ACE: + return c1.rank == ACE + return c1.rank == c2.rank+2 + + def canMoveCards(self, cards): + if cards[0].rank == ACE: + return isSameColorSequence(cards, dir=0) + elif cards[-1].rank == ACE: + return False # 5-3-ace + return isSameSuitSequence(cards, dir=-2) + + def canDropCards(self, stacks): + cards = self.cards + if not cards: + return (None, 0) + dcards = None + if cards[-1].rank == ACE: + if len(cards) < 4: + return (None, 0) + if isSameColorSequence(cards[-4:], dir=0): + dcards = cards[-4:] + else: + if len(cards) < 6: + return (None, 0) + if isSameSuitSequence(cards, dir=-2): + dcards = cards[-6:] + if not dcards: + return (None, 0) + for s in stacks: + if s is not self and s.acceptsCards(self, dcards): + return (s, len(dcards)) + return (None, 0) + + +class TheJollyRoger(Game): + Hint_Class = Spider_Hint + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM+13*l.XS, l.YM+3*l.YS+12*l.YOFFSET) + + # create stacks + y = l.YM + for i in range(2): + x = l.XM+2*l.XS + for j in range(8): + s.foundations.append(Spider_SS_Foundation(x, y, self, + dir=-2, base_rank=ANY_RANK, + min_accept=6, max_cards=6, max_move=0)) + x += l.XS + s.foundations.append(TheJollyRoger_Foundation(x, y, self, + suit=ANY_SUIT, dir=0, + min_accept=4, max_accept=4, + max_cards=4, max_move=0)) + y += l.YS + + x, y = l.XM, l.YM+2*l.YS + for i in range(13): + s.rows.append(TheJollyRoger_RowStack(x, y, self, dir=2, + max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS)) + x += l.XS + s.talon = DealRowTalonStack(l.XM, l.YM, self) + l.createText(s.talon, 's') + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + for i in range(2): + self.s.talon.dealRow(frames=0) + self.startDealSample() + self.s.talon.dealRow() + + def shallHighlightMatch(self, stack1, card1, stack2, card2): + if card1.rank != ACE and card2.rank != ACE: + # by rank + return abs(card1.rank-card2.rank) == 2 + return card1.rank == ACE and card2.rank == ACE + + getQuickPlayScore = Game._getSpiderQuickPlayScore + + # register the game registerGame(GameInfo(10, RelaxedSpider, "Relaxed Spider", @@ -1396,6 +1504,8 @@ registerGame(GameInfo(685, FechtersGame, "Fechter's Game", GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(710, Bebop, "Bebop", GI.GT_2DECK_TYPE | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) -#registerGame(GameInfo(711, SimpleSimonII, "Simple Simon II", +#registerGame(GameInfo(000, SimpleSimonII, "Simple Simon II", # GI.GT_SPIDER | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) +registerGame(GameInfo(711, TheJollyRoger, "The Jolly Roger", + GI.GT_SPIDER | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) diff --git a/pysollib/games/yukon.py b/pysollib/games/yukon.py index 80cf31c6..45312b54 100644 --- a/pysollib/games/yukon.py +++ b/pysollib/games/yukon.py @@ -694,6 +694,9 @@ class Hawaiian(Game): self.startDealSample() self.s.talon.dealRow() + def getHighlightPilesStacks(self): + return () + shallHighlightMatch = Game._shallHighlightMatch_AC diff --git a/pysollib/images.py b/pysollib/images.py index 239d2693..1085d4b3 100644 --- a/pysollib/images.py +++ b/pysollib/images.py @@ -313,22 +313,46 @@ class Images: im = c._active_image._pil_image mask.paste(im, (x, y), im) # create shadow - sh = self._pil_shadow_image - shw, shh = sh.size - shadow = Image.new('RGBA', (w, h)) - x = 0 - while x < w: - y = 0 - while y < h: - shadow.paste(sh, (x,y)) - y += shh - x += shw - shadow = Image.composite(shadow, mask, mask) - # crop image (for speed) - sx, sy = self.SHADOW_XOFFSET, self.SHADOW_YOFFSET - mask = mask.crop((sx,sy,w,h)) - tmp = Image.new('RGBA', (w-sx,h-sy)) - shadow.paste(tmp, (0,0), mask) + if 0: + sh = self._pil_shadow_image + shw, shh = sh.size + shadow = Image.new('RGBA', (w, h)) + x = 0 + while x < w: + y = 0 + while y < h: + shadow.paste(sh, (x,y)) + y += shh + x += shw + shadow = Image.composite(shadow, mask, mask) + # crop image (for speed) + sx, sy = self.SHADOW_XOFFSET, self.SHADOW_YOFFSET + mask = mask.crop((sx,sy,w,h)) + tmp = Image.new('RGBA', (w-sx,h-sy)) + shadow.paste(tmp, (0,0), mask) + elif 0: + import ImageFilter + dx, dy = 5, 5 + sh_color = (0x00,0x00,0x00,0x80) + shadow = Image.new('RGBA', (w+dx, h+dy)) + sx, sy = self.SHADOW_XOFFSET, self.SHADOW_YOFFSET + shadow.paste(sh_color, (0, 0, w, h), mask) + for i in range(3): + shadow = shadow.filter(ImageFilter.BLUR) + shadow = shadow.crop((dx,dy,w,h)) + sx, sy = self.SHADOW_XOFFSET, self.SHADOW_YOFFSET + mask = mask.crop((sx,sy,w,h)) + tmp = Image.new('RGBA', (w-sx,h-sy)) + shadow.paste(tmp, (0,0), mask) + else: + sh_color = (0x00,0x00,0x00,0x50) + shadow = Image.new('RGBA', (w, h)) + shadow.paste(sh_color, (0, 0, w, h), mask) + sx, sy = self.SHADOW_XOFFSET, self.SHADOW_YOFFSET + mask = mask.crop((sx,sy,w,h)) + tmp = Image.new('RGBA', (w-sx,h-sy)) + shadow.paste(tmp, (0,0), mask) + # shadow = ImageTk.PhotoImage(shadow) self._pil_shadow[(w,h)] = shadow diff --git a/pysollib/settings.py b/pysollib/settings.py index c00bad01..efefdac4 100644 --- a/pysollib/settings.py +++ b/pysollib/settings.py @@ -26,11 +26,12 @@ n_ = lambda x: x # for gettext #PACKAGE = 'PySolFC' PACKAGE = 'PySol' +#PACKAGE_URL = 'http://pysolfc/sourceforge.net/' PACKAGE_URL = 'http://sourceforge.net/projects/pysolfc/' VERSION = '4.82' -FC_VERSION = '1.0' -VERSION_TUPLE = (10, 0) +FC_VERSION = '1.0.1' +VERSION_TUPLE = (10, 0, 1) # Tk windowing system (auto determine in init.py) WIN_SYSTEM = 'x11' # win32, x11, aqua, classic diff --git a/scripts/cardset_viewer.py b/scripts/cardset_viewer.py index aaec984a..8e255b7a 100755 --- a/scripts/cardset_viewer.py +++ b/scripts/cardset_viewer.py @@ -110,7 +110,12 @@ def show_cardset(*args): # zoom z = 1.0 + zoom/10.0 z = max(0.2, z) - im = im.resize((int(w*z), int(h*z)), resample=filter) + if 1: + tmp = Image.new('RGBA', (w+2, h+2)) + tmp.paste(im, (1,1), im) + im = tmp.resize((int(w*z), int(h*z)), resample=filter) + else: + im = im.resize((int(w*z), int(h*z)), resample=filter) t = '%d %%' % int(z*100) zoom_label.config(text=t)