2021-04-12 21:17:06 +03:00
|
|
|
import curses
|
2021-04-12 22:11:38 +03:00
|
|
|
import random
|
2021-04-13 01:20:31 +03:00
|
|
|
import time
|
|
|
|
|
import copy
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
MAP_POS_X = 16
|
|
|
|
|
MAP_POS_Y = 2
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
PLAYER = 'P'
|
2021-04-14 23:50:31 +03:00
|
|
|
MONSTER = 'M'
|
2021-04-13 01:20:31 +03:00
|
|
|
EMPTY = ' '
|
2021-04-14 23:50:31 +03:00
|
|
|
DOOR = '>'
|
2021-04-13 01:20:31 +03:00
|
|
|
MARK = '!'
|
|
|
|
|
WALL = '#'
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
SIMPLE_COLOR = 1
|
|
|
|
|
ACTIVE_COLOR = 2
|
2021-04-13 01:20:31 +03:00
|
|
|
WALL_COLOR = 3
|
|
|
|
|
GOLD_COLOR = 4
|
|
|
|
|
WEAPON_COLOR = 5
|
|
|
|
|
HIGHLIGHTED_COLOR = 6
|
|
|
|
|
PLAYER_COLOR = 7
|
|
|
|
|
DOOR_COLOR = 8
|
2021-04-14 23:50:31 +03:00
|
|
|
MONSTER_COLOR = 9
|
|
|
|
|
ADD_HEALTH_COLOR = 10
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-15 00:12:26 +03:00
|
|
|
DIRECTIONS = [
|
|
|
|
|
[1, 0],
|
|
|
|
|
[-1, 0],
|
|
|
|
|
[0, 1],
|
|
|
|
|
[0, -1]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
EXTENDED_DIRECTIONS = DIRECTIONS + [
|
|
|
|
|
[1, 1],
|
|
|
|
|
[1, -1],
|
|
|
|
|
[-1, 1],
|
|
|
|
|
[-1, -1]
|
|
|
|
|
]
|
|
|
|
|
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
def begin_curses():
|
|
|
|
|
stdscr = curses.initscr()
|
|
|
|
|
curses.noecho()
|
|
|
|
|
curses.cbreak()
|
|
|
|
|
curses.curs_set(0)
|
|
|
|
|
stdscr.keypad(True)
|
2021-04-14 23:50:31 +03:00
|
|
|
#stdscr.nodelay(True)
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
curses.start_color()
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
curses.init_pair(SIMPLE_COLOR, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(ACTIVE_COLOR, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
2021-04-13 01:20:31 +03:00
|
|
|
curses.init_pair(WALL_COLOR, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(GOLD_COLOR, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(WEAPON_COLOR, curses.COLOR_CYAN, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(HIGHLIGHTED_COLOR, curses.COLOR_CYAN, curses.COLOR_BLACK)
|
2021-04-14 23:50:31 +03:00
|
|
|
curses.init_pair(PLAYER_COLOR, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
|
|
|
|
curses.init_pair(DOOR_COLOR, curses.COLOR_BLUE, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(MONSTER_COLOR, curses.COLOR_RED, curses.COLOR_BLACK)
|
|
|
|
|
curses.init_pair(ADD_HEALTH_COLOR, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
return stdscr
|
2021-04-12 21:17:06 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
|
|
|
|
|
def end_curses(stdscr):
|
2021-04-14 23:50:31 +03:00
|
|
|
#stdscr.nodelay(False)
|
2021-04-12 22:11:38 +03:00
|
|
|
stdscr.keypad(False)
|
2021-04-13 01:20:31 +03:00
|
|
|
curses.curs_set(1)
|
|
|
|
|
curses.nocbreak()
|
2021-04-12 22:11:38 +03:00
|
|
|
curses.echo()
|
|
|
|
|
curses.endwin()
|
|
|
|
|
|
|
|
|
|
|
2021-04-15 00:12:26 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
def gen_map_step(map):
|
|
|
|
|
tmp_map = copy.deepcopy(map)
|
2021-04-15 00:12:26 +03:00
|
|
|
for i in range(1, len(map) - 1):
|
|
|
|
|
for j in range(1, len(map[i]) - 1):
|
|
|
|
|
x = 0
|
|
|
|
|
for d in EXTENDED_DIRECTIONS:
|
|
|
|
|
if tmp_map[i][j] == WALL:
|
|
|
|
|
x += 1
|
|
|
|
|
if x < 2 or x >= 4:
|
|
|
|
|
map[i][j] = (EMPTY, SIMPLE_COLOR)
|
|
|
|
|
elif x == 3:
|
|
|
|
|
map[i][j] = (WALL, WALL_COLOR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_map(map, sz_x, sz_y, map_symbols,
|
|
|
|
|
automata_iterations, wall_rand_range,
|
|
|
|
|
wall_rand_gen):
|
2021-04-12 22:18:20 +03:00
|
|
|
rand_sum = 0
|
2021-04-13 01:20:31 +03:00
|
|
|
for symbol in map_symbols:
|
|
|
|
|
rand_sum += symbol[1]
|
2021-04-12 22:18:20 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
for i in range(sz_x):
|
2021-04-13 01:20:31 +03:00
|
|
|
map.append([])
|
2021-04-14 23:50:31 +03:00
|
|
|
for j in range(sz_y):
|
|
|
|
|
if i == 0 or j == 0 or i == sz_x - 1 or j == sz_y - 1:
|
|
|
|
|
map[i].append([WALL, WALL_COLOR])
|
|
|
|
|
else:
|
2021-04-15 00:12:26 +03:00
|
|
|
if random.randint(1, wall_rand_range) <= wall_rand_gen:
|
|
|
|
|
map[i].append([WALL, WALL_COLOR])
|
|
|
|
|
else:
|
|
|
|
|
map[i].append([EMPTY, SIMPLE_COLOR])
|
|
|
|
|
|
|
|
|
|
for i in range(automata_iterations):
|
|
|
|
|
gen_map_step(map)
|
|
|
|
|
|
|
|
|
|
for i in range(1, len(map) - 1):
|
|
|
|
|
for j in range(1, len(map[i]) - 1):
|
|
|
|
|
if (map[i][j][0] == EMPTY):
|
2021-04-14 23:50:31 +03:00
|
|
|
x = random.randint(1, rand_sum)
|
|
|
|
|
for symbol in map_symbols:
|
|
|
|
|
x -= symbol[1]
|
|
|
|
|
if x <= 0:
|
2021-04-15 00:12:26 +03:00
|
|
|
map[i][j] = symbol[0]
|
2021-04-14 23:50:31 +03:00
|
|
|
break
|
2021-04-12 22:11:38 +03:00
|
|
|
|
|
|
|
|
|
2021-04-15 00:12:26 +03:00
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
def map_mark_dfs(map, i, j):
|
2021-04-14 23:50:31 +03:00
|
|
|
if map[i][j][0] != EMPTY:
|
|
|
|
|
return []
|
|
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
positions = [(i, j)]
|
2021-04-14 23:50:31 +03:00
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
map[i][j] = (MARK, SIMPLE_COLOR)
|
2021-04-15 00:12:26 +03:00
|
|
|
for d in DIRECTIONS:
|
2021-04-14 23:50:31 +03:00
|
|
|
# walls on all sides, then no check needed there
|
|
|
|
|
new_positions = map_mark_dfs(map, i + d[0], j + d[1])
|
|
|
|
|
for pos in new_positions:
|
|
|
|
|
positions.append(pos)
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
return positions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_doors(map):
|
|
|
|
|
doors = []
|
|
|
|
|
tmp_map = copy.deepcopy(map)
|
2021-04-14 23:50:31 +03:00
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
for i in range(len(tmp_map)):
|
|
|
|
|
for j in range(len(tmp_map[i])):
|
|
|
|
|
if tmp_map[i][j][0] == EMPTY:
|
|
|
|
|
map_mark_dfs(tmp_map, i, j)
|
2021-04-14 23:50:31 +03:00
|
|
|
map[i][j] = [DOOR, DOOR_COLOR]
|
|
|
|
|
doors.append([i, j])
|
|
|
|
|
|
|
|
|
|
return doors
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def random_direction():
|
|
|
|
|
k = random.randint(0, 3)
|
2021-04-14 23:50:31 +03:00
|
|
|
return [((k % 2) * 2 - 1) * (k // 2),
|
|
|
|
|
((k % 2) * 2 - 1) * (1 - k // 2)]
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_monsters(map, rand_range, rand_monster):
|
|
|
|
|
monsters = []
|
|
|
|
|
for i in range(len(map)):
|
|
|
|
|
for j in range(len(map[i])):
|
|
|
|
|
if (map[i][j][0] == EMPTY):
|
|
|
|
|
if random.randint(1, rand_range) <= rand_monster:
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
monsters.append([[i, j], random_direction()])
|
2021-04-13 01:20:31 +03:00
|
|
|
# position, move direction
|
|
|
|
|
|
|
|
|
|
return monsters
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def move_monsters(map, monsters):
|
|
|
|
|
for i in range(len(monsters)):
|
2021-04-14 23:50:31 +03:00
|
|
|
pos = [0, 0]
|
|
|
|
|
pos[0] = monsters[i][0][0] + monsters[i][1][0]
|
|
|
|
|
pos[1] = monsters[i][0][1] + monsters[i][1][1]
|
|
|
|
|
if map[pos[0]][pos[1]][0] == EMPTY:
|
|
|
|
|
monsters[i][0] = pos
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
monsters[i][1] = random_direction()
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def damage_player(monsters, player_state):
|
|
|
|
|
for m in monsters:
|
|
|
|
|
if abs(player_state[0][0] - m[0][0]) + abs(player_state[0][1] - m[0][1]) <= 1:
|
|
|
|
|
player_state[1] -= 1
|
2021-04-12 22:11:38 +03:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
def game_step(map, monsters, player_state, doors):
|
|
|
|
|
#if player_pos == door for any door ?
|
2021-04-13 01:20:31 +03:00
|
|
|
move_monsters(map, monsters)
|
2021-04-14 23:50:31 +03:00
|
|
|
damage_player(monsters, player_state)
|
2021-04-13 01:20:31 +03:00
|
|
|
pass
|
2021-04-12 22:11:38 +03:00
|
|
|
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
def draw(stdscr, map, monsters, player_state):
|
|
|
|
|
if player_state[1] <= 0:
|
|
|
|
|
stdscr.addstr(max(curses.COLS // 2 - 4, 0),
|
|
|
|
|
max(curses.LINES // 2 - 4, 0), "You lose(")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
stdscr.addstr(MAP_POS_Y - 1, 0, "Lives: " + str(player_state[1]),
|
|
|
|
|
curses.color_pair(HIGHLIGHTED_COLOR))
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
for i in range(len(map)):
|
|
|
|
|
stdscr.addstr(MAP_POS_Y - 1, i + MAP_POS_X,
|
|
|
|
|
'-', curses.color_pair(SIMPLE_COLOR))
|
|
|
|
|
stdscr.addstr(len(map[0]) + MAP_POS_Y, i + MAP_POS_X,
|
|
|
|
|
'-', curses.color_pair(SIMPLE_COLOR))
|
|
|
|
|
|
|
|
|
|
for i in range(len(map[0])): # ?? better ??
|
|
|
|
|
stdscr.addstr(i + MAP_POS_Y, MAP_POS_X - 1,
|
|
|
|
|
'|', curses.color_pair(SIMPLE_COLOR))
|
|
|
|
|
stdscr.addstr(i + MAP_POS_Y, len(map) + MAP_POS_X,
|
|
|
|
|
'|', curses.color_pair(SIMPLE_COLOR))
|
|
|
|
|
|
|
|
|
|
for i in range(len(map)):
|
|
|
|
|
for j in range(len(map[i])):
|
|
|
|
|
stdscr.addstr(j + MAP_POS_Y, i + MAP_POS_X,
|
|
|
|
|
map[i][j][0], curses.color_pair(map[i][j][1]))
|
|
|
|
|
|
|
|
|
|
for m in monsters:
|
|
|
|
|
stdscr.addstr(m[0][1] + MAP_POS_Y, m[0][0] + MAP_POS_X,
|
2021-04-14 23:50:31 +03:00
|
|
|
MONSTER, curses.color_pair(MONSTER_COLOR))
|
2021-04-13 01:20:31 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
stdscr.addstr(MAP_POS_Y + player_state[0][1],
|
|
|
|
|
MAP_POS_X + player_state[0][0], PLAYER,
|
2021-04-13 01:20:31 +03:00
|
|
|
curses.color_pair(PLAYER_COLOR))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def input(stdscr): # not work
|
2021-04-14 23:50:31 +03:00
|
|
|
m = [0, 0]
|
|
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
try:
|
|
|
|
|
key = stdscr.getkey()
|
|
|
|
|
if key == 'w':
|
|
|
|
|
m[1] -= 1
|
|
|
|
|
elif key == 's':
|
|
|
|
|
m[1] += 1
|
|
|
|
|
elif key == 'a':
|
|
|
|
|
m[0] -= 1
|
|
|
|
|
elif key == 'd':
|
|
|
|
|
m[0] += 1
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
# no input
|
2021-04-14 23:50:31 +03:00
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
return m
|
|
|
|
|
pass
|
2021-04-12 21:17:06 +03:00
|
|
|
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
def move_player(map, player_state, pos_change):
|
|
|
|
|
new_player_pos = copy.deepcopy(player_state[0])
|
|
|
|
|
|
|
|
|
|
new_player_pos[0] += pos_change[0]
|
|
|
|
|
new_player_pos[1] += pos_change[1]
|
|
|
|
|
|
|
|
|
|
if map[new_player_pos[0]][new_player_pos[1]][0] != WALL:
|
|
|
|
|
player_state[0] = new_player_pos
|
|
|
|
|
|
|
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
def main():
|
2021-04-13 01:20:31 +03:00
|
|
|
map_symbols = [
|
2021-04-14 23:50:31 +03:00
|
|
|
[[EMPTY, SIMPLE_COLOR], 30],
|
|
|
|
|
[[WALL, WALL_COLOR], 10],
|
|
|
|
|
[['$', GOLD_COLOR], 1],
|
|
|
|
|
[['/', WEAPON_COLOR], 2],
|
|
|
|
|
[['+', ADD_HEALTH_COLOR], 1]
|
2021-04-13 01:20:31 +03:00
|
|
|
]
|
2021-04-12 22:11:38 +03:00
|
|
|
|
|
|
|
|
stdscr = begin_curses()
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
map_size = [20, 20]
|
2021-04-13 01:20:31 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
player_state = [[0, 0], 10] # pos, lives
|
2021-04-13 01:20:31 +03:00
|
|
|
|
2021-04-12 22:11:38 +03:00
|
|
|
map = []
|
|
|
|
|
|
2021-04-15 00:12:26 +03:00
|
|
|
generate_map(map, map_size[0], map_size[1], map_symbols, 100, 100, 45)
|
2021-04-13 01:20:31 +03:00
|
|
|
|
|
|
|
|
doors = generate_doors(map)
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
player_state[0] = doors[0]
|
|
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
monsters = generate_monsters(map, 100, 7)
|
|
|
|
|
|
|
|
|
|
main_loop_exception = False
|
2021-04-12 22:11:38 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
#try:
|
|
|
|
|
while(True):
|
|
|
|
|
stdscr.clear()
|
|
|
|
|
game_step(map, monsters, player_state, doors)
|
|
|
|
|
draw(stdscr, map, monsters, player_state)
|
|
|
|
|
stdscr.refresh()
|
|
|
|
|
pos_change = input(stdscr)
|
|
|
|
|
move_player(map, player_state, pos_change)
|
|
|
|
|
#time.sleep(0.1)
|
2021-04-13 01:20:31 +03:00
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
#except:
|
|
|
|
|
# main_loop_exception = True
|
2021-04-12 22:11:38 +03:00
|
|
|
|
|
|
|
|
end_curses(stdscr)
|
|
|
|
|
|
2021-04-13 01:20:31 +03:00
|
|
|
if main_loop_exception:
|
|
|
|
|
print("Error during main loop");
|
|
|
|
|
|
|
|
|
|
|
2021-04-14 23:50:31 +03:00
|
|
|
main()
|