Move all root .py files into playscii/ package directory. Rename playscii.py to app.py, add __main__.py entry point. Convert bare imports to relative (within package) and absolute (in formats/ and games/). Data dirs stay at root.
132 lines
4.2 KiB
Python
132 lines
4.2 KiB
Python
from random import choice
|
|
|
|
from playscii.art import TileIter
|
|
from playscii.game_object import GameObject
|
|
|
|
# TODO:
|
|
# solver? https://stackoverflow.com/questions/1430962/how-to-optimally-solve-the-flood-fill-puzzle
|
|
|
|
|
|
TILE_COLORS = [3, 4, 5, 6, 7]
|
|
STARTING_TURNS = 15
|
|
BOARD_WIDTH, BOARD_HEIGHT = 10, 10
|
|
|
|
# game states
|
|
GS_PLAYING = 0
|
|
GS_WON = 1
|
|
GS_LOST = 2
|
|
|
|
|
|
class Board(GameObject):
|
|
generate_art = True
|
|
art_width, art_height = BOARD_WIDTH, BOARD_HEIGHT
|
|
art_charset = "jpetscii"
|
|
art_palette = "c64_original"
|
|
handle_key_events = True
|
|
|
|
def __init__(self, world, obj_data):
|
|
GameObject.__init__(self, world, obj_data)
|
|
self.reset()
|
|
|
|
def reset(self):
|
|
for frame, layer, x, y in TileIter(self.art):
|
|
color = choice(TILE_COLORS)
|
|
self.art.set_color_at(frame, layer, x, y, color, False)
|
|
self.captured_tiles = [(0, 0)]
|
|
# before play, flood with color of starting (top left) tile
|
|
start_color = self.art.get_bg_color_index_at(0, 0, 0, 0)
|
|
self.flood_with_color(start_color)
|
|
self.turns = STARTING_TURNS
|
|
self.game_state = GS_PLAYING
|
|
|
|
def get_adjacent_tiles(self, x, y):
|
|
tiles = []
|
|
if x > 0:
|
|
tiles.append((x - 1, y))
|
|
if x < BOARD_WIDTH - 1:
|
|
tiles.append((x + 1, y))
|
|
if y > 0:
|
|
tiles.append((x, y - 1))
|
|
if y < BOARD_HEIGHT - 1:
|
|
tiles.append((x, y + 1))
|
|
return tiles
|
|
|
|
def flood_with_color(self, flood_color):
|
|
# set captured tiles to new color
|
|
for tile_x, tile_y in self.captured_tiles:
|
|
self.art.set_color_at(0, 0, tile_x, tile_y, flood_color, False)
|
|
# capture like-colored tiles adjacent to captured tiles
|
|
for frame, layer, x, y in TileIter(self.art):
|
|
if (x, y) not in self.captured_tiles:
|
|
continue
|
|
adjacents = self.get_adjacent_tiles(x, y)
|
|
for adj_x, adj_y in adjacents:
|
|
adj_color = self.art.get_bg_color_index_at(frame, layer, adj_x, adj_y)
|
|
if adj_color == flood_color:
|
|
self.captured_tiles.append((adj_x, adj_y))
|
|
|
|
def color_picked(self, color):
|
|
self.flood_with_color(TILE_COLORS[color])
|
|
self.turns -= 1
|
|
if len(self.captured_tiles) == BOARD_WIDTH * BOARD_HEIGHT:
|
|
self.game_state = GS_WON
|
|
elif self.turns == 0:
|
|
self.game_state = GS_LOST
|
|
# TODO: reset after delay / feedback?
|
|
|
|
def handle_key_down(self, key, shift_pressed, alt_pressed, ctrl_pressed):
|
|
if self.game_state != GS_PLAYING:
|
|
self.reset()
|
|
return
|
|
# get list of valid keys from length of tile_colors
|
|
valid_keys = [f"{str(i + 1)}" for i in range(len(TILE_COLORS))]
|
|
if key not in valid_keys:
|
|
return
|
|
key = int(key) - 1
|
|
self.color_picked(key)
|
|
|
|
|
|
class ColorBar(GameObject):
|
|
generate_art = True
|
|
art_width, art_height = len(TILE_COLORS), 1
|
|
art_charset = "jpetscii"
|
|
art_palette = "c64_original"
|
|
|
|
def __init__(self, world, obj_data):
|
|
GameObject.__init__(self, world, obj_data)
|
|
i = 0
|
|
for frame, layer, x, y in TileIter(self.art):
|
|
self.art.set_color_at(frame, layer, x, y, TILE_COLORS[i], False)
|
|
self.art.write_string(frame, layer, x, y, str(i + 1), 1)
|
|
i += 1
|
|
|
|
|
|
class TurnsBar(GameObject):
|
|
text = "turns: %s"
|
|
generate_art = True
|
|
art_width, art_height = len(text) + 3, 1
|
|
art_charset = "jpetscii"
|
|
art_palette = "c64_original"
|
|
|
|
def __init__(self, world, obj_data):
|
|
GameObject.__init__(self, world, obj_data)
|
|
self.board = None
|
|
|
|
def pre_first_update(self):
|
|
self.board = self.world.get_all_objects_of_type("Board")[0]
|
|
|
|
def draw_text(self):
|
|
if not self.board:
|
|
return
|
|
self.art.clear_frame_layer(0, 0)
|
|
new_text = self.text % self.board.turns
|
|
if self.board.game_state == GS_WON:
|
|
new_text = "won!!"
|
|
elif self.board.game_state == GS_LOST:
|
|
new_text = "lost :("
|
|
color = TILE_COLORS[self.board.turns % len(TILE_COLORS)]
|
|
self.art.write_string(0, 0, 0, 0, new_text, color, 0)
|
|
|
|
def update(self):
|
|
GameObject.update(self)
|
|
self.draw_text()
|