solitaire: Add README.md

This commit is contained in:
Martin Fitzpatrick 2018-02-19 02:41:47 +01:00
parent 074c4c9970
commit a165bbcf28
4 changed files with 70 additions and 6 deletions

View File

@ -30,8 +30,12 @@ found [on my site](http://martinfitzpatrick.name/tag/pyqt).
1. [Currency converter](currency/) - "Doughnut" (PyQtGraph)
1. [Solitaire](solitaire/) - "Ronery" (QGraphicsScene)
# License
## License
All code is **licensed under an MIT license**. This allows you to re-use the code freely,
remixed in both commercial and non-commercial projects. The only requirement is to
include the same license when distributing.
## Other licenses
Icons used in the applications are by [Yusuke Kamiyaman](http://p.yusukekamiyamane.com/).

View File

@ -6,16 +6,16 @@ ready made pictures of pie.
Piecasso is a clone of the Paint programme from Windows 95 (ish) with a
few additions (and subtractions). The programme features standard
tools including pen, brush, fill, spray can, eraser, text and a number of
shape drawing widgets.
shapes.
![Piecasso](screenshot-paint.png)
![Piecasso](screenshot-paint2.png)
You can copy from the image, with a custom shape,
although pasting + floating is not supported. The canvas is a fixed size
and loaded images are adjusted to fit. A stamp tool is also included
which is pre-loaded with pictures of delicious pie.
![Piecasso](screenshot-paint2.png)
![Piecasso](screenshot-paint.png)
> If you think this example app is neat and want to learn more about
PyQt in general, [take a look at my ebook & online course

60
solitaire/README.md Normal file
View File

@ -0,0 +1,60 @@
# Ronery — A Solitaire game in PyQt
The classic card Solitaire (Klondike) game with a North Korean /
'Team America: World Police' twist. The game is otherwise identical,
offering the same options. Built with PyQt, it uses QGraphicsScene
to handle the play area.
![Ronery](screenshot-solitaire.png)
The classic Solitaire win-screen is also implemented, although since
the play canvas is not a bitmap it doesn't "fill up". It's still
sufficiently satisfying.
![Ronery](screenshot-solitaire2.png)
The configuration options allow for 3-draw and 1 draw styles, with 3, 5
or infinite rounds.
## Code notes
### Card handling
The approach I used here was to treat each place where cards can be placed
as a 'stack' object, which handles the cards it currently holds. Each stack
is responsible for the layout of the cards on it's pile.
A stack is also responsibly for accepting/rejecting an attempted drop of a
card on it. Some stacks, e.g. the deck + deal pile do not accept any drop.
Others, such as the finish piles, have specific rules.
In most cases there is no relationship between any cards on a stack, with
the exception of the 'in play' stacks along the bottom. Here cards have
a parent-child relationship, allowing multiple cards to be dragged at once.
### The end animation
The end-game was a bit weird to implement. Since it happens 'outside' of
game time the first thought was to have a self contained loop, using
`QApplication.processEvents` to tick over. But that's nasty.
Instead I used a timer, idle during play, which constantly pings an
animation step-forward endpoint. This moves cards (faking 'gravity', bouncing)
as well as re-stacking them once they're out of the play area.
Restacking uses the normal stacking code.
The final step was to block event handling, otherwise the cards could
still be grabbed while they bounced (and dropped). The easiest way to
achieve this was to simply place an event-capturing object over the entire
window.
## Other licenses
The card images were made from a [freely available set of PNGs](https://github.com/hayeah/playing-cards-assets)
which were themselves auto-generated from SVGs traced from actual cards(!).
The original card designs are out of copyright.
Note that the linked repository contains some custom art on ace cards which may still be copyrighted and so
was not used.
Icons used in the application are by [Yusuke Kamiyaman](http://p.yusukekamiyamane.com/).

View File

@ -651,8 +651,8 @@ class MainWindow(QMainWindow):
if card.pos().x() < - CARD_DIMENSIONS.width():
card.vector = None
drop = random.choice(self.drops)
drop.add_card(card)
# Put the card back where it started.
card.stack.add_card(card)