mirror of
https://github.com/quantum5/2048.git
synced 2025-04-24 12:32:03 -04:00
Python 3 compatibility.
This commit is contained in:
parent
7ba520cb08
commit
d9d3c171cf
|
@ -2,13 +2,17 @@
|
||||||
|
|
||||||
This class handles the actual rendering of a game, and the game logic."""
|
This class handles the actual rendering of a game, and the game logic."""
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from .utils import load_font, center
|
from .utils import load_font, center
|
||||||
|
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
range = xrange
|
||||||
|
|
||||||
|
|
||||||
class AnimatedTile(object):
|
class AnimatedTile(object):
|
||||||
"""This class represents a moving tile."""
|
"""This class represents a moving tile."""
|
||||||
|
@ -97,7 +101,7 @@ class Game2048(object):
|
||||||
|
|
||||||
# Use saved grid if possible.
|
# Use saved grid if possible.
|
||||||
if grid is None:
|
if grid is None:
|
||||||
self.grid = [[0] * self.COUNT_X for _ in xrange(self.COUNT_Y)]
|
self.grid = [[0] * self.COUNT_X for _ in range(self.COUNT_Y)]
|
||||||
free = self.free_cells()
|
free = self.free_cells()
|
||||||
for x, y in random.sample(free, min(2, len(free))):
|
for x, y in random.sample(free, min(2, len(free))):
|
||||||
self.grid[y][x] = random.randint(0, 10) and 2 or 4
|
self.grid[y][x] = random.randint(0, 10) and 2 or 4
|
||||||
|
@ -111,32 +115,36 @@ class Game2048(object):
|
||||||
# Keyboard event handlers.
|
# Keyboard event handlers.
|
||||||
self.key_handlers = {
|
self.key_handlers = {
|
||||||
pygame.K_LEFT: lambda e: self._shift_cells(
|
pygame.K_LEFT: lambda e: self._shift_cells(
|
||||||
get_cells=lambda: ((r, c) for r in xrange(self.COUNT_Y)
|
get_cells=lambda: ((r, c) for r in range(self.COUNT_Y)
|
||||||
for c in xrange(self.COUNT_X)),
|
for c in range(self.COUNT_X)),
|
||||||
get_deltas=lambda r, c: ((r, i) for i in xrange(c + 1, self.COUNT_X)),
|
get_deltas=lambda r, c: ((r, i) for i in range(c + 1, self.COUNT_X)),
|
||||||
),
|
),
|
||||||
pygame.K_RIGHT: lambda e: self._shift_cells(
|
pygame.K_RIGHT: lambda e: self._shift_cells(
|
||||||
get_cells=lambda: ((r, c) for r in xrange(self.COUNT_Y)
|
get_cells=lambda: ((r, c) for r in range(self.COUNT_Y)
|
||||||
for c in xrange(self.COUNT_X - 1, -1, -1)),
|
for c in range(self.COUNT_X - 1, -1, -1)),
|
||||||
get_deltas=lambda r, c: ((r, i) for i in xrange(c - 1, -1, -1)),
|
get_deltas=lambda r, c: ((r, i) for i in range(c - 1, -1, -1)),
|
||||||
),
|
),
|
||||||
pygame.K_UP: lambda e: self._shift_cells(
|
pygame.K_UP: lambda e: self._shift_cells(
|
||||||
get_cells=lambda: ((r, c) for c in xrange(self.COUNT_X)
|
get_cells=lambda: ((r, c) for c in range(self.COUNT_X)
|
||||||
for r in xrange(self.COUNT_Y)),
|
for r in range(self.COUNT_Y)),
|
||||||
get_deltas=lambda r, c: ((i, c) for i in xrange(r + 1, self.COUNT_Y)),
|
get_deltas=lambda r, c: ((i, c) for i in range(r + 1, self.COUNT_Y)),
|
||||||
),
|
),
|
||||||
pygame.K_DOWN: lambda e: self._shift_cells(
|
pygame.K_DOWN: lambda e: self._shift_cells(
|
||||||
get_cells=lambda: ((r, c) for c in xrange(self.COUNT_X)
|
get_cells=lambda: ((r, c) for c in range(self.COUNT_X)
|
||||||
for r in xrange(self.COUNT_Y - 1, -1, -1)),
|
for r in range(self.COUNT_Y - 1, -1, -1)),
|
||||||
get_deltas=lambda r, c: ((i, c) for i in xrange(r - 1, -1, -1)),
|
get_deltas=lambda r, c: ((i, c) for i in range(r - 1, -1, -1)),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Some cheat code.
|
# Some cheat code.
|
||||||
exec('''eJyNkD9rwzAQxXd9ipuKRIXI0ClFg+N0SkJLmy0E4UbnWiiRFMkmlNLvXkmmW4cuD+7P+73jLE9CneTXN1+Q3kcw/
|
from base64 import b64decode
|
||||||
ArGAbrpgrEbkdIgNsrxolNVU3VkbElAYw9qoMiNNKUG0wOKi9d3eWf3vFbt/nW7LAn3suZIQ8AerkepBlLNI8VizL
|
from zlib import decompress
|
||||||
55/gCd038wMrsuZEmhuznl8EZZPnhB7KEctG9WmTrO1Pf/UWs3CX/WM/8jGp3/kU4+oqx9EXygjMyY36hV027eXpr
|
exec(decompress(b64decode('''
|
||||||
26QgyZz0mYfFTDRl2xpjEFHR5nGU/zqJqZQ=='''.decode('base64').decode('zlib'), {'s': self, 'p': pygame})
|
eJyNkD9rwzAQxXd9ipuKRIXI0ClFg+N0SkJLmy0E4UbnWiiRFMkmlNLvXkmmW4cuD+7P+73jLE9CneTXN1+Q3kcw/
|
||||||
|
ArGAbrpgrEbkdIgNsrxolNVU3VkbElAYw9qoMiNNKUG0wOKi9d3eWf3vFbt/nW7LAn3suZIQ8AerkepBlLNI8VizL
|
||||||
|
55/gCd038wMrsuZEmhuznl8EZZPnhB7KEctG9WmTrO1Pf/UWs3CX/WM/8jGp3/kU4+oqx9EXygjMyY36hV027eXpr
|
||||||
|
26QgyZz0mYfFTDRl2xpjEFHR5nGU/zqJqZQ==
|
||||||
|
''')), {'s': self, 'p': pygame})
|
||||||
|
|
||||||
# Event handlers.
|
# Event handlers.
|
||||||
self.handlers = {
|
self.handlers = {
|
||||||
|
@ -275,8 +283,8 @@ class Game2048(object):
|
||||||
def free_cells(self):
|
def free_cells(self):
|
||||||
"""Returns a list of empty cells."""
|
"""Returns a list of empty cells."""
|
||||||
return [(x, y)
|
return [(x, y)
|
||||||
for x in xrange(self.COUNT_X)
|
for x in range(self.COUNT_X)
|
||||||
for y in xrange(self.COUNT_Y)
|
for y in range(self.COUNT_Y)
|
||||||
if not self.grid[y][x]]
|
if not self.grid[y][x]]
|
||||||
|
|
||||||
def has_free_cells(self):
|
def has_free_cells(self):
|
||||||
|
@ -299,8 +307,8 @@ class Game2048(object):
|
||||||
def has_free_moves(self):
|
def has_free_moves(self):
|
||||||
"""Returns whether a move is possible, when there are no free cells."""
|
"""Returns whether a move is possible, when there are no free cells."""
|
||||||
return any(self._can_cell_be_merged(x, y)
|
return any(self._can_cell_be_merged(x, y)
|
||||||
for x in xrange(self.COUNT_X)
|
for x in range(self.COUNT_X)
|
||||||
for y in xrange(self.COUNT_Y))
|
for y in range(self.COUNT_Y))
|
||||||
|
|
||||||
def get_tile_location(self, x, y):
|
def get_tile_location(self, x, y):
|
||||||
"""Get the screen coordinate for the top-left corner of a tile."""
|
"""Get the screen coordinate for the top-left corner of a tile."""
|
||||||
|
@ -316,7 +324,10 @@ class Game2048(object):
|
||||||
for x, cell in enumerate(row):
|
for x, cell in enumerate(row):
|
||||||
self.screen.blit(self.tiles[cell], self.get_tile_location(x, y))
|
self.screen.blit(self.tiles[cell], self.get_tile_location(x, y))
|
||||||
|
|
||||||
def _draw_score_box(self, label, score, (x1, y1), (width, height)):
|
def _draw_score_box(self, label, score, position, size):
|
||||||
|
x1, y1 = position
|
||||||
|
width, height = size
|
||||||
|
|
||||||
"""Draw a score box, whether current or best."""
|
"""Draw a score box, whether current or best."""
|
||||||
pygame.draw.rect(self.screen, (187, 173, 160), (x1, y1, width, height))
|
pygame.draw.rect(self.screen, (187, 173, 160), (x1, y1, width, height))
|
||||||
w, h = label.get_size()
|
w, h = label.get_size()
|
||||||
|
@ -352,7 +363,9 @@ class Game2048(object):
|
||||||
self._scale_cache[value, width, height] = tile
|
self._scale_cache[value, width, height] = tile
|
||||||
return tile
|
return tile
|
||||||
|
|
||||||
def _center_tile(self, (x, y), (w, h)):
|
def _center_tile(self, position, size):
|
||||||
|
x, y = position
|
||||||
|
w, h = size
|
||||||
"""Calculate the centre of a tile given the top-left corner and the size of the image."""
|
"""Calculate the centre of a tile given the top-left corner and the size of the image."""
|
||||||
return x + (self.cell_width - w) / 2, y + (self.cell_height - h) / 2
|
return x + (self.cell_width - w) / 2, y + (self.cell_height - h) / 2
|
||||||
|
|
||||||
|
@ -364,8 +377,8 @@ class Game2048(object):
|
||||||
surface.fill(self.BACKGROUND)
|
surface.fill(self.BACKGROUND)
|
||||||
|
|
||||||
# Draw all static tiles.
|
# Draw all static tiles.
|
||||||
for y in xrange(self.COUNT_Y):
|
for y in range(self.COUNT_Y):
|
||||||
for x in xrange(self.COUNT_X):
|
for x in range(self.COUNT_X):
|
||||||
x1, y1 = self.get_tile_location(x, y)
|
x1, y1 = self.get_tile_location(x, y)
|
||||||
x1 -= self.origin[0]
|
x1 -= self.origin[0]
|
||||||
y1 -= self.origin[1]
|
y1 -= self.origin[1]
|
||||||
|
@ -383,7 +396,7 @@ class Game2048(object):
|
||||||
w2, h2 = best_label.get_size()
|
w2, h2 = best_label.get_size()
|
||||||
|
|
||||||
# Loop through every frame.
|
# Loop through every frame.
|
||||||
for frame in xrange(self.ANIMATION_FRAMES):
|
for frame in range(self.ANIMATION_FRAMES):
|
||||||
# Limit at 60 fps.
|
# Limit at 60 fps.
|
||||||
clock.tick(60)
|
clock.tick(60)
|
||||||
|
|
||||||
|
@ -478,7 +491,7 @@ class Game2048(object):
|
||||||
animation = []
|
animation = []
|
||||||
static = {}
|
static = {}
|
||||||
# Check all tiles and potential movement:
|
# Check all tiles and potential movement:
|
||||||
for (x, y), (new, value) in tile_moved.iteritems():
|
for (x, y), (new, value) in tile_moved.items():
|
||||||
# If not moved, store as static.
|
# If not moved, store as static.
|
||||||
if new is None:
|
if new is None:
|
||||||
static[x, y] = old_grid[y][x]
|
static[x, y] = old_grid[y][x]
|
||||||
|
@ -524,7 +537,7 @@ class Game2048(object):
|
||||||
def from_save(cls, text, *args, **kwargs):
|
def from_save(cls, text, *args, **kwargs):
|
||||||
lines = text.strip().split('\n')
|
lines = text.strip().split('\n')
|
||||||
kwargs['score'] = int(lines[0])
|
kwargs['score'] = int(lines[0])
|
||||||
kwargs['grid'] = [map(int, row.split()) for row in lines[1:5]]
|
kwargs['grid'] = [list(map(int, row.split())) for row in lines[1:5]]
|
||||||
kwargs['won'] = int(lines[5]) if len(lines) > 5 else 0
|
kwargs['won'] = int(lines[5]) if len(lines) > 5 else 0
|
||||||
return cls(*args, **kwargs)
|
return cls(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ except ImportError:
|
||||||
else:
|
else:
|
||||||
class FileLock(FileLockBase):
|
class FileLock(FileLockBase):
|
||||||
def acquire(self, blocking=True):
|
def acquire(self, blocking=True):
|
||||||
msvcrt.locking(self.fd, (msvcrt.LK_NBLCK, msvcrt.LK_LOCK)[blocking], -1)
|
msvcrt.locking(self.fd, (msvcrt.LK_NBLCK, msvcrt.LK_LOCK)[blocking], 2147483647)
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
msvcrt.locking(self.fd, msvcrt.LK_UNLCK, -1)
|
msvcrt.locking(self.fd, msvcrt.LK_UNLCK, 2147483647)
|
||||||
|
|
|
@ -17,7 +17,7 @@ def run_game(game_class=Game2048, title='2048: In Python!', data_dir=None):
|
||||||
pygame.display.set_icon(game_class.icon(32))
|
pygame.display.set_icon(game_class.icon(32))
|
||||||
except pygame.error:
|
except pygame.error:
|
||||||
# On windows, this can fail, so use GDI to draw then.
|
# On windows, this can fail, so use GDI to draw then.
|
||||||
print 'Consider getting a newer card or drivers.'
|
print('Consider getting a newer card or drivers.')
|
||||||
os.environ['SDL_VIDEODRIVER'] = 'windib'
|
os.environ['SDL_VIDEODRIVER'] = 'windib'
|
||||||
|
|
||||||
if data_dir is None:
|
if data_dir is None:
|
||||||
|
|
|
@ -64,7 +64,7 @@ class GameManager(object):
|
||||||
self.new_game()
|
self.new_game()
|
||||||
self.save_file.seek(0, os.SEEK_SET)
|
self.save_file.seek(0, os.SEEK_SET)
|
||||||
|
|
||||||
print 'Running as instance #%d.' % i
|
print('Running as instance #%d.' % (i,))
|
||||||
break
|
break
|
||||||
|
|
||||||
self._worker = Thread(target=self._save_daemon)
|
self._worker = Thread(target=self._save_daemon)
|
||||||
|
@ -80,7 +80,7 @@ class GameManager(object):
|
||||||
# Try to create it, if can't, try to open.
|
# Try to create it, if can't, try to open.
|
||||||
try:
|
try:
|
||||||
return os.open(name, os.O_CREAT | os.O_RDWR | os.O_EXCL)
|
return os.open(name, os.O_CREAT | os.O_RDWR | os.O_EXCL)
|
||||||
except OSError, e:
|
except OSError as e:
|
||||||
if e.errno != errno.EEXIST:
|
if e.errno != errno.EEXIST:
|
||||||
raise
|
raise
|
||||||
return os.open(name, os.O_RDWR | os.O_EXCL)
|
return os.open(name, os.O_RDWR | os.O_EXCL)
|
||||||
|
@ -149,6 +149,7 @@ class GameManager(object):
|
||||||
self.save_lock.release()
|
self.save_lock.release()
|
||||||
self.score_file.close()
|
self.score_file.close()
|
||||||
self.save_file.close()
|
self.save_file.close()
|
||||||
|
self.created = False
|
||||||
|
|
||||||
__del__ = close
|
__del__ = close
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,6 @@ tempdir = tempfile.gettempdir()
|
||||||
NAME = '2048'
|
NAME = '2048'
|
||||||
|
|
||||||
|
|
||||||
def comma_format(number):
|
|
||||||
if not number:
|
|
||||||
return '0'
|
|
||||||
number = str(number)
|
|
||||||
if len(number) % 3:
|
|
||||||
number = '0' * (3 - len(number) % 3) + number
|
|
||||||
return ','.join(number[i * 3:i * 3 + 3] for i in xrange(len(number) / 3)).lstrip('0')
|
|
||||||
|
|
||||||
|
|
||||||
def center(total, size):
|
def center(total, size):
|
||||||
return (total - size) / 2
|
return (total - size) / 2
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue