This commit is contained in:
Yohann D'ANELLO 2021-01-10 22:08:42 +01:00
parent 01cdea6edc
commit 9df1ac7883
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
4 changed files with 38 additions and 34 deletions

View File

@ -2,7 +2,6 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from json import JSONDecodeError
from random import randint
from typing import Any, Optional, List
import curses
import json

View File

@ -4,7 +4,7 @@
from enum import Enum, auto
from math import ceil, sqrt
from itertools import product
from random import choice, choices, randint
from random import choice, randint
from typing import List, Optional, Any, Dict, Tuple
from queue import PriorityQueue
from functools import reduce

View File

@ -20,14 +20,15 @@ DEFAULT_PARAMS = {
"max_h_corr": 12,
"large_circular_room": .10,
"circular_holes": .5,
"loop_tries" : 40,
"loop_max" : 5,
"loop_threshold" : 15,
"spawn_per_region" : [1, 2],
"loop_tries": 40,
"loop_max": 5,
"loop_threshold": 15,
"spawn_per_region": [1, 2],
}
def dist(level, y1, x1, y2, x2):
copy = [[t for t in l] for l in level]
def dist(level: List[List[Tile]], y1: int, x1: int, y2: int, x2: int) -> int:
copy = [[t for t in row] for row in level]
dist = -1
queue, next_queue = [[y1, x1]], [0]
while next_queue:
@ -36,7 +37,7 @@ def dist(level, y1, x1, y2, x2):
while queue:
y, x = queue.pop()
copy[y][x] = Tile.EMPTY
if y == y2 and x == x2:
if y == y2 and x == x2:
return dist
for y, x in Map.neighbourhood(copy, y, x):
if copy[y][x].can_walk():
@ -44,6 +45,7 @@ def dist(level, y1, x1, y2, x2):
queue = next_queue
return -1
class Generator:
def __init__(self, params: dict = None):
self.params = params or DEFAULT_PARAMS
@ -89,7 +91,7 @@ class Generator:
level[y - door_y + ry][x - door_x + rx] = Tile.FLOOR
@staticmethod
def add_loop(level: List[List[Tile]], y: int, x: int) -> None:
def add_loop(level: List[List[Tile]], y: int, x: int) -> bool:
h, w = len(level), len(level[0])
if level[y][x] != Tile.EMPTY:
return False
@ -106,18 +108,21 @@ class Generator:
# if adding the path would make the two tiles significantly closer
# and its sides don't touch already placed terrain, build it
def verify_sides():
for Dx, Dy in [[dy, dx], [-dy, -dx]]:
for i in range(1, y2-y1+x2-x1):
if not(0<= y1+Dy+i*dy < h and 0 <= x1+Dx+i*dx < w) or \
level[y1+Dy+i*dy][x1+Dx+i*dx].can_walk():
def verify_sides() -> bool:
for delta_x, delta_y in [[dy, dx], [-dy, -dx]]:
for i in range(1, y2 - y1 + x2 - x1):
if not (0 <= y1 + delta_y + i * dy < h
and 0 <= x1 + delta_x + i * dx < w) or \
level[y1 + delta_y + i * dy][x1 + delta_x
+ i * dx]\
.can_walk():
return False
return True
if dist(level, y1, x1, y2, x2) < 20 and verify_sides():
y, x = y1+dy, x1+dx
y, x = y1 + dy, x1 + dx
while level[y][x] == Tile.EMPTY:
level[y][x] = Tile.FLOOR
y, x = y+dy, x+dx
y, x = y + dy, x + dx
return True
return False
@ -143,7 +148,8 @@ class Generator:
return 0, 0, 0, 0
@staticmethod
def build_door(room, y, x, dy, dx, length):
def build_door(room: List[List[Tile]], y: int, x: int,
dy: int, dx: int, length: int) -> bool:
rh, rw = len(room), len(room[0])
# verify we are pointing away from a floor tile
if not(0 <= y - dy < rh and 0 <= x - dx < rw) \
@ -155,7 +161,7 @@ class Generator:
if 0 <= ny < rh and 0 <= nx < rw \
and room[ny][nx] != Tile.EMPTY:
return False
for i in range(length+1):
for i in range(length + 1):
if room[y + i * dy][x + i * dx] != Tile.EMPTY:
return False
for i in range(length):
@ -163,8 +169,8 @@ class Generator:
return True
@staticmethod
def attach_door(room: List[List[Tile]], h_sup: int, w_sup: int,
h_off: int, w_off: int) -> Tuple[int, int, int, int]:
def attach_door(room: List[List[Tile]], h_sup: int, w_sup: int,
h_off: int, w_off: int) -> Tuple[int, int, int, int]:
length = h_sup + w_sup
dy, dx = 0, 0
if length > 0:
@ -228,7 +234,7 @@ class Generator:
-> Tuple[List[list], int, int, int, int]:
return self.create_circular_room()
def register_spawn_area(self, area:List[List[Tile]]):
def register_spawn_area(self, area: List[List[Tile]]) -> None:
spawn_positions = []
for y, line in enumerate(area):
for x, tile in enumerate(line):
@ -236,13 +242,13 @@ class Generator:
spawn_positions.append([y, x])
self.queued_area = spawn_positions
def update_spawnable(self, y, x):
if self.queued_area != None:
translated_area = [[y+ry, x+rx] for ry, rx in self.queued_area]
def update_spawnable(self, y: int, x: int) -> None:
if self.queued_area is not None:
translated_area = [[y + ry, x + rx] for ry, rx in self.queued_area]
self.spawn_areas.append(translated_area)
self.queued_area = None
def populate(self, rv):
def populate(self, rv: Map) -> None:
min_c, max_c = self.params["spawn_per_region"]
for region in self.spawn_areas:
entity_count = randint(min_c, max_c)
@ -259,7 +265,7 @@ class Generator:
# the starting room must have no corridor
mem, self.params["corridor_chance"] = self.params["corridor_chance"], 0
starting_room, _, _, _, _ = self.create_random_room(spawnable = False)
starting_room, _, _, _, _ = self.create_random_room(spawnable=False)
dim_v, dim_h = len(starting_room), len(starting_room[0])
pos_y, pos_x = randint(0, height - dim_v - 1),\
randint(0, width - dim_h - 1)
@ -297,7 +303,7 @@ class Generator:
while tries < self.params["loop_tries"] and \
loops < self.params["loop_max"]:
tries += 1
y, x = randint(0, height-1), randint(0, width-1)
y, x = randint(0, height - 1), randint(0, width - 1)
loops += self.add_loop(level, y, x)
# place an exit ladder

