mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-15 02:54:09 -04:00
Compare commits
14 commits
c5864cc0f6
...
467a0f14e0
Author | SHA1 | Date | |
---|---|---|---|
|
467a0f14e0 | ||
|
88cdccea5b | ||
|
7914c6e805 | ||
|
3ef4b3c6dc | ||
|
12cf1e507f | ||
|
b311ff83fd | ||
|
a8fd45e2f8 | ||
|
068d72d634 | ||
|
b6f014f6e0 | ||
|
c4545ab114 | ||
|
3ca47be6e2 | ||
|
bea4266889 | ||
|
7896974496 | ||
|
91ef2ca74e |
6 changed files with 46 additions and 159 deletions
|
@ -35,7 +35,7 @@ and implemented some other enhancements.
|
||||||
|
|
||||||
## Installation.
|
## Installation.
|
||||||
|
|
||||||
We provide an [installer for Windows](https://sourceforge.net/projects/pysolfc/files/PySolFC/)
|
We provide an [installer for Windows](https://sourceforge.net/projects/pysolfc/files/PySolFC/) (requires Windows XP SP3 or higher)
|
||||||
as well as an Android package on F-droid.
|
as well as an Android package on F-droid.
|
||||||
|
|
||||||
For installation from source, see: http://www.python.org/doc/current/inst/
|
For installation from source, see: http://www.python.org/doc/current/inst/
|
||||||
|
|
|
@ -54,7 +54,7 @@ from pysollib.move import AUpdateStackMove
|
||||||
from pysollib.mygettext import _
|
from pysollib.mygettext import _
|
||||||
from pysollib.mygettext import ungettext
|
from pysollib.mygettext import ungettext
|
||||||
from pysollib.pysolrandom import LCRandom31, PysolRandom, constructRandom, \
|
from pysollib.pysolrandom import LCRandom31, PysolRandom, constructRandom, \
|
||||||
random__long2str
|
random__int2str
|
||||||
from pysollib.pysoltk import CURSOR_WATCH
|
from pysollib.pysoltk import CURSOR_WATCH
|
||||||
from pysollib.pysoltk import Card
|
from pysollib.pysoltk import Card
|
||||||
from pysollib.pysoltk import EVENT_HANDLED, EVENT_PROPAGATE
|
from pysollib.pysoltk import EVENT_HANDLED, EVENT_PROPAGATE
|
||||||
|
@ -3200,7 +3200,7 @@ class Game(object):
|
||||||
game.version = version
|
game.version = version
|
||||||
game.version_tuple = version_tuple
|
game.version_tuple = version_tuple
|
||||||
#
|
#
|
||||||
initial_seed = random__long2str(pload(int))
|
initial_seed = random__int2str(pload(int))
|
||||||
game.random = constructRandom(initial_seed)
|
game.random = constructRandom(initial_seed)
|
||||||
state = pload()
|
state = pload()
|
||||||
if not (isinstance(game.random, random2.Random) and
|
if not (isinstance(game.random, random2.Random) and
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from pysollib.pysolrandom import random__str2long
|
from pysollib.pysolrandom import random__str2int
|
||||||
from pysollib.settings import PACKAGE
|
from pysollib.settings import PACKAGE
|
||||||
from pysollib.settings import VERSION, VERSION_TUPLE
|
from pysollib.settings import VERSION, VERSION_TUPLE
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ def pysolDumpGame(game_, p, bookmark=0):
|
||||||
p.dump(game_.GAME_VERSION)
|
p.dump(game_.GAME_VERSION)
|
||||||
p.dump(game_.id)
|
p.dump(game_.id)
|
||||||
#
|
#
|
||||||
p.dump(random__str2long(game_.random.getSeedStr()))
|
p.dump(random__str2int(game_.random.getSeedStr()))
|
||||||
p.dump(game_.random.getstate())
|
p.dump(game_.random.getstate())
|
||||||
#
|
#
|
||||||
p.dump(len(game_.allstacks))
|
p.dump(len(game_.allstacks))
|
||||||
|
|
|
@ -26,96 +26,19 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pysol_cards
|
import pysol_cards
|
||||||
assert getattr(pysol_cards, 'VERSION', (0, 0, 0)) >= (0, 8, 7), (
|
assert getattr(pysol_cards, 'VERSION', (0, 0, 0)) >= (0, 8, 15), (
|
||||||
"Newer version of https://pypi.org/project/pysol-cards is required.")
|
"Newer version of https://pypi.org/project/pysol-cards is required.")
|
||||||
from pysol_cards.random_base import RandomBase # noqa: I100
|
import pysol_cards.random # noqa: I100
|
||||||
from pysol_cards.random import MTRandom, match_ms_deal_prefix # noqa: I100
|
import pysol_cards.random_base # noqa: I100
|
||||||
|
from pysol_cards.random import LCRandom31, match_ms_deal_prefix # noqa: I100
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# * Wichman-Hill random number generator
|
|
||||||
# * uses the standard python module `random'
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
# class WHRandom(RandomBase, random.WichmannHill):
|
|
||||||
#
|
|
||||||
# def __init__(self, seed=None):
|
|
||||||
# if seed is None:
|
|
||||||
# seed = self._getRandomSeed()
|
|
||||||
# RandomBase.__init__(self)
|
|
||||||
# random.WichmannHill.__init__(self, seed)
|
|
||||||
# self.initial_seed = seed
|
|
||||||
# self.initial_state = self.getstate()
|
|
||||||
# self.origin = self.ORIGIN_UNKNOWN
|
|
||||||
#
|
|
||||||
# def reset(self):
|
|
||||||
# self.setstate(self.initial_state)
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# * Abstract class for LC Random number generators.
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
|
|
||||||
class MFXRandom(RandomBase):
|
|
||||||
|
|
||||||
def __init__(self, seed=None):
|
|
||||||
RandomBase.__init__(self)
|
|
||||||
if seed is None:
|
|
||||||
seed = self._getRandomSeed()
|
|
||||||
self.initial_seed = self.setSeed(seed)
|
|
||||||
self.origin = self.ORIGIN_UNKNOWN
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.seed = self.initial_seed
|
|
||||||
|
|
||||||
def getSeed(self):
|
|
||||||
return self.seed
|
|
||||||
|
|
||||||
def setSeed(self, seed):
|
|
||||||
seed = int(seed)
|
|
||||||
if not (0 <= seed <= self.MAX_SEED):
|
|
||||||
raise ValueError("seed out of range")
|
|
||||||
self.seed = seed
|
|
||||||
return seed
|
|
||||||
|
|
||||||
def getstate(self):
|
|
||||||
return self.seed
|
|
||||||
|
|
||||||
def setstate(self, state):
|
|
||||||
self.seed = state
|
|
||||||
|
|
||||||
#
|
|
||||||
# implementation
|
|
||||||
#
|
|
||||||
|
|
||||||
def choice(self, seq):
|
|
||||||
return seq[int(self.random() * len(seq))]
|
|
||||||
|
|
||||||
def randrange(self, a, b):
|
|
||||||
return self.randint(a, b-1)
|
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# * Linear Congruential random generator
|
|
||||||
# *
|
|
||||||
# * Knuth, Donald.E., "The Art of Computer Programming,", Vol 2,
|
|
||||||
# * Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
|
|
||||||
# * p. 106 (line 26) & p. 108
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
class LCRandom64(MFXRandom):
|
|
||||||
|
|
||||||
def random(self):
|
|
||||||
self.seed = (self.seed*int('6364136223846793005') + 1) & self.MAX_SEED
|
|
||||||
return ((self.seed >> 21) & 0x7fffffff) / 2147483648.0
|
|
||||||
|
|
||||||
|
|
||||||
MS_LONG_BIT = (1 << 1000)
|
MS_LONG_BIT = (1 << 1000)
|
||||||
CUSTOM_BIT = (1 << 999)
|
CUSTOM_BIT = (1 << 999)
|
||||||
|
|
||||||
|
|
||||||
class CustomRandom(RandomBase):
|
class CustomRandom(pysol_cards.random_base.RandomBase):
|
||||||
def __init__(self):
|
def __init__(self, seed=None):
|
||||||
self.initial_seed = self.seed = MS_LONG_BIT | CUSTOM_BIT
|
self.initial_seed = self.seed = MS_LONG_BIT | CUSTOM_BIT
|
||||||
self.origin = self.ORIGIN_UNKNOWN
|
self.origin = self.ORIGIN_UNKNOWN
|
||||||
self.setSeedAsStr('Custom')
|
self.setSeedAsStr('Custom')
|
||||||
|
@ -126,68 +49,8 @@ class CustomRandom(RandomBase):
|
||||||
def shuffle(self, seq):
|
def shuffle(self, seq):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getstate(self):
|
|
||||||
return self.seed
|
|
||||||
|
|
||||||
def setstate(self, state):
|
PysolRandom = pysol_cards.random.MTRandom
|
||||||
self.seed = state
|
|
||||||
|
|
||||||
# ************************************************************************
|
|
||||||
# * Linear Congruential random generator
|
|
||||||
# * In PySol this is only used for 0 <= seed <= 32000
|
|
||||||
# * for Windows FreeCell compatibility
|
|
||||||
# ************************************************************************
|
|
||||||
|
|
||||||
|
|
||||||
class LCRandom31(MFXRandom):
|
|
||||||
MAX_SEED = int('0x1ffffffff', 0) # 33 bits
|
|
||||||
|
|
||||||
def increaseSeed(self, seed):
|
|
||||||
ret = super(LCRandom31, self).increaseSeed(seed)
|
|
||||||
return "ms{}".format(ret)
|
|
||||||
|
|
||||||
def getSeedStr(self):
|
|
||||||
return "ms" + str(self.initial_seed)
|
|
||||||
|
|
||||||
def str(self, seed):
|
|
||||||
if match_ms_deal_prefix("{}".format(seed)) is None:
|
|
||||||
return "%05d" % int(seed)
|
|
||||||
return seed
|
|
||||||
|
|
||||||
def setSeed(self, seed):
|
|
||||||
seed = int(seed)
|
|
||||||
self.seed = seed
|
|
||||||
if not (0 <= seed <= self.MAX_SEED):
|
|
||||||
raise ValueError("seed out of range")
|
|
||||||
self.seedx = (seed if (seed < int('0x100000000', 0)) else
|
|
||||||
(seed - int('0x100000000', 0)))
|
|
||||||
return seed
|
|
||||||
|
|
||||||
def _rando(self):
|
|
||||||
self.seedx = (self.seedx*214013 + 2531011) & self.MAX_SEED
|
|
||||||
return ((self.seedx >> 16) & 0x7fff)
|
|
||||||
|
|
||||||
def _randp(self):
|
|
||||||
self.seedx = (self.seedx*214013 + 2531011) & self.MAX_SEED
|
|
||||||
return ((self.seedx >> 16) & 0xffff)
|
|
||||||
|
|
||||||
def randint(self, a, b):
|
|
||||||
if self.seed < 0x100000000:
|
|
||||||
ret = self._rando()
|
|
||||||
ret = (ret if (self.seed < 0x80000000) else (ret | 0x8000))
|
|
||||||
else:
|
|
||||||
ret = self._randp() + 1
|
|
||||||
|
|
||||||
return a + (ret % (b+1-a))
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.setSeed(self.seed)
|
|
||||||
|
|
||||||
|
|
||||||
# select
|
|
||||||
# PysolRandom = LCRandom64
|
|
||||||
# PysolRandom = WHRandom
|
|
||||||
PysolRandom = MTRandom
|
|
||||||
|
|
||||||
|
|
||||||
# ************************************************************************
|
# ************************************************************************
|
||||||
|
@ -204,7 +67,10 @@ def constructRandom(s):
|
||||||
seed = m
|
seed = m
|
||||||
if 0 <= seed <= LCRandom31.MAX_SEED:
|
if 0 <= seed <= LCRandom31.MAX_SEED:
|
||||||
ret = LCRandom31(seed)
|
ret = LCRandom31(seed)
|
||||||
ret.setSeedAsStr(s)
|
assert ret.seed
|
||||||
|
assert ret.seedx
|
||||||
|
assert ret.initial_seed
|
||||||
|
# ret.setSeedAsStr(s)
|
||||||
return ret
|
return ret
|
||||||
else:
|
else:
|
||||||
raise ValueError("ms seed out of range")
|
raise ValueError("ms seed out of range")
|
||||||
|
@ -216,10 +82,10 @@ def constructRandom(s):
|
||||||
seed = int(s)
|
seed = int(s)
|
||||||
if 0 <= seed < 32000:
|
if 0 <= seed < 32000:
|
||||||
return LCRandom31(seed)
|
return LCRandom31(seed)
|
||||||
return PysolRandom(seed)
|
return pysol_cards.random.MTRandom(seed)
|
||||||
|
|
||||||
|
|
||||||
def random__str2long(s):
|
def random__str2int(s):
|
||||||
if s == 'Custom':
|
if s == 'Custom':
|
||||||
return CUSTOM_BIT | MS_LONG_BIT
|
return CUSTOM_BIT | MS_LONG_BIT
|
||||||
m = match_ms_deal_prefix(s)
|
m = match_ms_deal_prefix(s)
|
||||||
|
@ -229,7 +95,7 @@ def random__str2long(s):
|
||||||
return int(s)
|
return int(s)
|
||||||
|
|
||||||
|
|
||||||
def random__long2str(l):
|
def random__int2str(l):
|
||||||
if ((l & MS_LONG_BIT) != 0):
|
if ((l & MS_LONG_BIT) != 0):
|
||||||
if ((l & CUSTOM_BIT) != 0):
|
if ((l & CUSTOM_BIT) != 0):
|
||||||
return 'Custom'
|
return 'Custom'
|
||||||
|
|
|
@ -76,6 +76,26 @@ begin
|
||||||
Result := False;
|
Result := False;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
''', file=out)
|
|
||||||
|
function InitializeSetup(): Boolean;
|
||||||
|
var
|
||||||
|
Version: TWindowsVersion;
|
||||||
|
begin
|
||||||
|
GetWindowsVersionEx(Version);
|
||||||
|
|
||||||
|
// Windows XP SP3 and higher
|
||||||
|
if ((Version.Major = 5) and ((Version.Minor = 1) and
|
||||||
|
(Version.ServicePackMajor >= 3) or (Version.Minor > 1)) or
|
||||||
|
(Version.Major > 5)) then
|
||||||
|
Result := True
|
||||||
|
else begin
|
||||||
|
MsgBox(
|
||||||
|
'This version of Windows is not supported. PySolFC %(prog_version)s \
|
||||||
|
requires Windows XP SP3 or higher.',
|
||||||
|
mbCriticalError, MB_OK);
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
''' % vars(), file=out)
|
||||||
|
|
||||||
out.close()
|
out.close()
|
||||||
|
|
|
@ -59,7 +59,7 @@ from pysol_cards.random_base import RandomBase
|
||||||
|
|
||||||
# So the localpaths will be overrided.
|
# So the localpaths will be overrided.
|
||||||
from pysollib.pysolrandom import constructRandom, \
|
from pysollib.pysolrandom import constructRandom, \
|
||||||
random__long2str, random__str2long
|
random__int2str, random__str2int
|
||||||
|
|
||||||
# PySol imports
|
# PySol imports
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ KC JS 9H 4S 7S AD
|
||||||
''', 'PySolFC deal No. 123456')
|
''', 'PySolFC deal No. 123456')
|
||||||
|
|
||||||
rand = constructRandom('ms3000000000')
|
rand = constructRandom('ms3000000000')
|
||||||
|
self.assertEqual(rand.getSeedAsStr(), 'ms3000000000')
|
||||||
game = Game("freecell", 3000000000, RandomBase.DEALS_MS)
|
game = Game("freecell", 3000000000, RandomBase.DEALS_MS)
|
||||||
# TEST
|
# TEST
|
||||||
self._cmp_board(game.calc_layout_string(ren), '''8D TS JS TD JH JD JC
|
self._cmp_board(game.calc_layout_string(ren), '''8D TS JS TD JH JD JC
|
||||||
|
@ -150,20 +151,20 @@ QH 9H 9D 5S 7S 6C
|
||||||
''', 'Microsoft Deal #6E9 - extra long seed.')
|
''', 'Microsoft Deal #6E9 - extra long seed.')
|
||||||
|
|
||||||
inp = 'ms12345678'
|
inp = 'ms12345678'
|
||||||
got = random__long2str(random__str2long(inp))
|
got = random__int2str(random__str2int(inp))
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
self.assertEqual(got, inp, 'long2str ms roundtrip.')
|
self.assertEqual(got, inp, 'long2str ms roundtrip.')
|
||||||
|
|
||||||
inp = '246007891097'
|
inp = '246007891097'
|
||||||
got = random__long2str(random__str2long(inp))
|
got = random__int2str(random__str2int(inp))
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
self.assertEqual(got, inp, 'long2str PySolFC roundtrip.')
|
self.assertEqual(got, inp, 'long2str PySolFC roundtrip.')
|
||||||
|
|
||||||
proto_inp = '246007891097'
|
proto_inp = '246007891097'
|
||||||
inp = random__str2long(proto_inp)
|
inp = random__str2int(proto_inp)
|
||||||
got = random__str2long(random__long2str(inp))
|
got = random__str2int(random__int2str(inp))
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
self.assertEqual(got, inp, 'str2long PySolFC roundtrip.')
|
self.assertEqual(got, inp, 'str2long PySolFC roundtrip.')
|
||||||
|
|
Loading…
Add table
Reference in a new issue