Strategická: Generátor kopců
This commit is contained in:
parent
281567422e
commit
82c25830ca
3 changed files with 105 additions and 0 deletions
103
server/bin/gen_hills
Executable file
103
server/bin/gen_hills
Executable file
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import numpy as np
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--seed", default=1, type=int, help="Random seed.")
|
||||
parser.add_argument("--threshold", default=0.4, type=float, help="Higher threshold = less hills.")
|
||||
parser.add_argument("--safezone", default=3.0, type=float, help="Size of hill-free area around home bases.")
|
||||
parser.add_argument("--size", default=(30, 30), type=int, nargs=2, help="Width and height for team.")
|
||||
parser.add_argument("--res", default=(10, 10), type=int, nargs=2, help="Higher res = more smaller hills. Must divide size.")
|
||||
|
||||
|
||||
def main():
|
||||
np.random.seed(args.seed)
|
||||
# base noise profile
|
||||
noise = generate_perlin_noise_2d(
|
||||
args.size,
|
||||
args.res,
|
||||
tileable=(True, True),
|
||||
)
|
||||
|
||||
# make it less likely for hills to be close to home bases
|
||||
home_distance_tile = np.fromfunction(distance_decay, args.size, dtype=np.float32)
|
||||
home_distance = np.sum([
|
||||
home_distance_tile,
|
||||
np.flip(home_distance_tile, axis=0),
|
||||
np.flip(home_distance_tile, axis=1),
|
||||
np.flip(home_distance_tile, axis=(0,1)),
|
||||
], axis=0)
|
||||
|
||||
hills = np.where(noise - home_distance > args.threshold, "x", ".")
|
||||
rows = ["".join(row) for row in hills]
|
||||
config = {
|
||||
"width_per_team": args.size[0],
|
||||
"height_per_team": args.size[1],
|
||||
"hills": rows
|
||||
}
|
||||
print(json.dumps(config, indent=4))
|
||||
|
||||
|
||||
def distance_decay(x, y):
|
||||
return np.exp(-np.sqrt(x*x + y*y) / args.safezone)
|
||||
|
||||
|
||||
# Source:
|
||||
# https://github.com/pvigier/perlin-numpy/blob/master/perlin_numpy/perlin2d.py
|
||||
|
||||
def interpolant(t):
|
||||
return t*t*t*(t*(t*6 - 15) + 10)
|
||||
|
||||
|
||||
def generate_perlin_noise_2d(
|
||||
shape, res, tileable=(False, False), interpolant=interpolant
|
||||
):
|
||||
"""Generate a 2D numpy array of perlin noise.
|
||||
Args:
|
||||
shape: The shape of the generated array (tuple of two ints).
|
||||
This must be a multple of res.
|
||||
res: The number of periods of noise to generate along each
|
||||
axis (tuple of two ints). Note shape must be a multiple of
|
||||
res.
|
||||
tileable: If the noise should be tileable along each axis
|
||||
(tuple of two bools). Defaults to (False, False).
|
||||
interpolant: The interpolation function, defaults to
|
||||
t*t*t*(t*(t*6 - 15) + 10).
|
||||
Returns:
|
||||
A numpy array of shape shape with the generated noise.
|
||||
Raises:
|
||||
ValueError: If shape is not a multiple of res.
|
||||
"""
|
||||
delta = (res[0] / shape[0], res[1] / shape[1])
|
||||
d = (shape[0] // res[0], shape[1] // res[1])
|
||||
grid = np.mgrid[0:res[0]:delta[0], 0:res[1]:delta[1]]\
|
||||
.transpose(1, 2, 0) % 1
|
||||
# Gradients
|
||||
angles = 2*np.pi*np.random.rand(res[0]+1, res[1]+1)
|
||||
gradients = np.dstack((np.cos(angles), np.sin(angles)))
|
||||
if tileable[0]:
|
||||
gradients[-1, :] = gradients[0, :]
|
||||
if tileable[1]:
|
||||
gradients[:, -1] = gradients[:, 0]
|
||||
gradients = gradients.repeat(d[0], 0).repeat(d[1], 1)
|
||||
g00 = gradients[:-d[0], :-d[1]]
|
||||
g10 = gradients[d[0]:, :-d[1]]
|
||||
g01 = gradients[:-d[0], d[1]:]
|
||||
g11 = gradients[d[0]:, d[1]:]
|
||||
# Ramps
|
||||
n00 = np.sum(np.dstack((grid[:, :, 0], grid[:, :, 1])) * g00, 2)
|
||||
n10 = np.sum(np.dstack((grid[:, :, 0]-1, grid[:, :, 1])) * g10, 2)
|
||||
n01 = np.sum(np.dstack((grid[:, :, 0], grid[:, :, 1]-1)) * g01, 2)
|
||||
n11 = np.sum(np.dstack((grid[:, :, 0]-1, grid[:, :, 1]-1)) * g11, 2)
|
||||
# Interpolation
|
||||
t = interpolant(grid)
|
||||
n0 = n00*(1-t[:, :, 0]) + t[:, :, 0]*n10
|
||||
n1 = n01*(1-t[:, :, 0]) + t[:, :, 0]*n11
|
||||
return np.sqrt(2)*((1-t[:, :, 1])*n0 + t[:, :, 1]*n1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parser.parse_args([] if "__file__" not in globals() else None)
|
||||
main()
|
|
@ -16,6 +16,7 @@ lxml==4.9.1
|
|||
MarkupSafe==2.1.1
|
||||
mypy==0.971
|
||||
mypy-extensions==0.4.3
|
||||
numpy==1.23.3
|
||||
packaging==21.3
|
||||
pikepdf==5.6.1
|
||||
Pillow==9.2.0
|
||||
|
|
|
@ -27,6 +27,7 @@ setuptools.setup(
|
|||
'dateutils',
|
||||
'flask_bootstrap',
|
||||
'flask_sqlalchemy',
|
||||
'numpy',
|
||||
'pikepdf',
|
||||
'pillow',
|
||||
'psycopg2',
|
||||
|
|
Loading…
Reference in a new issue