View File

@ -13,10 +13,10 @@ from squirrelbattle.display.texturepack import TexturePack
class TestBroguelike(unittest.TestCase):
def setUp(self) -> None:
self.generator = broguelike.Generator()
self.stom = lambda x : Map.load_from_string("0 0\n" + x)
self.mtos = lambda x : x.draw_string(TexturePack.ASCII_PACK)
self.stom = lambda x: Map.load_from_string("0 0\n" + x)
self.mtos = lambda x: x.draw_string(TexturePack.ASCII_PACK)
def test_dist(self):
def test_dist(self) -> None:
m = self.stom(".. ..\n ... ")
distance = broguelike.dist(m.tiles, 0, 0, 0, 4)
self.assertEqual(distance, 6)
@ -37,7 +37,7 @@ class TestBroguelike(unittest.TestCase):
queue += Map.neighbourhood(grid, y, x)
return not any([t.can_walk() for row in grid for t in row])
def test_build_doors(self):
def test_build_doors(self) -> None:
m = self.stom(". .\n. .\n. .\n")
self.assertFalse(self.generator.build_door(m.tiles, 1, 1, 0, 1, 2))
@ -46,11 +46,10 @@ class TestBroguelike(unittest.TestCase):
self.assertTrue(self.is_connex(m.tiles))
def test_loops(self) -> None:
m = self.stom(3*".. ..\n")
m = self.stom(3 * ".. ..\n")
self.generator.add_loop(m.tiles, 1, 3)
s = self.mtos(m)
self.assertEqual(s, ".. ..\n.......\n.. ..")
self.assertFalse(self.generator.add_loop(m.tiles, 0, 0))
m = self.stom("...\n. .\n...")
self.assertFalse(self.generator.add_loop(m.tiles, 1, 1))