310 lines
9.9 KiB
Python
310 lines
9.9 KiB
Python
import os
|
|
import random
|
|
|
|
from pynput import keyboard
|
|
|
|
from assets.maps.dh1 import levels as dh1_levels
|
|
from assets.maps.dh2 import levels as dh2_levels
|
|
from assets.maps.mas_sasquatch import levels as mas_sasquatch_levels
|
|
from assets.maps.microban import levels as microban_levels
|
|
from assets.maps.microcosmos import levels as microcosmos_levels
|
|
from assets.maps.minicosmos import levels as minicosmos_levels
|
|
from assets.maps.nabokosmos import levels as nabokosmos_levels
|
|
from assets.maps.picokosmos import levels as picokosmos_levels
|
|
from assets.maps.sasquatch import levels as sasquatch_levels
|
|
from assets.maps.sasquatch_iii import levels as sasquatch_iii_levels
|
|
from assets.maps.sasquatch_iv import levels as sasquatch_iv_levels
|
|
from assets.maps.sasquatch_v import levels as sasquatch_v_levels
|
|
from assets.maps.yoshio_murase import levels as yoshio_murase_levels
|
|
from assets.text import logo, lose, win, help
|
|
|
|
|
|
WORLD_MAP = {
|
|
'dh1': dh1_levels,
|
|
'dh2': dh2_levels,
|
|
'mas_sasquatch': mas_sasquatch_levels,
|
|
'microban': microban_levels,
|
|
'microcosmos': microcosmos_levels,
|
|
'minicosmos': minicosmos_levels,
|
|
'nabokosomos': nabokosmos_levels,
|
|
'picokosmos': picokosmos_levels,
|
|
'sasquatch': sasquatch_levels,
|
|
'sasquatch_iii': sasquatch_iii_levels,
|
|
'sasquatch_iv': sasquatch_iv_levels,
|
|
'sasquatch_v': sasquatch_v_levels,
|
|
'yoshio_murase': yoshio_murase_levels
|
|
}
|
|
|
|
|
|
class Game:
|
|
def __init__(self):
|
|
self.map_instance = None
|
|
self.level = 0
|
|
self.lives = 3
|
|
self.points = 0
|
|
self.total_moves = 0
|
|
self.level_moves = {}
|
|
|
|
def initialize_level(self):
|
|
self.map_instance = Map()
|
|
self.map_instance.generate_map_array()
|
|
self.loop()
|
|
|
|
def loop(self):
|
|
while self.map_instance.break_condition:
|
|
self.map_instance.display()
|
|
self.map_instance.wait_for_input()
|
|
self.map_instance.check_win_condition()
|
|
|
|
self.initialize_level()
|
|
|
|
def handle_points(self, points):
|
|
self.points += points
|
|
if self.points + points < 0:
|
|
self.points = 0
|
|
|
|
|
|
class Map:
|
|
def __init__(self):
|
|
self.level = g.level
|
|
self.level_map = levels[self.level][0]
|
|
self.level_par = levels[self.level][1]
|
|
self.map_array = []
|
|
self.storage_locations = []
|
|
|
|
self.listener = None
|
|
|
|
self.player_x = None
|
|
self.player_y = None
|
|
self.previous_element = ' '
|
|
|
|
self.win = False
|
|
self.lose = False
|
|
self.break_condition = True
|
|
|
|
self.total_win = g.level + 1 == len(levels)
|
|
self.final_points_given = False
|
|
|
|
def generate_map_array(self):
|
|
g.level_moves[self.level] = 0
|
|
|
|
level_array = self.level_map.split('\n')
|
|
|
|
for idx, line in enumerate(level_array):
|
|
if idx == 0 or idx == len(level_array) - 1:
|
|
continue
|
|
|
|
row_elements = list(line)
|
|
|
|
if '@' in row_elements:
|
|
self.player_y = idx - 1
|
|
self.player_x = row_elements.index('@')
|
|
|
|
for storage_type in ['.', '*']:
|
|
if storage_type in row_elements:
|
|
for xidx, element in enumerate(row_elements):
|
|
if element == storage_type:
|
|
self.storage_locations.append((idx - 1, xidx))
|
|
|
|
self.map_array.append(row_elements)
|
|
|
|
def display(self):
|
|
if self.total_win and self.win and not self.final_points_given:
|
|
self.final_points_given = True
|
|
g.handle_points(self.calculate_points())
|
|
|
|
os.system('clear')
|
|
for storage_location in self.storage_locations:
|
|
if self.map_array[storage_location[0]][storage_location[1]] == ' ':
|
|
self.map_array[storage_location[0]][storage_location[1]] = '.'
|
|
print(logo)
|
|
print(f'world: {world}')
|
|
print(f'lvl: {g.level} | mvs: {g.level_moves[self.level]} | pts: {g.points} | lives: {g.lives}')
|
|
|
|
if self.lose:
|
|
print(lose)
|
|
elif self.total_win and self.win:
|
|
print(win)
|
|
else:
|
|
for row in self.map_array:
|
|
print('\t', ''.join(row))
|
|
|
|
if self.total_win:
|
|
print('\n\n Press [r] to to play again or [q] to quit')
|
|
elif self.win:
|
|
print('\n\n NICE! Press [w] to continue!')
|
|
elif self.lose:
|
|
print('\n\n Press [r] to retry')
|
|
else:
|
|
print('\n\npress [r] to reset the map')
|
|
|
|
def on_release(self, key):
|
|
self.listener = None
|
|
if 'char' in dir(key):
|
|
if key.char == 'q':
|
|
self.quit()
|
|
if key.char == '?':
|
|
os.system('clear')
|
|
print(help)
|
|
input('Back to the game? Press any key to contiue: ')
|
|
os.system('clear')
|
|
|
|
if (self.total_win and self.win) or self.lose:
|
|
if key.char == 'r':
|
|
self.retry()
|
|
else:
|
|
if key.char == 'h' or key.char == '4':
|
|
self.move('left')
|
|
if key.char == 'l' or key.char == '6':
|
|
self.move('right')
|
|
if key.char == 'j' or key.char == '2':
|
|
self.move('down')
|
|
if key.char == 'k' or key.char == '8':
|
|
self.move('up')
|
|
if key.char == 'y' or key.char == '7':
|
|
self.move('up left')
|
|
if key.char == 'u' or key.char == '9':
|
|
self.move('up right')
|
|
if key.char == 'b' or key.char == '1':
|
|
self.move('down left')
|
|
if key.char == 'n' or key.char == '3':
|
|
self.move('down right')
|
|
if key.char == 'r':
|
|
self.reset_level()
|
|
if self.win:
|
|
if key.char == 'w':
|
|
self.win_level()
|
|
|
|
return False
|
|
|
|
def wait_for_input(self):
|
|
with keyboard.Listener(on_press=self.on_release) as self.listener:
|
|
self.listener.join()
|
|
|
|
def move(self, direction):
|
|
g.level_moves[self.level] += 1
|
|
g.total_moves += 1
|
|
|
|
tmp_player_x, tmp_player_y = self.calculate_future_position(self.player_x, self.player_y, direction)
|
|
|
|
future_position = self.map_array[tmp_player_y][tmp_player_x]
|
|
|
|
if future_position not in ['#']:
|
|
can_move = True
|
|
if future_position in ['0', '*']:
|
|
future_position = ' '
|
|
can_move = self.push_boulder(tmp_player_y, tmp_player_x, direction)
|
|
|
|
if can_move:
|
|
self.map_array[self.player_y][self.player_x] = self.previous_element
|
|
self.previous_element = future_position
|
|
self.map_array[tmp_player_y][tmp_player_x] = '@'
|
|
self.player_x = tmp_player_x
|
|
self.player_y = tmp_player_y
|
|
|
|
def calculate_future_position(self, x, y, direction):
|
|
dir_list = direction.split(' ')
|
|
|
|
if 'right' in dir_list:
|
|
x += 1
|
|
elif 'left' in dir_list:
|
|
x -= 1
|
|
|
|
if 'down' in dir_list:
|
|
y += 1
|
|
elif 'up' in dir_list:
|
|
y -= 1
|
|
|
|
return x, y
|
|
|
|
def push_boulder(self, tmp_player_y, tmp_player_x, direction):
|
|
if len(direction.split(' ')) > 1:
|
|
return False
|
|
|
|
tmp_boulder_x, tmp_boulder_y = self.calculate_future_position(tmp_player_x, tmp_player_y, direction)
|
|
|
|
future_position = self.map_array[tmp_boulder_y][tmp_boulder_x]
|
|
|
|
if future_position not in ['#', '0', '*']:
|
|
if future_position == '.':
|
|
self.map_array[tmp_boulder_y][tmp_boulder_x] = '*'
|
|
else:
|
|
self.map_array[tmp_boulder_y][tmp_boulder_x] = '0'
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def check_win_condition(self):
|
|
self.win = True
|
|
for yidx, line in enumerate(self.map_array):
|
|
for xidx, element in enumerate(line):
|
|
if element == '0':
|
|
if (yidx, xidx) not in self.storage_locations:
|
|
self.win = False
|
|
|
|
def win_level(self):
|
|
if not self.total_win:
|
|
g.handle_points(self.calculate_points())
|
|
g.level += 1
|
|
self.break_condition = False
|
|
|
|
def calculate_points(self):
|
|
multiplier = 1
|
|
penality = 0
|
|
|
|
if g.level_moves[g.level] < self.level_par:
|
|
multiplier = 1.5
|
|
elif g.level_moves[g.level] == self.level_par:
|
|
multiplier = 1.2
|
|
elif g.level_moves[g.level] > self.level_par:
|
|
penality = (g.level_moves[g.level] - self.level_par) * 0.1
|
|
|
|
return (10 - penality) * multiplier
|
|
|
|
def reset_level(self):
|
|
g.lives -= 1
|
|
g.handle_points(-3.5)
|
|
if g.lives <= 0:
|
|
self.lose = True
|
|
else:
|
|
self.break_condition = False
|
|
|
|
def retry(self):
|
|
global g
|
|
g = Game()
|
|
g.initialize_level()
|
|
|
|
def quit(self):
|
|
os.system('clear')
|
|
response = input('Are you sure you want to quit? [Y/N]: ')[-1]
|
|
if response.lower() == 'y':
|
|
os.system('clear')
|
|
os._exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
world_map_key_list = list(WORLD_MAP.keys())
|
|
|
|
def get_world_response():
|
|
response = input('Which world would you like to play? Input a number: ')
|
|
|
|
if response not in [str(idx) for idx, _ in enumerate(world_map_key_list)] and response != str(len(world_map_key_list)):
|
|
return get_world_response()
|
|
|
|
return response
|
|
|
|
os.system('clear')
|
|
for idx, name in enumerate(world_map_key_list):
|
|
print(f'[{idx}] {name}')
|
|
random_idx = idx + 1
|
|
print(f'[{random_idx}] random world')
|
|
|
|
response = int(get_world_response())
|
|
if int(response) == random_idx:
|
|
response = random.randint(0, len(world_map_key_list))
|
|
world = list(WORLD_MAP.keys())[response]
|
|
levels = WORLD_MAP.get(world)
|
|
|
|
g = Game()
|
|
g.initialize_level()
|
|
os.system('clear')
|