mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-15 02:54:09 -04:00
Compare commits
37 commits
2c16d5773d
...
513726360d
Author | SHA1 | Date | |
---|---|---|---|
|
513726360d | ||
|
52d37cfeae | ||
|
c7a3907d25 | ||
|
8244d19e6e | ||
|
70123aaa5d | ||
|
9666c56a9f | ||
|
6f591dd519 | ||
|
bce3354f3d | ||
|
abc9c2c3aa | ||
|
90d36213e8 | ||
|
b90b3ed1e1 | ||
|
8dbd5c552f | ||
|
bf620c6310 | ||
|
cc9adb6813 | ||
|
18d3b2713a | ||
|
0a220861a9 | ||
|
42ede36daf | ||
|
451e5a5003 | ||
|
928c8a2819 | ||
|
89a6728bf8 | ||
|
55edd37a72 | ||
|
c6d093d995 | ||
|
b92091d1c3 | ||
|
b26786a877 | ||
|
4b7df34d67 | ||
|
a004f7e690 | ||
|
ccacdbe148 | ||
|
9169297801 | ||
|
586cd4a05f | ||
|
ce72838aff | ||
|
3649a52ab2 | ||
|
3f660b25a0 | ||
|
ca93af4897 | ||
|
2fea665242 | ||
|
d0ff5494d5 | ||
|
3793d8392e | ||
|
0fd5e40b54 |
52 changed files with 214 additions and 2251 deletions
|
@ -37,11 +37,16 @@ test_script:
|
||||||
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
|
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
|
||||||
- 7z x music.tar.xz -so | 7z x -si -ttar
|
- 7z x music.tar.xz -so | 7z x -si -ttar
|
||||||
- move pysol-music-4.50\data\music dist\data\music
|
- move pysol-music-4.50\data\music dist\data\music
|
||||||
- ps: |
|
# - ps: |
|
||||||
$apiUrl = 'https://ci.appveyor.com/api'
|
# $apiUrl = 'https://ci.appveyor.com/api'
|
||||||
$project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
|
# $project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
|
||||||
$jobId = $project.build.jobs[0].jobId
|
# $jobId = $project.build.jobs[0].jobId
|
||||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/fc-solve/pkg-build/fc-solve-for-pysol.zip" -OutFile fc-solve.zip
|
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/fc-solve/pkg-build/fc-solve-for-pysol.zip" -OutFile fc-solve.zip
|
||||||
|
#
|
||||||
|
# For reproducible builds:
|
||||||
|
# See: https://reproducible-builds.org/ .
|
||||||
|
- SET FC_SOLVE_VER=5.20.0
|
||||||
|
- appveyor DownloadFile https://netix.dl.sourceforge.net/project/fc-solve/fc-solve/DO-NOT-USE--fc-solve-for-pysol/fc-solve-for-pysol--v%FC_SOLVE_VER%.zip -FileName fc-solve.zip
|
||||||
- 7z x fc-solve.zip
|
- 7z x fc-solve.zip
|
||||||
- move fcs-pysol dist\freecell-solver
|
- move fcs-pysol dist\freecell-solver
|
||||||
- 7z a -r pysol_win_dist.7z dist\
|
- 7z a -r pysol_win_dist.7z dist\
|
||||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -1,7 +1,7 @@
|
||||||
addons:
|
addons:
|
||||||
homebrew:
|
homebrew:
|
||||||
update: true
|
|
||||||
brewfile: true
|
brewfile: true
|
||||||
|
update: true
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/perl_modules
|
- $HOME/perl_modules
|
||||||
|
@ -18,12 +18,25 @@ deploy:
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
dist: bionic
|
dist: bionic
|
||||||
before_install:
|
before_install:
|
||||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then wget --content-disposition https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/minimal/PySolFC-Cardsets--Minimal-2.0.tar.xz/download && tar xJf PySolFC-Cardsets--Minimal-2.0.tar.xz && mv PySolFC-Cardsets--Minimal-2.0/cardset-* data ; fi
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then
|
||||||
|
wget --content-disposition https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/minimal/PySolFC-Cardsets--Minimal-2.0.tar.xz/download &&
|
||||||
|
tar xJf PySolFC-Cardsets--Minimal-2.0.tar.xz &&
|
||||||
|
mv PySolFC-Cardsets--Minimal-2.0/cardset-* data ;
|
||||||
|
fi
|
||||||
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then
|
||||||
|
PYVER=3.8.2 &&
|
||||||
|
PYVER_SHORT=3.8 &&
|
||||||
|
wget -O python.pkg "https://www.python.org/ftp/python/${PYVER}/python-${PYVER}-macosx10.9.pkg" &&
|
||||||
|
sudo installer -pkg python.pkg -target / &&
|
||||||
|
export PATH="/Library/Frameworks/Python.framework/Versions/${PYVER_SHORT}/bin:${PATH}" ;
|
||||||
|
fi
|
||||||
install:
|
install:
|
||||||
# Tests are failing for them sometimes
|
# Tests are failing for them sometimes
|
||||||
- sudo cpanm --notest Capture::Tiny IPC::System::Simple
|
- sudo cpanm --notest Capture::Tiny IPC::System::Simple
|
||||||
- sudo cpanm Code::TidyAll::Plugin::Flake8 Perl::Tidy Test::Code::TidyAll Test::Differences Test::TrailingSpace
|
- sudo cpanm Code::TidyAll::Plugin::Flake8 Perl::Tidy Test::Code::TidyAll Test::Differences Test::TrailingSpace
|
||||||
|
|
||||||
- export PY_MODS='attrs configobj pycotap pysol-cards random2 setuptools six'
|
- export PY_MODS='attrs configobj pycotap pysol-cards random2 setuptools six'
|
||||||
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then export PY_MODS="--no-binary=Pillow Pillow $PY_MODS" ; fi
|
||||||
- sudo pip3 install --upgrade $PY_MODS flake8 flake8-import-order
|
- sudo pip3 install --upgrade $PY_MODS flake8 flake8-import-order
|
||||||
- sudo pip2 install --upgrade $PY_MODS
|
- sudo pip2 install --upgrade $PY_MODS
|
||||||
language: generic
|
language: generic
|
||||||
|
@ -47,6 +60,6 @@ matrix:
|
||||||
script:
|
script:
|
||||||
- export TIDYALL_DATA_DIR="$HOME/tidyall_d"
|
- export TIDYALL_DATA_DIR="$HOME/tidyall_d"
|
||||||
- bash -x scripts/travis-ci-build
|
- bash -x scripts/travis-ci-build
|
||||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then PYTHONPATH="`pwd`" python3 setup_osx.py py2app ; fi
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then PYTHONPATH="." python3 setup_osx.py py2app ; fi
|
||||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then find . -iname '*.app' ; fi
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then find . -iname '*.app' ; fi
|
||||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then (cd dist; tar -cvf ../PySolFC.app.tar PySolFC.app/ ; ); xz PySolFC.app.tar ; fi
|
- if test "$TRAVIS_OS_NAME" = "osx" ; then (cd dist && tar -cvf ../PySolFC.app.tar PySolFC.app/) && xz PySolFC.app.tar ; fi
|
||||||
|
|
3
Brewfile
3
Brewfile
|
@ -2,8 +2,7 @@ brew "perl"
|
||||||
brew "cpanminus"
|
brew "cpanminus"
|
||||||
brew "gettext", link: true
|
brew "gettext", link: true
|
||||||
brew "gnutls"
|
brew "gnutls"
|
||||||
|
brew "jpeg"
|
||||||
brew "openssl"
|
brew "openssl"
|
||||||
brew "tcl-tk"
|
|
||||||
brew "python@2"
|
brew "python@2"
|
||||||
brew "python"
|
|
||||||
brew "pyenv-virtualenv"
|
brew "pyenv-virtualenv"
|
||||||
|
|
|
@ -46,7 +46,7 @@ graft html-src
|
||||||
#graft data/images
|
#graft data/images
|
||||||
recursive-include data/images *.gif *.png *.jpg
|
recursive-include data/images *.gif *.png *.jpg
|
||||||
graft data/tiles
|
graft data/tiles
|
||||||
include data/pysol.xbm data/pysol.xpm data/pysol.ico data/PySol.icns
|
include data/pysol.ico data/PySol.icns
|
||||||
##
|
##
|
||||||
## data - sound
|
## data - sound
|
||||||
##
|
##
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
[[news]]
|
[[news]]
|
||||||
=== News
|
=== News
|
||||||
|
|
||||||
|
* _5 March, 2020:_ There is a new stable release
|
||||||
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.8.0/[PySolFC
|
||||||
|
v2.8.0]. New in this release:
|
||||||
|
** Better kivy/Android support
|
||||||
|
** Using ttk and configobj as shipped in the python dist (instead of forked versions)
|
||||||
|
** Requiring https://pypi.org/project/attrs/[attrs] and https://pypi.org/project/pysol-cards/[pysol-cards] from PyPI
|
||||||
|
** Added tests, bug fixes and refactorings.
|
||||||
|
** Add the +-g+ and +--deal+ command line options.
|
||||||
* _25 April, 2019:_ There is a new stable release
|
* _25 April, 2019:_ There is a new stable release
|
||||||
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.6.4/[PySolFC
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.6.4/[PySolFC
|
||||||
v2.6.4]. New in this release:
|
v2.6.4]. New in this release:
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
|
||||||
Prerequisites (needs root):
|
Prerequisites (needs root):
|
||||||
|
|
||||||
|
(For updated information on these subjects please consult the scripts in
|
||||||
|
android/debian).
|
||||||
|
|
||||||
On a 'freshly installed' Ubuntu 16.04 (32bit), the following
|
On a 'freshly installed' Ubuntu 16.04 (32bit), the following
|
||||||
additional packages had to be installed:
|
additional packages had to be installed:
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,17 @@ apt-get install -y \
|
||||||
lld
|
lld
|
||||||
|
|
||||||
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
|
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
|
||||||
|
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
imagemagick \
|
||||||
|
python3-tk \
|
||||||
|
ccache \
|
||||||
|
libltdl-dev
|
||||||
|
|
||||||
|
# set python3 as default.
|
||||||
|
# make python alternatives selectable.
|
||||||
|
# (debian stretch, adapt for different versions)
|
||||||
|
|
||||||
|
update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
|
||||||
|
update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,27 @@ set -eux
|
||||||
|
|
||||||
. mkp4a.common
|
. mkp4a.common
|
||||||
|
|
||||||
if [[ -d $sdkdir && -d $ndkdir ]]; then
|
urlbase=https://dl.google.com/android/repository/
|
||||||
echo "Skipping SDK and NDK installation: SDK and NDK directories already exist."
|
|
||||||
exit
|
if [[ -d $ndkdir ]]; then
|
||||||
|
echo "Skipping NDK installation: NDK directory already exists."
|
||||||
|
else
|
||||||
|
mkdir -p $ndkdir
|
||||||
|
ndk_zip=android-ndk-${ndkver}-linux-x86_64.zip
|
||||||
|
[ -a $ndk_zip ] || wget $urlbase/$ndk_zip
|
||||||
|
unzip -d $(dirname $ndkdir) $ndk_zip
|
||||||
fi
|
fi
|
||||||
|
|
||||||
urlbase=https://dl.google.com/android/repository/
|
if [[ -d $sdkdir ]]; then
|
||||||
tools_zip=sdk-tools-linux-4333796.zip
|
echo "Skipping SDK installation: SDK directory already exists."
|
||||||
ndk_zip=android-ndk-r17c-linux-x86_64.zip
|
else
|
||||||
|
mkdir -p $sdkdir
|
||||||
|
tools_zip=sdk-tools-linux-4333796.zip
|
||||||
|
[ -a $tools_zip ] || wget $urlbase/$tools_zip
|
||||||
|
unzip -d $sdkdir $tools_zip
|
||||||
|
|
||||||
mkdir -p $sdkdir $ndkdir
|
$sdkdir/tools/bin/sdkmanager 'platforms;android-27'
|
||||||
|
$sdkdir/tools/bin/sdkmanager 'build-tools;29.0.1'
|
||||||
|
fi
|
||||||
|
|
||||||
[ -a $ndk_zip ] || wget $urlbase/$ndk_zip
|
|
||||||
unzip -d $(dirname $ndkdir) $ndk_zip
|
|
||||||
|
|
||||||
[ -a $tools_zip ] || wget $urlbase/$tools_zip
|
|
||||||
unzip -d $sdkdir $tools_zip
|
|
||||||
|
|
||||||
$sdkdir/tools/bin/sdkmanager 'platforms;android-27'
|
|
||||||
$sdkdir/tools/bin/sdkmanager 'build-tools;29.0.1'
|
|
||||||
|
|
|
@ -8,8 +8,11 @@ tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
|
||||||
cardsets_dir='PySolFC-Cardsets--Minimal-2.0.1'
|
cardsets_dir='PySolFC-Cardsets--Minimal-2.0.1'
|
||||||
cardsets_file="${cardsets_dir}.tar.xz"
|
cardsets_file="${cardsets_dir}.tar.xz"
|
||||||
|
|
||||||
|
p4aver="2019.10.6"
|
||||||
|
ndkver="r19c"
|
||||||
|
|
||||||
sdkdir="${HOME}/.cache/sdk-for-p4a/sdk"
|
sdkdir="${HOME}/.cache/sdk-for-p4a/sdk"
|
||||||
ndkdir="${HOME}/.cache/sdk-for-p4a/android-ndk-r17c"
|
ndkdir="${HOME}/.cache/sdk-for-p4a/android-ndk-${ndkver}"
|
||||||
pkgdir="${HOME}/.local/share/python-for-android/packages"
|
pkgdir="${HOME}/.local/share/python-for-android/packages"
|
||||||
|
|
||||||
# gradle may need this.
|
# gradle may need this.
|
||||||
|
@ -27,7 +30,7 @@ p4a_options="\
|
||||||
--private ${tmpdir} \
|
--private ${tmpdir} \
|
||||||
--orientation sensor \
|
--orientation sensor \
|
||||||
--icon ${tmpdir}/data/images/icons/48x48/pysol.png \
|
--icon ${tmpdir}/data/images/icons/48x48/pysol.png \
|
||||||
--presplash ${tmpdir}/data/images/icons/1024x1024/pysol.png \
|
--presplash ${tmpdir}/data/images/logo-with-margin-1024.png \
|
||||||
--copy-libs \
|
--copy-libs \
|
||||||
--add-jar ${tmpdir}/support-v4-24.1.1.aar \
|
--add-jar ${tmpdir}/support-v4-24.1.1.aar \
|
||||||
--color always"
|
--color always"
|
||||||
|
|
|
@ -17,7 +17,16 @@ echo '### install p4a'
|
||||||
|
|
||||||
if [[ $# == 0 ]]
|
if [[ $# == 0 ]]
|
||||||
then
|
then
|
||||||
python3 -m pip install -q --user python-for-android
|
if not python3 -m pip install -q --user "python-for-android==${p4aver}"
|
||||||
|
then
|
||||||
|
echo "obviously inside a virtualenv, so omit --user"
|
||||||
|
if python3 -m pip install -q "python-for-android==${p4aver}"
|
||||||
|
then
|
||||||
|
echo "done"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "done"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo '### prepare source'
|
echo '### prepare source'
|
||||||
|
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
@ -1,20 +0,0 @@
|
||||||
#define pysol_width 41
|
|
||||||
#define pysol_height 40
|
|
||||||
static char pysol_bits[] = {
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x7c,
|
|
||||||
0x00,0x00,0xfe,0x00,0x00,0xff,0x01,0x00,0xfe,0x00,0x80,0xff,0x03,0x00,0xfe,
|
|
||||||
0x00,0xc0,0xff,0x07,0x00,0xfe,0x00,0xe0,0xff,0x0f,0x00,0xfe,0x00,0xe0,0xff,
|
|
||||||
0x0f,0x00,0xfe,0x00,0xf0,0xff,0x1f,0x00,0xfe,0x00,0xf0,0xff,0x1f,0x00,0xfe,
|
|
||||||
0x00,0xf0,0xff,0x1f,0x00,0xfe,0x00,0xf0,0xff,0x1f,0x00,0xfe,0x00,0xf0,0xff,
|
|
||||||
0x1f,0x00,0xfe,0x00,0xe0,0xff,0x0f,0x00,0xfe,0x00,0xe0,0xff,0x0f,0x00,0xfe,
|
|
||||||
0x00,0xc0,0xff,0x07,0x00,0xfe,0x00,0x9f,0xff,0xf3,0x01,0xfe,0xc0,0x7f,0xff,
|
|
||||||
0xfd,0x07,0xfe,0xe0,0xff,0x7c,0xfe,0x0f,0xfe,0xf0,0xff,0x39,0xff,0x1f,0xfe,
|
|
||||||
0xf8,0xff,0xbb,0xff,0x3f,0xfe,0xf8,0xff,0xbb,0xff,0x3f,0xfe,0xfc,0xff,0xff,
|
|
||||||
0xff,0x7f,0xfe,0xfc,0xff,0xff,0xff,0x7f,0xfe,0xfc,0xff,0xff,0xff,0x7f,0xfe,
|
|
||||||
0xfc,0xff,0xff,0xff,0x7f,0xfe,0xfc,0xff,0xff,0xff,0x7f,0xfe,0xf8,0xff,0xbb,
|
|
||||||
0xff,0x3f,0xfe,0xf8,0xff,0xbb,0xff,0x3f,0xfe,0xf0,0xff,0x39,0xff,0x1f,0xfe,
|
|
||||||
0xe0,0xff,0x39,0xfe,0x0f,0xfe,0xc0,0x7f,0x38,0xfc,0x07,0xfe,0x00,0x1f,0x7c,
|
|
||||||
0xf0,0x01,0xfe,0x00,0x00,0x7c,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xfe,
|
|
||||||
0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xff,0x01,0x00,0xfe,0x00,0x80,0xff,
|
|
||||||
0x03,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0xfe
|
|
||||||
};
|
|
|
@ -1,49 +0,0 @@
|
||||||
/* XPM */
|
|
||||||
static char *magick[] = {
|
|
||||||
/* columns rows colors chars-per-pixel */
|
|
||||||
"32 32 11 1",
|
|
||||||
" c Gray0",
|
|
||||||
". c #191919",
|
|
||||||
"X c Gray20",
|
|
||||||
"o c #4c4c4c",
|
|
||||||
"O c #666667",
|
|
||||||
"+ c Gray60",
|
|
||||||
"@ c #b2b2b2",
|
|
||||||
"# c Gray80",
|
|
||||||
"$ c Gray90",
|
|
||||||
"% c Gray100",
|
|
||||||
"& c None",
|
|
||||||
/* pixels */
|
|
||||||
"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&&&&+@@@&&&&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&&@o o@&&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&# #&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&# #&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&& &&&&&&&&&&",
|
|
||||||
"&&&&&&&&&+ @&&&&&&&&&",
|
|
||||||
"&&&&&&&&&o o&&&&&&&&&",
|
|
||||||
"&&&&&&&&&o o&&&&&&&&&",
|
|
||||||
"&&&&&&&&&o o&&&&&&&&&",
|
|
||||||
"&&&&&&&&&# #&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&. .&&&&&&&&&&",
|
|
||||||
"&&&&&&$$$$&X X&$$$$&&&&&&",
|
|
||||||
"&&&&$@ +@X X@+ @$&&&&",
|
|
||||||
"&&&&X .+@ @@ X&&&&",
|
|
||||||
"&&&X .&$ $& X&&&",
|
|
||||||
"&&o $ $ o&&",
|
|
||||||
"&&. + + .$&",
|
|
||||||
"&+ +&",
|
|
||||||
"&+ +&",
|
|
||||||
"&+ +&",
|
|
||||||
"&# O O #&",
|
|
||||||
"&&o $ $ o&&",
|
|
||||||
"&&$ @& &@ .$&&",
|
|
||||||
"&&&& .$& &&+ &&&&",
|
|
||||||
"&&&&$O o+&&+ +&&+o O$&&&&",
|
|
||||||
"&&&&&&@+@+&&&& &&&&+@+@&&&&&&",
|
|
||||||
"&&&&&&&&&&&&&O O&&&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&&&. .&&&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&$. .$&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&$+++@@@++$&&&&&&&&&&&",
|
|
||||||
"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"
|
|
||||||
};
|
|
|
@ -183,7 +183,7 @@ class Application:
|
||||||
try:
|
try:
|
||||||
approc = self.mainproc() # setup process
|
approc = self.mainproc() # setup process
|
||||||
approc.send(None) # and go
|
approc.send(None) # and go
|
||||||
except Exception:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def gameproc(self):
|
def gameproc(self):
|
||||||
|
|
|
@ -78,6 +78,11 @@ if TOOLKIT == 'tk':
|
||||||
else:
|
else:
|
||||||
from pysollib.pysoltk import reset_solver_dialog
|
from pysollib.pysoltk import reset_solver_dialog
|
||||||
|
|
||||||
|
# See: https://github.com/shlomif/PySolFC/issues/159 .
|
||||||
|
# 'factory=' is absent from older versions.
|
||||||
|
assert getattr(attr, '__version_info__', (0, 0, 0)) >= (18, 2, 0), (
|
||||||
|
"Newer version of https://pypi.org/project/attrs/ is required.")
|
||||||
|
|
||||||
|
|
||||||
PLAY_TIME_TIMEOUT = 200
|
PLAY_TIME_TIMEOUT = 200
|
||||||
S_PLAY = 0x40
|
S_PLAY = 0x40
|
||||||
|
|
|
@ -82,8 +82,10 @@ class Pyramid_StackMethods:
|
||||||
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
|
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
|
||||||
if not self.game.demo:
|
if not self.game.demo:
|
||||||
self.game.playSample("droppair", priority=200)
|
self.game.playSample("droppair", priority=200)
|
||||||
assert n == 1 and self.acceptsCards(
|
if not (n == 1
|
||||||
other_stack, [other_stack.cards[-1]])
|
and other_stack.cards
|
||||||
|
and self.acceptsCards(other_stack, [other_stack.cards[-1]])):
|
||||||
|
return
|
||||||
old_state = self.game.enterState(self.game.S_FILL)
|
old_state = self.game.enterState(self.game.S_FILL)
|
||||||
f = self.game.s.foundations[0]
|
f = self.game.s.foundations[0]
|
||||||
self.game.moveMove(n, self, f, frames=frames, shadow=shadow)
|
self.game.moveMove(n, self, f, frames=frames, shadow=shadow)
|
||||||
|
|
|
@ -31,6 +31,7 @@ from kivy.base import EventLoop
|
||||||
from kivy.base import stopTouchApp
|
from kivy.base import stopTouchApp
|
||||||
from kivy.cache import Cache
|
from kivy.cache import Cache
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
from kivy.config import Config
|
||||||
from kivy.core.audio import SoundLoader
|
from kivy.core.audio import SoundLoader
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.graphics import Color
|
from kivy.graphics import Color
|
||||||
|
@ -54,6 +55,9 @@ from kivy.utils import platform
|
||||||
|
|
||||||
from pysollib.kivy.androidperms import requestStoragePerm
|
from pysollib.kivy.androidperms import requestStoragePerm
|
||||||
|
|
||||||
|
if platform != 'android':
|
||||||
|
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@ -713,13 +717,27 @@ class LImageItem(BoxLayout, LBase):
|
||||||
# ev. noch globales cache für stacks->game und cards->stack
|
# ev. noch globales cache für stacks->game und cards->stack
|
||||||
# einrichten. Aber: stacks hängt vom jeweiligen spiel ab.
|
# einrichten. Aber: stacks hängt vom jeweiligen spiel ab.
|
||||||
|
|
||||||
def send_event_pressed_1(self, event):
|
def send_event_pressed_n(self, event, n):
|
||||||
if self.group and '<1>' in self.group.bindings:
|
if self.group and n in self.group.bindings:
|
||||||
self.group.bindings['<1>'](event)
|
self.group.bindings[n](event)
|
||||||
|
|
||||||
def send_event_pressed_double_1(self, event):
|
def send_event_pressed(self, touch, event):
|
||||||
if self.group and '<Double-1>' in self.group.bindings:
|
|
||||||
self.group.bindings['<Double-1>'](event)
|
if touch.is_double_tap:
|
||||||
|
self.send_event_pressed_n(event, '<Double-1>')
|
||||||
|
else:
|
||||||
|
button = 'left'
|
||||||
|
if 'button' in touch.profile:
|
||||||
|
button = touch.button
|
||||||
|
if button == 'left':
|
||||||
|
self.send_event_pressed_n(event, '<1>')
|
||||||
|
return
|
||||||
|
if button == 'middle':
|
||||||
|
self.send_event_pressed_n(event, '<2>')
|
||||||
|
return
|
||||||
|
if button == 'right':
|
||||||
|
self.send_event_pressed_n(event, '<3>')
|
||||||
|
return
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
|
|
||||||
|
@ -743,10 +761,7 @@ class LImageItem(BoxLayout, LBase):
|
||||||
event.y = ppos[1]
|
event.y = ppos[1]
|
||||||
self.dragstart = touch.pos
|
self.dragstart = touch.pos
|
||||||
event.cardid = i
|
event.cardid = i
|
||||||
if touch.is_double_tap:
|
self.send_event_pressed(touch, event)
|
||||||
self.send_event_pressed_double_1(event)
|
|
||||||
else:
|
|
||||||
self.send_event_pressed_1(event)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.group is not None:
|
if self.group is not None:
|
||||||
|
@ -1777,10 +1792,9 @@ class LApp(App):
|
||||||
|
|
||||||
def doSize(self, obj, val):
|
def doSize(self, obj, val):
|
||||||
mval = self.mainWindow.size
|
mval = self.mainWindow.size
|
||||||
logging.info("LApp: size changed %s - %s (%s)" % (obj, val, mval))
|
if (val[0] != mval[0] and val[1] != mval[1]):
|
||||||
# Clock.schedule_once(self.delayedRebuild, 0.01)
|
logging.info("LApp: size changed %s - %s (%s)" % (obj, val, mval))
|
||||||
Clock.schedule_once(self.makeDelayedRebuild(), 0.01)
|
Clock.schedule_once(self.makeDelayedRebuild(), 0.01)
|
||||||
# self.mainWindow.rebuildContainer()
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
|
|
|
@ -66,3 +66,9 @@ class KpatXmlEmitter:
|
||||||
|
|
||||||
def writeInitialLayout(self, state, turn_cb):
|
def writeInitialLayout(self, state, turn_cb):
|
||||||
assert False # unimpl
|
assert False # unimpl
|
||||||
|
|
||||||
|
|
||||||
|
class KpatEmitter:
|
||||||
|
"""docstring for KpatEmitter"""
|
||||||
|
def __init__(self, f):
|
||||||
|
self.f = f
|
||||||
|
|
|
@ -93,7 +93,7 @@ def parse_option(argv):
|
||||||
"sound-mod=",
|
"sound-mod=",
|
||||||
"help"])
|
"help"])
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
print_err(err + "\n" + _("try %s --help for more information") %
|
print_err(str(err) + "\n" + _("try %s --help for more information") %
|
||||||
prog_name, 0)
|
prog_name, 0)
|
||||||
return None
|
return None
|
||||||
opts = {"help": False,
|
opts = {"help": False,
|
||||||
|
@ -355,7 +355,10 @@ Please check your %(app)s installation.
|
||||||
if music:
|
if music:
|
||||||
app.music_playlist = list(music)[:]
|
app.music_playlist = list(music)[:]
|
||||||
app.miscrandom.shuffle(app.music_playlist)
|
app.miscrandom.shuffle(app.music_playlist)
|
||||||
if 1:
|
# Cancelling because otherwise people complain
|
||||||
|
# that the music order is not random.
|
||||||
|
SHOULD_PUT_bye_for_now_FIRST = False
|
||||||
|
if SHOULD_PUT_bye_for_now_FIRST:
|
||||||
for m in app.music_playlist:
|
for m in app.music_playlist:
|
||||||
if m.name.lower() == "bye_for_now":
|
if m.name.lower() == "bye_for_now":
|
||||||
app.music_playlist.remove(m)
|
app.music_playlist.remove(m)
|
||||||
|
|
|
@ -87,14 +87,7 @@ class PysolProgressBar:
|
||||||
im.show()
|
im.show()
|
||||||
im.set_property('xpad', 10)
|
im.set_property('xpad', 10)
|
||||||
im.set_property('ypad', 5)
|
im.set_property('ypad', 5)
|
||||||
# set icon
|
|
||||||
# if app:
|
|
||||||
# try:
|
|
||||||
# name = app.dataloader.findFile('pysol.xpm')
|
|
||||||
# bg = self.top.get_style().bg[gtk.STATE_NORMAL]
|
|
||||||
# pixmap, mask = create_pixmap_from_xpm(self.top, bg, name)
|
|
||||||
# self.top.set_icon(pixmap, mask)
|
|
||||||
# except: pass
|
|
||||||
setTransient(self.top, parent)
|
setTransient(self.top, parent)
|
||||||
self.top.show()
|
self.top.show()
|
||||||
self.top.window.set_cursor(gdk.Cursor(gdk.WATCH))
|
self.top.window.set_cursor(gdk.Cursor(gdk.WATCH))
|
||||||
|
|
|
@ -393,7 +393,6 @@ class SelectGameDialogWithPreview(MfxDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -165,12 +165,7 @@ class _MfxToplevel(gtk.Window):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def wm_iconbitmap(self, name):
|
def wm_iconbitmap(self, name):
|
||||||
print('wm_iconbitmap:', name)
|
pass
|
||||||
if name and name[0] == '@' and name[-4:] == '.xbm':
|
|
||||||
name = name[1:-4] + '.xpm'
|
|
||||||
# bg = self.get_style().bg[gtk.STATE_NORMAL]
|
|
||||||
# pixmap, mask = create_pixmap_from_xpm(self, bg, name)
|
|
||||||
# self.set_icon(pixmap, mask)
|
|
||||||
|
|
||||||
def wm_iconname(self, name):
|
def wm_iconname(self, name):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -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, 6, 4)
|
VERSION_TUPLE = (2, 8, 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)
|
||||||
|
|
|
@ -2935,9 +2935,10 @@ class FaceUpWasteTalonStack(WasteTalonStack):
|
||||||
self.game.fillStack(self)
|
self.game.fillStack(self)
|
||||||
|
|
||||||
def dealCards(self, sound=False):
|
def dealCards(self, sound=False):
|
||||||
WasteTalonStack.dealCards(self, sound=sound)
|
retval = WasteTalonStack.dealCards(self, sound=sound)
|
||||||
if self.canFlipCard():
|
if self.canFlipCard():
|
||||||
self.flipMove()
|
self.flipMove()
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
class OpenTalonStack(TalonStack, OpenStack):
|
class OpenTalonStack(TalonStack, OpenStack):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from . import ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from .tkwidget import MfxDialog
|
from .tkwidget import MfxDialog
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ from pysollib.ui.tktile.tkutil import bind
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
from six.moves import tkinter_font
|
from six.moves import tkinter_font
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog
|
from .tkwidget import MfxDialog
|
||||||
from .tkwidget import PysolScale
|
from .tkwidget import PysolScale
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ from pysollib.ui.tktile.menubar import MfxMenu, PysolMenubarTkCommon
|
||||||
from pysollib.ui.tktile.solverdialog import connect_game_solver_dialog
|
from pysollib.ui.tktile.solverdialog import connect_game_solver_dialog
|
||||||
from pysollib.util import CARDSET
|
from pysollib.util import CARDSET
|
||||||
|
|
||||||
from . import ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from .selectgame import SelectGameDialog, SelectGameDialogWithPreview
|
from .selectgame import SelectGameDialog, SelectGameDialogWithPreview
|
||||||
from .selecttile import SelectTileDialogWithPreview
|
from .selecttile import SelectTileDialogWithPreview
|
||||||
from .soundoptionsdialog import SoundOptionsDialog
|
from .soundoptionsdialog import SoundOptionsDialog
|
||||||
|
|
|
@ -25,8 +25,8 @@ from pysollib.mfxutil import KwStruct
|
||||||
from pysollib.mygettext import _
|
from pysollib.mygettext import _
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog
|
from .tkwidget import MfxDialog
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,7 @@ from pysollib.ui.tktile.tkconst import EVENT_HANDLED
|
||||||
from pysollib.ui.tktile.tkutil import makeToplevel, setTransient
|
from pysollib.ui.tktile.tkutil import makeToplevel, setTransient
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
from . import ttk
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
# * a simple progress bar
|
# * a simple progress bar
|
||||||
|
|
|
@ -32,8 +32,8 @@ from pysollib.ui.tktile.tkutil import loadImage
|
||||||
from pysollib.util import CARDSET
|
from pysollib.util import CARDSET
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .selecttree import SelectDialogTreeCanvas
|
from .selecttree import SelectDialogTreeCanvas
|
||||||
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
||||||
from .tkwidget import MfxDialog, MfxScrolledCanvas, PysolScale
|
from .tkwidget import MfxDialog, MfxScrolledCanvas, PysolScale
|
||||||
|
|
|
@ -32,8 +32,8 @@ from pysollib.ui.tktile.selecttree import SelectDialogTreeData
|
||||||
from pysollib.ui.tktile.tkutil import unbind_destroy
|
from pysollib.ui.tktile.tkutil import unbind_destroy
|
||||||
|
|
||||||
from six.moves import UserList
|
from six.moves import UserList
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .selecttree import SelectDialogTreeCanvas
|
from .selecttree import SelectDialogTreeCanvas
|
||||||
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
||||||
from .tkwidget import MfxDialog, MfxScrolledCanvas
|
from .tkwidget import MfxDialog, MfxScrolledCanvas
|
||||||
|
@ -319,13 +319,14 @@ class SelectGameDialog(MfxDialog):
|
||||||
if button == 0: # Ok or double click
|
if button == 0: # Ok or double click
|
||||||
self.gameid = self.tree.selection_key
|
self.gameid = self.tree.selection_key
|
||||||
self.tree.n_expansions = 1 # save xyview in any case
|
self.tree.n_expansions = 1 # save xyview in any case
|
||||||
if button == 1: # Rules
|
if button == 10: # Rules
|
||||||
doc = self.app.getGameRulesFilename(self.tree.selection_key)
|
doc = self.app.getGameRulesFilename(self.tree.selection_key)
|
||||||
if not doc:
|
if not doc:
|
||||||
return
|
return
|
||||||
dir = os.path.join("html", "rules")
|
dir = os.path.join("html", "rules")
|
||||||
from pysollib.help import help_html
|
from pysollib.help import help_html
|
||||||
help_html(self.app, doc, dir, self.top)
|
help_html(self.app, doc, dir, self.top)
|
||||||
|
self.top.grab_release() # Don't want the help window appear frozen
|
||||||
return
|
return
|
||||||
MfxDialog.mDone(self, button)
|
MfxDialog.mDone(self, button)
|
||||||
|
|
||||||
|
@ -483,7 +484,6 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -28,8 +28,8 @@ from pysollib.ui.tktile.selecttree import SelectDialogTreeData
|
||||||
import six
|
import six
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
from six.moves import tkinter_colorchooser
|
from six.moves import tkinter_colorchooser
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .selecttree import SelectDialogTreeCanvas
|
from .selecttree import SelectDialogTreeCanvas
|
||||||
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
||||||
from .tkwidget import MfxDialog, MfxScrolledCanvas
|
from .tkwidget import MfxDialog, MfxScrolledCanvas
|
||||||
|
|
|
@ -30,8 +30,8 @@ from pysollib.settings import TITLE
|
||||||
from pysollib.ui.tktile.tkconst import EVENT_HANDLED
|
from pysollib.ui.tktile.tkconst import EVENT_HANDLED
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog, MfxMessageDialog
|
from .tkwidget import MfxDialog, MfxMessageDialog
|
||||||
from .tkwidget import PysolScale
|
from .tkwidget import PysolScale
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ from pysollib.mygettext import _
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxTooltip
|
from .tkwidget import MfxTooltip
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -25,8 +25,8 @@ from pysollib.mfxutil import KwStruct
|
||||||
from pysollib.mygettext import _
|
from pysollib.mygettext import _
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog, PysolScale
|
from .tkwidget import MfxDialog, PysolScale
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ from pysollib.mygettext import _
|
||||||
from pysollib.ui.tktile.tkhtml import Base_HTMLViewer
|
from pysollib.ui.tktile.tkhtml import Base_HTMLViewer
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .statusbar import HtmlStatusbar
|
from .statusbar import HtmlStatusbar
|
||||||
from .tkwidget import MfxMessageDialog
|
from .tkwidget import MfxMessageDialog
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ from pysollib.ui.tktile.tkutil import bind, loadImage
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
from six.moves import tkinter_font
|
from six.moves import tkinter_font
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog, MfxMessageDialog
|
from .tkwidget import MfxDialog, MfxMessageDialog
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,7 @@ import six
|
||||||
from six import PY2
|
from six import PY2
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
from six.moves import tkinter_font
|
from six.moves import tkinter_font
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
from . import ttk
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
# * abstract base class for the dialogs in this module
|
# * abstract base class for the dialogs in this module
|
||||||
|
|
|
@ -33,8 +33,8 @@ from pysollib.util import IMAGE_EXTENSIONS
|
||||||
from pysollib.winsystems import TkSettings
|
from pysollib.winsystems import TkSettings
|
||||||
|
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxTooltip
|
from .tkwidget import MfxTooltip
|
||||||
|
|
||||||
|
|
||||||
|
|
1555
pysollib/tile/ttk.py
1555
pysollib/tile/ttk.py
File diff suppressed because it is too large
Load diff
|
@ -28,8 +28,8 @@ from pysollib.wizardutil import WizardWidgets
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import tkinter
|
from six.moves import tkinter
|
||||||
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
from . import ttk
|
|
||||||
from .tkwidget import MfxDialog
|
from .tkwidget import MfxDialog
|
||||||
from .tkwidget import PysolCombo, PysolScale
|
from .tkwidget import PysolCombo, PysolScale
|
||||||
|
|
||||||
|
|
|
@ -484,7 +484,6 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -156,7 +156,7 @@ class PysolStatusbar(MfxStatusbar):
|
||||||
self._createLabel(n, tooltip=t, width=w)
|
self._createLabel(n, tooltip=t, width=w)
|
||||||
#
|
#
|
||||||
label = self._createLabel('info', expand=True)
|
label = self._createLabel('info', expand=True)
|
||||||
label.config(padding=(8, 0))
|
label.config(padx=8)
|
||||||
|
|
||||||
|
|
||||||
class HelpStatusbar(MfxStatusbar):
|
class HelpStatusbar(MfxStatusbar):
|
||||||
|
|
|
@ -110,7 +110,7 @@ def makeToplevel(parent, title=None):
|
||||||
def make_help_toplevel(app, title=None):
|
def make_help_toplevel(app, title=None):
|
||||||
# Create an independent Toplevel window.
|
# Create an independent Toplevel window.
|
||||||
from pysollib.winsystems import init_root_window
|
from pysollib.winsystems import init_root_window
|
||||||
window = tkinter.Tk(className=TITLE)
|
window = tkinter.Toplevel(class_=TITLE)
|
||||||
init_root_window(window, app)
|
init_root_window(window, app)
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
|
|
@ -161,11 +161,22 @@ class DataLoader:
|
||||||
raise OSError("DataLoader could not find image "+filename +
|
raise OSError("DataLoader could not find image "+filename +
|
||||||
" in "+self.dir+" "+str(subdirs))
|
" in "+self.dir+" "+str(subdirs))
|
||||||
|
|
||||||
def findIcon(self, filename='pysol', subdirs=None):
|
def findAllIconSizes(self, filename='pysol.png'):
|
||||||
root, ext = os.path.splitext(filename)
|
try:
|
||||||
if not ext:
|
icondir = self.findDir(os.path.join('images', 'icons'))
|
||||||
filename += ('.ico' if os.name == 'nt' else '.xbm')
|
icons = [os.path.join(icondir, subdir, filename) for subdir in
|
||||||
return self.findFile(filename, subdirs)
|
os.listdir(icondir)]
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
# pysol06.png is known to have transparent borders around it
|
||||||
|
# which is unsuitable for a window icon
|
||||||
|
icon_blacklist = ('pysol06.png',)
|
||||||
|
miscdir = self.findDir(os.path.join('images', 'misc'))
|
||||||
|
icons = [os.path.join(miscdir, f) for f in os.listdir(miscdir)
|
||||||
|
if f not in icon_blacklist]
|
||||||
|
except OSError:
|
||||||
|
icons = []
|
||||||
|
return filter(os.path.isfile, icons)
|
||||||
|
|
||||||
def findDir(self, filename, subdirs=None):
|
def findDir(self, filename, subdirs=None):
|
||||||
return self.__findFile(os.path.isdir, filename, subdirs)
|
return self.__findFile(os.path.isdir, filename, subdirs)
|
||||||
|
|
|
@ -25,11 +25,6 @@ from pysollib.macosx.appSupport import hideTkConsole
|
||||||
from pysollib.settings import TOOLKIT, USE_TILE
|
from pysollib.settings import TOOLKIT, USE_TILE
|
||||||
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
|
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
|
||||||
|
|
||||||
from six.moves import tkinter
|
|
||||||
|
|
||||||
if USE_TILE:
|
|
||||||
from pysollib.tile import ttk
|
|
||||||
|
|
||||||
|
|
||||||
def init_root_window(root, app):
|
def init_root_window(root, app):
|
||||||
base_init_root_window(root, app)
|
base_init_root_window(root, app)
|
||||||
|
@ -38,15 +33,7 @@ def init_root_window(root, app):
|
||||||
if TOOLKIT == 'gtk':
|
if TOOLKIT == 'gtk':
|
||||||
pass
|
pass
|
||||||
elif USE_TILE:
|
elif USE_TILE:
|
||||||
style = ttk.Style(root)
|
pass
|
||||||
color = style.lookup('.', 'background')
|
|
||||||
if color:
|
|
||||||
root.tk_setPalette(color) # for non-ttk widgets
|
|
||||||
|
|
||||||
if app.opt.tile_theme == 'aqua':
|
|
||||||
# standard Tk scrollbars work on OS X, but ttk ones look weird
|
|
||||||
ttk.Scrollbar = tkinter.Scrollbar
|
|
||||||
|
|
||||||
else: # pure Tk
|
else: # pure Tk
|
||||||
# root.option_add(...)
|
# root.option_add(...)
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -32,8 +32,9 @@ from pysollib.settings import TOOLKIT, USE_TILE
|
||||||
from pysollib.settings import VERSION
|
from pysollib.settings import VERSION
|
||||||
|
|
||||||
if TOOLKIT == 'tk':
|
if TOOLKIT == 'tk':
|
||||||
|
from pysollib.ui.tktile.tkutil import loadImage
|
||||||
if USE_TILE:
|
if USE_TILE:
|
||||||
from pysollib.tile import ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
|
|
||||||
def init_tile(app, top):
|
def init_tile(app, top):
|
||||||
|
@ -89,6 +90,15 @@ def base_init_root_window(root, app):
|
||||||
# root.wm_group(root)
|
# root.wm_group(root)
|
||||||
root.wm_title(TITLE + ' ' + VERSION)
|
root.wm_title(TITLE + ' ' + VERSION)
|
||||||
root.wm_iconname(TITLE + ' ' + VERSION)
|
root.wm_iconname(TITLE + ' ' + VERSION)
|
||||||
|
|
||||||
|
if TOOLKIT == 'tk':
|
||||||
|
icons = [loadImage(img) for img in app.dataloader.findAllIconSizes()]
|
||||||
|
if icons:
|
||||||
|
try:
|
||||||
|
root.wm_iconphoto(True, *icons)
|
||||||
|
except AttributeError:
|
||||||
|
root.tk.call('wm', 'iconphoto', root, '-default', *icons)
|
||||||
|
|
||||||
# set minsize
|
# set minsize
|
||||||
sw, sh = (root.winfo_screenwidth(), root.winfo_screenheight())
|
sw, sh = (root.winfo_screenwidth(), root.winfo_screenheight())
|
||||||
if sw < 640 or sh < 480:
|
if sw < 640 or sh < 480:
|
||||||
|
|
|
@ -25,7 +25,7 @@ from pysollib.settings import TOOLKIT, USE_TILE
|
||||||
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
|
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
|
||||||
|
|
||||||
if USE_TILE:
|
if USE_TILE:
|
||||||
from pysollib.tile import ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
|
|
||||||
def init_root_window(root, app):
|
def init_root_window(root, app):
|
||||||
|
|
|
@ -33,7 +33,7 @@ from pysollib.winsystems.common import \
|
||||||
|
|
||||||
if TOOLKIT == 'tk':
|
if TOOLKIT == 'tk':
|
||||||
if USE_TILE:
|
if USE_TILE:
|
||||||
from pysollib.tile import ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
@ -44,10 +44,6 @@ def init_root_window(root, app):
|
||||||
|
|
||||||
base_init_root_window(root, app)
|
base_init_root_window(root, app)
|
||||||
|
|
||||||
# if TOOLKIT == 'tk':
|
|
||||||
# window.wm_iconbitmap("@"+filename)
|
|
||||||
# window.wm_iconmask("@"+filename)
|
|
||||||
|
|
||||||
# root.self.wm_maxsize(9999, 9999) # unlimited
|
# root.self.wm_maxsize(9999, 9999) # unlimited
|
||||||
if TOOLKIT == 'gtk':
|
if TOOLKIT == 'gtk':
|
||||||
pass
|
pass
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -50,7 +50,6 @@ for d in ddirs:
|
||||||
data_files += get_data_files('locale', locale_dir)
|
data_files += get_data_files('locale', locale_dir)
|
||||||
|
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
data_files.append(('share/pixmaps', ['data/pysol.xbm', 'data/pysol.xpm']))
|
|
||||||
for size in os.listdir('data/images/icons'):
|
for size in os.listdir('data/images/icons'):
|
||||||
data_files.append(('share/icons/hicolor/%s/apps' % size,
|
data_files.append(('share/icons/hicolor/%s/apps' % size,
|
||||||
['data/images/icons/%s/pysol.png' % size]))
|
['data/images/icons/%s/pysol.png' % size]))
|
||||||
|
|
|
@ -3,6 +3,7 @@ import unittest
|
||||||
|
|
||||||
from pysollib.acard import AbstractCard
|
from pysollib.acard import AbstractCard
|
||||||
from pysollib.kpat_load_save import KpatXmlEmitter
|
from pysollib.kpat_load_save import KpatXmlEmitter
|
||||||
|
from pysollib.kpat_load_save import KpatEmitter
|
||||||
|
|
||||||
from six.moves import cStringIO
|
from six.moves import cStringIO
|
||||||
|
|
||||||
|
@ -83,3 +84,5 @@ class MyTests(unittest.TestCase):
|
||||||
+ "<card id=\"1004\" suit=\"hearts\" " +
|
+ "<card id=\"1004\" suit=\"hearts\" " +
|
||||||
"rank=\"queen\" turn=\"face-up\"/>\n"
|
"rank=\"queen\" turn=\"face-up\"/>\n"
|
||||||
)
|
)
|
||||||
|
e = KpatEmitter(f)
|
||||||
|
self.assertTrue(e)
|
||||||
|
|
|
@ -53,10 +53,12 @@
|
||||||
# imports
|
# imports
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from pysol_cards.cards import ms_rearrange
|
from pysol_cards.cards import CardRenderer
|
||||||
|
from pysol_cards.deal_game import Game
|
||||||
|
from pysol_cards.random_base import RandomBase
|
||||||
|
|
||||||
# So the localpaths will be overrided.
|
# So the localpaths will be overrided.
|
||||||
from pysollib.pysolrandom import LCRandom31, constructRandom, \
|
from pysollib.pysolrandom import constructRandom, \
|
||||||
random__long2str, random__str2long
|
random__long2str, random__str2long
|
||||||
|
|
||||||
# PySol imports
|
# PySol imports
|
||||||
|
@ -68,497 +70,7 @@ from pysollib.pysolrandom import LCRandom31, constructRandom, \
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
class Card:
|
ren = CardRenderer(True)
|
||||||
|
|
||||||
ACE = 1
|
|
||||||
KING = 13
|
|
||||||
|
|
||||||
def __init__(self, id, rank, suit, print_ts):
|
|
||||||
self.id = id
|
|
||||||
self.rank = rank
|
|
||||||
self.suit = suit
|
|
||||||
self.flipped = False
|
|
||||||
self.print_ts = print_ts
|
|
||||||
self.empty = False
|
|
||||||
|
|
||||||
def is_king(self):
|
|
||||||
return self.rank == self.KING
|
|
||||||
|
|
||||||
def is_ace(self):
|
|
||||||
return self.rank == self.ACE
|
|
||||||
|
|
||||||
def rank_s(self):
|
|
||||||
s = "0A23456789TJQK"[self.rank]
|
|
||||||
if (not self.print_ts) and s == "T":
|
|
||||||
s = "10"
|
|
||||||
return s
|
|
||||||
|
|
||||||
def suit_s(self):
|
|
||||||
return "CSHD"[self.suit]
|
|
||||||
|
|
||||||
def to_s(self):
|
|
||||||
if self.empty:
|
|
||||||
return "-"
|
|
||||||
ret = ""
|
|
||||||
ret = ret + self.rank_s()
|
|
||||||
ret = ret + self.suit_s()
|
|
||||||
if self.flipped:
|
|
||||||
ret = "<" + ret + ">"
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def found_s(self):
|
|
||||||
return self.suit_s() + "-" + self.rank_s()
|
|
||||||
|
|
||||||
def flip(self, flipped=True):
|
|
||||||
new_card = Card(self.id, self.rank, self.suit, self.print_ts)
|
|
||||||
new_card.flipped = flipped
|
|
||||||
return new_card
|
|
||||||
|
|
||||||
def is_empty(self):
|
|
||||||
return self.empty
|
|
||||||
|
|
||||||
|
|
||||||
class Columns:
|
|
||||||
|
|
||||||
def __init__(self, num):
|
|
||||||
self.num = num
|
|
||||||
cols = []
|
|
||||||
for i in range(num):
|
|
||||||
cols.append([])
|
|
||||||
|
|
||||||
self.cols = cols
|
|
||||||
|
|
||||||
def add(self, idx, card):
|
|
||||||
self.cols[idx].append(card)
|
|
||||||
|
|
||||||
def rev(self):
|
|
||||||
self.cols.reverse()
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
s = ''
|
|
||||||
for column in self.cols:
|
|
||||||
s += column_to_string(column) + "\n"
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
class Board:
|
|
||||||
def __init__(self, num_columns, with_freecells=False,
|
|
||||||
with_talon=False, with_foundations=False):
|
|
||||||
self.with_freecells = with_freecells
|
|
||||||
self.with_talon = with_talon
|
|
||||||
self.with_foundations = with_foundations
|
|
||||||
self.columns = Columns(num_columns)
|
|
||||||
if (self.with_freecells):
|
|
||||||
self.freecells = []
|
|
||||||
if (self.with_talon):
|
|
||||||
self.talon = []
|
|
||||||
if (self.with_foundations):
|
|
||||||
self.foundations = map(lambda s: empty_card(), range(4))
|
|
||||||
|
|
||||||
def reverse_cols(self):
|
|
||||||
return self.columns.rev()
|
|
||||||
|
|
||||||
def add(self, idx, card):
|
|
||||||
return self.columns.add(idx, card)
|
|
||||||
|
|
||||||
def print_freecells(self):
|
|
||||||
return "FC: " + column_to_string(self.freecells)
|
|
||||||
|
|
||||||
def print_talon(self):
|
|
||||||
return "Talon: " + column_to_string(self.talon)
|
|
||||||
|
|
||||||
def print_foundations(self):
|
|
||||||
cells = []
|
|
||||||
for f in [2, 0, 3, 1]:
|
|
||||||
if not self.foundations[f].is_empty():
|
|
||||||
cells.append(self.foundations[f].found_s())
|
|
||||||
|
|
||||||
if len(cells):
|
|
||||||
return "Foundations:" + ("".join(map(lambda s: " "+s, cells)))
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
s = ''
|
|
||||||
if (self.with_talon):
|
|
||||||
s += self.print_talon() + "\n"
|
|
||||||
if (self.with_foundations):
|
|
||||||
s += self.print_foundations() + "\n"
|
|
||||||
if (self.with_freecells):
|
|
||||||
s += self.print_freecells() + "\n"
|
|
||||||
s += self.columns.output()
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def add_freecell(self, card):
|
|
||||||
if not self.with_freecells:
|
|
||||||
raise AttributeError("Layout does not have freecells!")
|
|
||||||
self.freecells.append(card)
|
|
||||||
|
|
||||||
def add_talon(self, card):
|
|
||||||
if not self.with_talon:
|
|
||||||
raise AttributeError("Layout does not have a talon!")
|
|
||||||
|
|
||||||
self.talon.append(card)
|
|
||||||
|
|
||||||
def put_into_founds(self, card):
|
|
||||||
if not self.with_foundations:
|
|
||||||
raise AttributeError("Layout does not have foundations!")
|
|
||||||
|
|
||||||
if ((self.foundations[card.suit].rank+1) == card.rank):
|
|
||||||
self.foundations[card.suit] = card
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
self.talon.append(card)
|
|
||||||
|
|
||||||
|
|
||||||
def empty_card():
|
|
||||||
ret = Card(0, 0, 0, 1)
|
|
||||||
ret.empty = True
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def createCards(num_decks, print_ts):
|
|
||||||
cards = []
|
|
||||||
for deck in range(num_decks):
|
|
||||||
id = 0
|
|
||||||
for suit in range(4):
|
|
||||||
for rank in range(13):
|
|
||||||
cards.append(Card(id, rank+1, suit, print_ts))
|
|
||||||
id = id + 1
|
|
||||||
return cards
|
|
||||||
|
|
||||||
|
|
||||||
def column_to_list_of_strings(col):
|
|
||||||
return map(lambda c: c.to_s(), col)
|
|
||||||
|
|
||||||
|
|
||||||
def column_to_string(col):
|
|
||||||
return " ".join(column_to_list_of_strings(col))
|
|
||||||
|
|
||||||
|
|
||||||
def flip_card(card_str, flip):
|
|
||||||
if flip:
|
|
||||||
return "<" + card_str + ">"
|
|
||||||
else:
|
|
||||||
return card_str
|
|
||||||
|
|
||||||
|
|
||||||
def shuffle(orig_cards, rand):
|
|
||||||
shuffled_cards = list(orig_cards)
|
|
||||||
if isinstance(rand, LCRandom31):
|
|
||||||
shuffled_cards = ms_rearrange(shuffled_cards)
|
|
||||||
# rand.shuffle works in place
|
|
||||||
rand.shuffle(shuffled_cards)
|
|
||||||
return shuffled_cards
|
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
|
||||||
REVERSE_MAP = \
|
|
||||||
{
|
|
||||||
"freecell":
|
|
||||||
["freecell", "forecell", "bakers_game",
|
|
||||||
"ko_bakers_game", "kings_only_bakers_game",
|
|
||||||
"relaxed_freecell", "eight_off"],
|
|
||||||
"der_katz":
|
|
||||||
["der_katz", "der_katzenschwantz", "die_schlange"],
|
|
||||||
"seahaven":
|
|
||||||
["seahaven_towers", "seahaven", "relaxed_seahaven",
|
|
||||||
"relaxed_seahaven_towers"],
|
|
||||||
"bakers_dozen": None,
|
|
||||||
"gypsy": None,
|
|
||||||
"klondike": ["klondike", "klondike_by_threes",
|
|
||||||
"casino_klondike", "small_harp",
|
|
||||||
"thumb_and_pouch", "vegas_klondike", "whitehead"],
|
|
||||||
"simple_simon": None,
|
|
||||||
"yukon": None,
|
|
||||||
"beleaguered_castle": ["beleaguered_castle",
|
|
||||||
"streets_and_alleys", "citadel"],
|
|
||||||
"fan": None,
|
|
||||||
"black_hole": None,
|
|
||||||
"all_in_a_row": None,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, game_id, rand, print_ts):
|
|
||||||
mymap = {}
|
|
||||||
for k in self.REVERSE_MAP.keys():
|
|
||||||
if self.REVERSE_MAP[k] is None:
|
|
||||||
mymap[k] = k
|
|
||||||
else:
|
|
||||||
for alias in self.REVERSE_MAP[k]:
|
|
||||||
mymap[alias] = k
|
|
||||||
self.games_map = mymap
|
|
||||||
self.game_id = game_id
|
|
||||||
self.print_ts = print_ts
|
|
||||||
self.rand = rand
|
|
||||||
|
|
||||||
def print_layout(self):
|
|
||||||
game_class = self.lookup()
|
|
||||||
|
|
||||||
if not game_class:
|
|
||||||
raise ValueError("Unknown game type " + self.game_id + "\n")
|
|
||||||
|
|
||||||
self.deal()
|
|
||||||
|
|
||||||
getattr(self, game_class)()
|
|
||||||
|
|
||||||
return self.board.output()
|
|
||||||
|
|
||||||
def lookup(self):
|
|
||||||
return self.games_map[self.game_id]
|
|
||||||
|
|
||||||
def is_two_decks(self):
|
|
||||||
return self.game_id in ("der_katz", "der_katzenschwantz",
|
|
||||||
"die_schlange", "gypsy")
|
|
||||||
|
|
||||||
def get_num_decks(self):
|
|
||||||
if self.is_two_decks():
|
|
||||||
return 2
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def deal(self):
|
|
||||||
orig_cards = createCards(self.get_num_decks(), self.print_ts)
|
|
||||||
|
|
||||||
orig_cards = shuffle(orig_cards, self.rand)
|
|
||||||
|
|
||||||
cards = orig_cards
|
|
||||||
cards.reverse()
|
|
||||||
|
|
||||||
self.cards = cards
|
|
||||||
self.card_idx = 0
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def no_more_cards(self):
|
|
||||||
return self.card_idx >= len(self.cards)
|
|
||||||
|
|
||||||
def next(self):
|
|
||||||
if self.no_more_cards():
|
|
||||||
raise StopIteration
|
|
||||||
c = self.cards[self.card_idx]
|
|
||||||
self.card_idx = self.card_idx + 1
|
|
||||||
return c
|
|
||||||
|
|
||||||
def new_cards(self, cards):
|
|
||||||
self.cards = cards
|
|
||||||
self.card_idx = 0
|
|
||||||
|
|
||||||
def add(self, idx, card):
|
|
||||||
return self.board.add(idx, card)
|
|
||||||
|
|
||||||
def add_freecell(self, card):
|
|
||||||
return self.board.add_freecell(card)
|
|
||||||
|
|
||||||
def cyclical_deal(game, num_cards, num_cols, flipped=False):
|
|
||||||
for i in range(num_cards):
|
|
||||||
game.add(i % num_cols, game.next().flip(flipped=flipped))
|
|
||||||
return i
|
|
||||||
|
|
||||||
def add_all_to_talon(game):
|
|
||||||
for card in game:
|
|
||||||
game.board.add_talon(card)
|
|
||||||
|
|
||||||
# These are the games variants:
|
|
||||||
# Each one is a callback.
|
|
||||||
def der_katz(game):
|
|
||||||
if (game.game_id == "die_schlange"):
|
|
||||||
return "Foundations: H-A S-A D-A C-A H-A S-A D-A C-A"
|
|
||||||
|
|
||||||
game.board = Board(9)
|
|
||||||
col_idx = 0
|
|
||||||
|
|
||||||
for card in game:
|
|
||||||
if card.is_king():
|
|
||||||
col_idx = col_idx + 1
|
|
||||||
if not ((game.game_id == "die_schlange") and (card.rank == 1)):
|
|
||||||
game.add(col_idx, card)
|
|
||||||
|
|
||||||
def freecell(game):
|
|
||||||
is_fc = (game.game_id in ('forecell', 'eight_off'))
|
|
||||||
|
|
||||||
game.board = Board(8, with_freecells=is_fc)
|
|
||||||
|
|
||||||
if is_fc:
|
|
||||||
game.cyclical_deal(48, 8)
|
|
||||||
for card in game:
|
|
||||||
game.add_freecell(card)
|
|
||||||
if game.game_id == "eight_off":
|
|
||||||
game.add_freecell(empty_card())
|
|
||||||
else:
|
|
||||||
game.cyclical_deal(52, 8)
|
|
||||||
|
|
||||||
def seahaven(game):
|
|
||||||
game.board = Board(10, with_freecells=True)
|
|
||||||
|
|
||||||
game.add_freecell(empty_card())
|
|
||||||
|
|
||||||
game.cyclical_deal(50, 10)
|
|
||||||
|
|
||||||
for card in game:
|
|
||||||
game.add_freecell(card)
|
|
||||||
|
|
||||||
def bakers_dozen(game):
|
|
||||||
i, n = 0, 13
|
|
||||||
kings = []
|
|
||||||
cards = game.cards
|
|
||||||
cards.reverse()
|
|
||||||
for c in cards:
|
|
||||||
if c.is_king():
|
|
||||||
kings.append(i)
|
|
||||||
i = i + 1
|
|
||||||
for i in kings:
|
|
||||||
j = i % n
|
|
||||||
while j < i:
|
|
||||||
if not cards[j].is_king():
|
|
||||||
cards[i], cards[j] = cards[j], cards[i]
|
|
||||||
break
|
|
||||||
j = j + n
|
|
||||||
|
|
||||||
game.new_cards(cards)
|
|
||||||
|
|
||||||
game.board = Board(13)
|
|
||||||
|
|
||||||
game.cyclical_deal(52, 13)
|
|
||||||
|
|
||||||
def gypsy(game):
|
|
||||||
num_cols = 8
|
|
||||||
game.board = Board(num_cols, with_talon=True)
|
|
||||||
|
|
||||||
game.cyclical_deal(num_cols*2, num_cols, flipped=True)
|
|
||||||
game.cyclical_deal(num_cols, num_cols, flipped=False)
|
|
||||||
|
|
||||||
game.add_all_to_talon()
|
|
||||||
|
|
||||||
def klondike(game):
|
|
||||||
num_cols = 7
|
|
||||||
game.board = Board(num_cols, with_talon=True)
|
|
||||||
|
|
||||||
for r in range(1, num_cols):
|
|
||||||
for s in range(num_cols-r):
|
|
||||||
game.add(s, game.next().flip())
|
|
||||||
|
|
||||||
game.cyclical_deal(num_cols, num_cols)
|
|
||||||
|
|
||||||
game.add_all_to_talon()
|
|
||||||
|
|
||||||
if not (game.game_id == "small_harp"):
|
|
||||||
game.board.reverse_cols()
|
|
||||||
|
|
||||||
def simple_simon(game):
|
|
||||||
game.board = Board(10)
|
|
||||||
|
|
||||||
num_cards = 9
|
|
||||||
|
|
||||||
while num_cards >= 3:
|
|
||||||
for s in range(num_cards):
|
|
||||||
game.add(s, game.next())
|
|
||||||
num_cards = num_cards - 1
|
|
||||||
|
|
||||||
for s in range(10):
|
|
||||||
game.add(s, game.next())
|
|
||||||
|
|
||||||
def fan(game):
|
|
||||||
game.board = Board(18)
|
|
||||||
|
|
||||||
game.cyclical_deal(52-1, 17)
|
|
||||||
|
|
||||||
game.add(17, game.next())
|
|
||||||
|
|
||||||
def _shuffleHookMoveSorter(self, cards, func, ncards):
|
|
||||||
# note that we reverse the cards, so that smaller sort_orders
|
|
||||||
# will be nearer to the top of the Talon
|
|
||||||
sitems, i = [], len(cards)
|
|
||||||
for c in cards[:]:
|
|
||||||
select, sort_order = func(c)
|
|
||||||
if select:
|
|
||||||
cards.remove(c)
|
|
||||||
sitems.append((sort_order, i, c))
|
|
||||||
if len(sitems) >= ncards:
|
|
||||||
break
|
|
||||||
i = i - 1
|
|
||||||
sitems.sort()
|
|
||||||
sitems.reverse()
|
|
||||||
scards = map(lambda item: item[2], sitems)
|
|
||||||
return cards, scards
|
|
||||||
|
|
||||||
def _shuffleHookMoveToBottom(self, cards, func, ncards=999999):
|
|
||||||
# move cards to bottom of the Talon (i.e. last cards to be dealt)
|
|
||||||
cards, scards = self._shuffleHookMoveSorter(cards, func, ncards)
|
|
||||||
ret = scards + cards
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def _shuffleHookMoveToTop(self, cards, func, ncards=999999):
|
|
||||||
# move cards to top of the Talon (i.e. last cards to be dealt)
|
|
||||||
cards, scards = self._shuffleHookMoveSorter(cards, func, ncards)
|
|
||||||
return cards + scards
|
|
||||||
|
|
||||||
def black_hole(game):
|
|
||||||
game.board = Board(17)
|
|
||||||
|
|
||||||
# move Ace to bottom of the Talon (i.e. last cards to be dealt)
|
|
||||||
game.cards = game._shuffleHookMoveToBottom(
|
|
||||||
game.cards, lambda c: (c.id == 13, c.suit), 1)
|
|
||||||
game.next()
|
|
||||||
game.cyclical_deal(52-1, 17)
|
|
||||||
|
|
||||||
return "Foundations: AS"
|
|
||||||
|
|
||||||
def all_in_a_row(game):
|
|
||||||
game.board = Board(13)
|
|
||||||
|
|
||||||
# move Ace to bottom of the Talon (i.e. last cards to be dealt)
|
|
||||||
game.cards = game._shuffleHookMoveToTop(
|
|
||||||
game.cards, lambda c: (c.id == 13, c.suit), 1)
|
|
||||||
game.cyclical_deal(52, 13)
|
|
||||||
return "Foundations: -"
|
|
||||||
|
|
||||||
def beleaguered_castle(game):
|
|
||||||
aces_up = game.game_id in ("beleaguered_castle", "citadel")
|
|
||||||
|
|
||||||
game.board = Board(8, with_foundations=True)
|
|
||||||
|
|
||||||
if aces_up:
|
|
||||||
new_cards = []
|
|
||||||
|
|
||||||
for c in game:
|
|
||||||
if c.is_ace():
|
|
||||||
game.board.put_into_founds(c)
|
|
||||||
else:
|
|
||||||
new_cards.append(c)
|
|
||||||
|
|
||||||
game.new_cards(new_cards)
|
|
||||||
|
|
||||||
for i in range(6):
|
|
||||||
for s in range(8):
|
|
||||||
c = game.next()
|
|
||||||
if (game.game_id == "citadel") and \
|
|
||||||
game.board.put_into_founds(c):
|
|
||||||
# Already dealt with this card
|
|
||||||
True
|
|
||||||
else:
|
|
||||||
game.add(s, c)
|
|
||||||
if game.no_more_cards():
|
|
||||||
break
|
|
||||||
|
|
||||||
if (game.game_id == "streets_and_alleys"):
|
|
||||||
game.cyclical_deal(4, 4)
|
|
||||||
|
|
||||||
def yukon(game):
|
|
||||||
num_cols = 7
|
|
||||||
game.board = Board(num_cols)
|
|
||||||
|
|
||||||
for i in range(1, num_cols):
|
|
||||||
for j in range(i, num_cols):
|
|
||||||
game.add(j, game.next().flip())
|
|
||||||
|
|
||||||
for i in range(4):
|
|
||||||
for j in range(1, num_cols):
|
|
||||||
game.add(j, game.next())
|
|
||||||
|
|
||||||
game.cyclical_deal(num_cols, num_cols)
|
|
||||||
|
|
||||||
|
|
||||||
class MyTests(unittest.TestCase):
|
class MyTests(unittest.TestCase):
|
||||||
|
@ -569,11 +81,9 @@ class MyTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_main(self):
|
def test_main(self):
|
||||||
|
|
||||||
rand = constructRandom('24')
|
|
||||||
|
|
||||||
def test_24(blurb):
|
def test_24(blurb):
|
||||||
game = Game("freecell", rand, True)
|
game = Game("freecell", 24, RandomBase.DEALS_PYSOLFC)
|
||||||
got_s = game.print_layout()
|
got_s = game.calc_layout_string(ren)
|
||||||
self.assertEqual(got_s, '''4C 2C 9C 8C QS 4S 2H
|
self.assertEqual(got_s, '''4C 2C 9C 8C QS 4S 2H
|
||||||
5H QH 3C AC 3H 4H QD
|
5H QH 3C AC 3H 4H QD
|
||||||
QC 9S 6H 9H 3S KS 3D
|
QC 9S 6H 9H 3S KS 3D
|
||||||
|
@ -586,14 +96,10 @@ AH 5S 6S AD 8H JD
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
test_24('Deal 24')
|
test_24('Deal 24')
|
||||||
rand.reset()
|
|
||||||
# TEST
|
|
||||||
test_24('MS deal after reset.')
|
|
||||||
|
|
||||||
rand = constructRandom('ms123456')
|
game = Game("freecell", 123456, RandomBase.DEALS_MS)
|
||||||
game = Game("freecell", rand, True)
|
|
||||||
# TEST
|
# TEST
|
||||||
got_s = game.print_layout()
|
got_s = game.calc_layout_string(ren)
|
||||||
self.assertEqual(got_s, '''QD TC AS KC AH KH 6H
|
self.assertEqual(got_s, '''QD TC AS KC AH KH 6H
|
||||||
6D TD 8D TH 7C 2H 9C
|
6D TD 8D TH 7C 2H 9C
|
||||||
AC AD 5C 5H 8C 9H 9D
|
AC AD 5C 5H 8C 9H 9D
|
||||||
|
@ -604,10 +110,9 @@ JS 8S 4D 4C 2S 7D 3C
|
||||||
JD QH 6S 4H QC 8H
|
JD QH 6S 4H QC 8H
|
||||||
''', 'Microsoft Deal 123456')
|
''', 'Microsoft Deal 123456')
|
||||||
|
|
||||||
rand = constructRandom('123456')
|
game = Game("freecell", 123456, True)
|
||||||
game = Game("freecell", rand, True)
|
|
||||||
# TEST
|
# TEST
|
||||||
self._cmp_board(game.print_layout(), '''3D 6C AS TS QC 8D 4D
|
self._cmp_board(game.calc_layout_string(ren), '''3D 6C AS TS QC 8D 4D
|
||||||
2D TC 4H JD TD 2H 5C
|
2D TC 4H JD TD 2H 5C
|
||||||
2C 8S AH KD KH 5S 7C
|
2C 8S AH KD KH 5S 7C
|
||||||
9C 8C QH 3C 5D 9S QD
|
9C 8C QH 3C 5D 9S QD
|
||||||
|
@ -618,9 +123,9 @@ KC JS 9H 4S 7S AD
|
||||||
''', 'PySolFC deal No. 123456')
|
''', 'PySolFC deal No. 123456')
|
||||||
|
|
||||||
rand = constructRandom('ms3000000000')
|
rand = constructRandom('ms3000000000')
|
||||||
game = Game("freecell", rand, True)
|
game = Game("freecell", 3000000000, RandomBase.DEALS_MS)
|
||||||
# TEST
|
# TEST
|
||||||
self._cmp_board(game.print_layout(), '''8D TS JS TD JH JD JC
|
self._cmp_board(game.calc_layout_string(ren), '''8D TS JS TD JH JD JC
|
||||||
4D QS TH AD 4S TC 3C
|
4D QS TH AD 4S TC 3C
|
||||||
9H KH QH 4C 5C KD AS
|
9H KH QH 4C 5C KD AS
|
||||||
9D 5D 8S 4H KS 6S 9S
|
9D 5D 8S 4H KS 6S 9S
|
||||||
|
@ -631,9 +136,9 @@ KC JS 9H 4S 7S AD
|
||||||
''', 'Microsoft Deal #3E9 - long seed.')
|
''', 'Microsoft Deal #3E9 - long seed.')
|
||||||
|
|
||||||
rand = constructRandom('ms6000000000')
|
rand = constructRandom('ms6000000000')
|
||||||
game = Game("freecell", rand, True)
|
game = Game("freecell", 6000000000, RandomBase.DEALS_MS)
|
||||||
# TEST
|
# TEST
|
||||||
got_s = game.print_layout()
|
got_s = game.calc_layout_string(ren)
|
||||||
self.assertEqual(got_s, '''2D 2C QS 8D KD 8C 4C
|
self.assertEqual(got_s, '''2D 2C QS 8D KD 8C 4C
|
||||||
3D AH 2H 4H TS 6H QD
|
3D AH 2H 4H TS 6H QD
|
||||||
4D JS AD 6S JH JC JD
|
4D JS AD 6S JH JC JD
|
||||||
|
@ -669,9 +174,9 @@ QH 9H 9D 5S 7S 6C
|
||||||
# TEST
|
# TEST
|
||||||
self.assertEqual(seed, 'ms100001', 'increaseSeed for ms deals')
|
self.assertEqual(seed, 'ms100001', 'increaseSeed for ms deals')
|
||||||
rand = constructRandom(seed)
|
rand = constructRandom(seed)
|
||||||
game = Game("freecell", rand, True)
|
game = Game("freecell", int(seed[2:]), RandomBase.DEALS_MS)
|
||||||
# TEST
|
# TEST
|
||||||
self._cmp_board(game.print_layout(), '''5S AH 4H TD 4S JD JS
|
self._cmp_board(game.calc_layout_string(ren), '''5S AH 4H TD 4S JD JS
|
||||||
3C 8C 4C AC JC AS QS
|
3C 8C 4C AC JC AS QS
|
||||||
7C QH 2D QD 8S 9D AD
|
7C QH 2D QD 8S 9D AD
|
||||||
KS 7S 5H 3H TS 3S 5D
|
KS 7S 5H 3H TS 3S 5D
|
||||||
|
|
Loading…
Add table
Reference in a new issue