Compare commits

...

3 Commits

Author SHA1 Message Date
Mistmoon 3280b6f013
Merge pull request #163 from Hang-THU/dev
MapGeneratorForTHUAI8
2025-04-07 20:38:21 +08:00
Hang-THU 6990f99398
Merge branch 'eesast:dev' into dev 2025-04-07 20:31:39 +08:00
Henry 66573ea894 feat: MapGeneratorForTHUAI8 2025-04-07 20:32:04 +08:00
24 changed files with 2164 additions and 0 deletions

View File

@ -0,0 +1,3 @@
# THUAI7 随机地图生成器
地图生成逻辑极为简单,有待其他大佬进一步改进。

View File

@ -0,0 +1,62 @@
#paint {
float: left;
}
#paint canvas {
border: 1px solid #333;
border-radius: 10px;
cursor: crosshair;
margin: 0 20px 20px 0;
}
#color-picker {
float: left;
}
#color-picker div {
width: 120px;
height: 40px;
text-align: center;
cursor: pointer;
margin: 14px;
border-radius: 10px;
border: 1px solid #000;
}
#color-picker div:hover {
border: 1px solid #333;
box-shadow: 0 0 5px #333;
text-shadow: 0 0 5px #333;
}
#color-picker div p {
font-size: 16px;
font-weight: 500;
line-height: 40px;
margin: 0;
}
#random-settings {
float: left;
}
#random-settings p {
font-size: 16px;
font-weight: 500;
margin: 0 0 10px;
text-align: right;
}
#random-settings p:hover {
color: #025b9e;
}
#random-settings input {
border-radius: 5px;
border: 1px solid #333;
width: 64px;
}
#operate {
clear: both;
}

View File

@ -0,0 +1,185 @@
html {
box-sizing: border-box;
font-family: 'Roboto', sans-serif;
background-color: #fff;
}
header {
background-color: #fff;
border-bottom: 1px solid #eee;
height: 60px;
line-height: 60px;
position: fixed;
top: 0;
width: 100%;
z-index: 999;
}
header .logo {
float: left;
margin-left: 30px;
}
header .logo a {
color: #333;
font-size: 20px;
font-weight: 700;
text-decoration: none;
}
header .logo a:hover {
color: #025b9e;
}
header .logo img {
height: 40px;
margin-top: 10px;
}
header .top-nav {
float: right;
margin-right: 30px;
}
header .top-nav ul {
list-style: none;
margin: 0;
padding: 0;
}
header .top-nav ul li {
display: inline-block;
margin-left: 20px;
position: relative;
}
header .top-nav ul li a {
color: #333;
font-size: 16px;
font-weight: 500;
text-decoration: none;
}
header .top-nav ul li a:hover {
color: #025b9e;
}
main {
margin-top: 60px;
padding: 30px;
}
main h1 {
color: #333;
font-size: 24px;
font-weight: 700;
margin: 0 0 20px;
}
main h2 {
color: #333;
font-size: 20px;
font-weight: 700;
margin: 0 0 20px;
}
main p {
color: #333;
font-size: 16px;
font-weight: 400;
line-height: 1.5;
margin: 0 0 20px;
}
main a {
color: #027dcd;
font-size: 16px;
font-weight: 500;
text-decoration: none;
}
main a:hover {
color: #025b9e;
}
main ul {
/* list-style: none; */
margin: 0;
/* padding: 0; */
}
main ul li {
margin-bottom: 20px;
}
main ul li a {
color: #333;
font-size: 16px;
font-weight: 500;
/* text-decoration: none; */
}
main ul li a:hover {
color: #025b9e;
}
main button {
background-color: #027dcd;
border: 0;
border-radius: 10px;
color: #fff;
cursor: pointer;
font-size: 16px;
font-weight: 500;
height: 40px;
margin-bottom: 20px;
padding: 0 20px;
}
main button:hover {
background-color: #025b9e;
box-shadow: 0 0 5px #333;
text-shadow: 0 0 5px #333;
}
main fieldset {
border: 1px solid #333;
border-radius: 10px;
margin-bottom: 20px;
padding: 20px;
}
main fieldset legend {
color: #333;
font-size: 16px;
font-weight: 500;
}
main fieldset label {
color: #333;
font-size: 16px;
font-weight: 500;
}
main fieldset input[type="text"],
main fieldset input[type="email"],
main fieldset input[type="password"],
main fieldset select {
border: 1px solid #eee;
border-radius: 10px;
color: #333;
font-size: 16px;
font-weight: 400;
height: 40px;
margin-bottom: 20px;
padding: 0 10px;
width: 100%;
}
main fieldset input[type="text"]:focus,
main fieldset input[type="email"]:focus,
main fieldset input[type="password"]:focus,
main fieldset select:focus {
border: 1px solid #333;
box-shadow: 0 0 5px #333;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,321 @@
var canvas = document.getElementById("map");
var ctx = canvas.getContext("2d");
var currentColor = 0;
var map = new Array(50);
for (var i = 0; i < 50; i++) {
map[i] = new Array(50);
for (var j = 0; j < 50; j++) {
map[i][j] = 0;
}
}
var color = [
"#ED1C24", // Home
"#FFFFFF", // Space
"#B97A57", // Barrier
"#22B14C", // Bush
"#A349A4", // E_Resource
"#99D9EA", // A_Resource
"#FF7F27", // Construction
];
const placeType = {
Home: 0,
Space: 1,
Barrier: 2,
Bush: 3,
E_Resource: 4,
A_Resource: 5,
Construction: 6,
};
function draw() {
ctx.clearRect(0, 0, 500, 500);
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
ctx.fillStyle = color[map[i][j]];
ctx.fillRect(i * 10, j * 10, 10, 10);
}
}
}
canvas.onmousedown = function (e) {
var x = Math.floor(e.offsetX / 10);
var y = Math.floor(e.offsetY / 10);
map[x][y] = currentColor;
draw();
}
document.getElementById("space").onclick = function () {
currentColor = 0;
document.getElementById("current").innerHTML = "当前Space";
}
document.getElementById("barrier").onclick = function () {
currentColor = 1;
document.getElementById("current").innerHTML = "当前Barrier";
}
document.getElementById("bush").onclick = function () {
currentColor = 2;
document.getElementById("current").innerHTML = "当前Bush";
}
document.getElementById("a_resource").onclick = function () {
currentColor = 3;
document.getElementById("current").innerHTML = "当前A_Resource";
}
document.getElementById("e_resource").onclick = function () {
currentColor = 4;
document.getElementById("current").innerHTML = "当前E_Resource";
}
document.getElementById("construction").onclick = function () {
currentColor = 5;
document.getElementById("current").innerHTML = "当前Construction";
}
document.getElementById("home").onclick = function () {
currentColor = 7;
document.getElementById("current").innerHTML = "当前Home";
}
function saveAsTxt() {
var str = "";
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
str += map[j][i];
str += " ";
}
str += "\n";
}
var a = document.createElement("a");
a.style.display = "none";
a.href = "data:text/plain;charset=utf-8," + str;
a.download = "map.txt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function saveAsCs() {
var str = "public static uint[,] Map = new uint[50, 50] {\n";
for (var i = 0; i < 50; i++) {
str += " {";
for (var j = 0; j < 50; j++) {
str += map[j][i];
if (j != 49) {
str += ", ";
}
}
str += "}";
if (i != 49) {
str += ",";
}
str += "\n";
}
str += "};";
var a = document.createElement("a");
a.style.display = "none";
a.href = "data:text/plain;charset=utf-8," + str;
a.download = "map.cs";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function saveAsPng() {
var a = document.createElement("a");
a.style.display = "none";
a.href = canvas.toDataURL("image/png");
a.download = "map.png";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function isEmptyNearby(x, y, radius) {
for (var i = (x - radius >= 0 ? x - radius : 0); i <= (x + radius <= 49 ? x + radius : 49); i++) {
for (var j = (y - radius >= 0 ? y - radius : 0); j <= (y + radius <= 49 ? y + radius : 49); j++) {
if (map[i][j] != 1) {
return false;
}
}
}
return true;
}
function haveSthNearby(x, y, radius, type) {
var ret = 0;
for (var i = (x - radius >= 0 ? x - radius : 0); i <= (x + radius <= 49 ? x + radius : 49); i++) {
for (var j = (y - radius >= 0 ? y - radius : 0); j <= (y + radius <= 49 ? y + radius : 49); j++) {
if (map[i][j] == type) {
ret++;
}
}
}
return ret;
}
function haveSthCross(x, y, radius, type) {
var ret = 0;
for (var i = (x - radius >= 0 ? x - radius : 0); i <= (x + radius <= 49 ? x + radius : 49); i++) {
if (map[i][y] == type) {
ret++;
}
}
for (var j = (y - radius >= 0 ? y - radius : 0); j <= (y + radius <= 49 ? y + radius : 49); j++) {
if (map[x][j] == type) {
ret++;
}
}
return ret;
}
function generateBorderBarrier() {
for (var i = 0; i < 50; i++) {
map[i][0] = placeType.Barrier;
map[i][49] = placeType.Barrier;
map[0][i] = placeType.Barrier;
map[49][i] = placeType.Barrier;
}
}
function generateHome() {
map[3][46] = placeType.Home;
map[46][3] = placeType.Home;
}
function generateEResource(num = 7) {
for (var i = 0; i < num; i++) {
var x = Math.floor(Math.random() * 48) + 1;
var y = Math.floor(Math.random() * 23) + 1;
if (isEmptyNearby(x, y, 2)) {
map[x][y] = placeType.E_Resource;
map[49 - x][49 - y] = placeType.E_Resource;
}
else {
i--;
}
}
}
function generateAResource(num = 4) {
for (var i = 0; i < num; i++) {
var x = Math.floor(Math.random() * 48) + 1;
var y = Math.floor(Math.random() * 23) + 1;
if (isEmptyNearby(x, y, 2)) {
map[x][y] = placeType.A_Resource;
map[49 - x][49 - y] = placeType.A_Resource;
}
else {
i--;
}
}
}
function generateConstruction(num = 5) {
for (var i = 0; i < num; i++) {
var x = Math.floor(Math.random() * 48) + 1;
var y = Math.floor(Math.random() * 23) + 1;
if (isEmptyNearby(x, y, 1)) {
map[x][y] = placeType.Construction;
map[49 - x][49 - y] = placeType.Construction;
}
else {
i--;
}
}
}
function generateBush(prob = 0.015, crossBonus = 23) {
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
if (map[i][j] == 1 && Math.random() < prob * (haveSthCross(i, j, 1, placeType.Shadow) * crossBonus + 1)) {
map[i][j] = placeType.Bush;
map[49 - i][49 - j] = placeType.Bush;
}
}
}
}
function generateBarrier(prob = 0.01, crossBonus = 40) {
for (var i = 2; i < 48; i++) {
for (var j = 2; j < 48; j++) {
if ((map[i][j] == 1 || map[i][j] == 3) &&
!haveSthNearby(i, j, 1, placeType.Barrier) &&
!haveSthNearby(i, j, 1, placeType.Home) &&
Math.random() < prob * (haveSthCross(i, j, 1, placeType.Barrier) * (haveSthCross(i, j, 1, placeType.Barrier) > 1 ? 0 : crossBonus) + 1)) {
map[i][j] = 2;
map[49 - i][49 - j] = 2;
}
}
}
}
function clearCanvas() {
for (var i = 0; i < 50; i++) {
map[i] = new Array(50);
for (var j = 0; j < 50; j++) {
map[i][j] = 1;
}
}
// generateBorderRuin();
// generateHome();
draw();
}
function random() {
for (var i = 0; i < 50; i++) {
map[i] = new Array(50);
for (var j = 0; j < 50; j++) {
map[i][j] = 1;
}
}
var EresourceNum = parseInt(document.getElementById("Eresource-num").value);
var AresourceNum = parseInt(document.getElementById("Aresource-num").value);
var constructionNum = parseInt(document.getElementById("construction-num").value);
var bushProb = parseFloat(document.getElementById("bush-prob").value);
var bushCrossBonus = parseInt(document.getElementById("bush-cross-bonus").value);
var barrierProb = parseFloat(document.getElementById("barrier-prob").value);
var barrierCrossBonus = parseInt(document.getElementById("barrier-cross-bonus").value);
if (isNaN(EresourceNum) || EresourceNum < 1 || EresourceNum > 10) {
EresourceNum = 7;
alert("EResource 数量非法,设置为默认值 7");
document.getElementById("Eresource-num").value = 7;
}
if (isNaN(AresourceNum) || AresourceNum < 1 || AresourceNum > 8) {
AresourceNum = 4;
alert("AResource 数量非法,设置为默认值 4");
document.getElementById("Aresource-num").value = 4;
}
if (isNaN(constructionNum) || constructionNum < 1 || constructionNum > 10) {
constructionNum = 5;
alert("Construction 数量非法,设置为默认值 5");
document.getElementById("construction-num").value = 5;
}
if (isNaN(bushProb) || bushProb < 0 || bushProb > 0.1) {
bushProb = 0.015;
alert("Bush 生成概率非法,设置为默认值 0.015");
document.getElementById("bush-prob").value = 0.015;
}
if (isNaN(bushCrossBonus) || bushCrossBonus < 1 || bushCrossBonus > 50) {
bushCrossBonus = 23;
alert("Bush 蔓延加成非法,设置为默认值 23");
document.getElementById("bush-cross-bonus").value = 23;
}
if (isNaN(barrierProb) || barrierProb < 0 || barrierProb > 0.1) {
barrierProb = 0.01;
alert("Barrier 生成概率非法,设置为默认值 0.01");
document.getElementById("barrier-prob").value = 0.01;
}
if (isNaN(barrierCrossBonus) || barrierCrossBonus < 1 || barrierCrossBonus > 50) {
barrierCrossBonus = 40;
alert("Barrier 蔓延加成非法,设置为默认值 40");
document.getElementById("barrier-cross-bonus").value = 40;
}
generateBorderBarrier();
generateHome();
generateEResource(EresourceNum);
generateAResource(AresourceNum);
generateConstruction(constructionNum);
generateBush(bushProb, bushCrossBonus);
generateBarrier(barrierProb, barrierCrossBonus);
draw();
}
clearCanvas();

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>THUAI8 地图生成器</title>
<link rel="shortcut icon" href="assets/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/map.css">
</head>
<body>
<header class="clearfix">
<div class="logo">
<a href="#">
<img src="assets/img/favicon.ico" alt="THUAI8 7Tools">
</a>
</div>
</header>
<main>
<h1>地图生成器</h1>
<div id="paint">
<canvas id="map" width="500" height="500">
<p>请使用支持 HTML5 的浏览器!</p>
</canvas>
</div>
<div id="color-picker">
<div id="space" style="background-color: #FFFFFF;">
<p style="color: #000000;">Space</p>
</div>
<div id="barrier" style="background-color: #B97A57;">
<p style="color: #FFFFFF;">Barrier</p>
</div>
<div id="bush" style="background-color: #22B14C;">
<p style="color: #FFFFFF;">Bush</p>
</div>
<div id="EResource" style="background-color: #A349A4">
<p style="color: #FFFFFF;">EResource</p>
</div>
<div id="Aresource" style="background-color: #99D9EA;">
<p style="color: #FFFFFF;">AResource</p>
</div>
<div id="construction" style="background-color: #FF7F27;">
<p style="color: #FFFFFF;">Construction</p>
</div>
<div id="home" style="background-color: #ED1C24;">
<p style="color: #FFFFFF;">Home</p>
</div>
<p id="current" style="margin-left: 20px;">当前Space</p>
</div>
<div id="random-settings">
<fieldset>
<legend>随机参数设置</legend>
<p>⚠ 请谨慎修改参数!</p>
<p>EResource 数量:<input type="number" id="Eresource-num" value="7" min="1" max="10"></p>
<p>AResource 数量:<input type="number" id="Aresource-num" value="4" min="1" max="8"></p>
<p>Construction 数量:<input type="number" id="construction-num" value="5" min="1" max="10"></p>
<p>Bush 生成概率:<input type="number" id="bush-prob" value="0.015" min="0" max="0.1" step="0.001"></p>
<p>Bush 蔓延加成:<input type="number" id="bush-cross-bonus" value="23" min="0" max="50"></p>
<p>Barrier 生成概率:<input type="number" id="barrier-prob" value="0.01" min="0" max="0.1" step="0.001"></p>
<p>Barrier 蔓延加成:<input type="number" id="barrier-cross-bonus" value="40" min="0" max="50"></p>
</fieldset>
</div>
<div id="operate">
<button class="outline" onclick="saveAsTxt()">保存为 TXT</button>
<button onclick="saveAsCs()">保存为 C#</button>
<button onclick="saveAsPng()">保存为 PNG</button>
<button onclick="clearCanvas()">清空地图</button>
<button onclick="random()">随机生成</button>
</div>
</main>
</body>
<script src="assets/js/map.js"></script>
</html>

5
map-generator/Python/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.vscode/
*.map
build/
dist/
*__pycache__

View File

@ -0,0 +1,33 @@
import CLR_START
import clr
import sys
clr.AddReference('System')
PREPARATION_IMPORT = [r'../../logic/Preparation/bin/Debug/net8.0/',
r'../../logic/Preparation/bin/Release/net8.0/',
r'../../../logic/Preparation/bin/Debug/net8.0/',
r'../../../logic/Preparation/bin/Release/net8.0/',
r'./',
r'./_internal/']
PREPARATION = 'Preparation'
GAMECLASS_IMPORT = [r'../../logic/GameClass/bin/Debug/net8.0/',
r'../../logic/GameClass/bin/Release/net8.0/',
r'../../../logic/GameClass/bin/Debug/net8.0/',
r'../../../logic/GameClass/bin/Release/net8.0/',
r'./',
r'./_internal/']
GAMECLASS = 'GameClass'
def Find(paths: list[str], target: str) -> None:
try:
sys.path.append(paths[0])
clr.AddReference(target)
except BaseException:
paths.pop(0)
if paths == []:
raise FileNotFoundError(f'未找到{target}')
Find(paths, target)
Find(PREPARATION_IMPORT, PREPARATION)
Find(GAMECLASS_IMPORT, GAMECLASS)

View File

@ -0,0 +1,3 @@
from clr_loader import get_coreclr
from pythonnet import set_runtime
set_runtime(get_coreclr())

View File

@ -0,0 +1,165 @@
from __future__ import annotations
from queue import Queue
from typing import Any, Generator, NoReturn
from easygui import choicebox, msgbox
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.axes import Axes
from matplotlib.patches import Rectangle
from matplotlib.ticker import MultipleLocator
from matplotlib.backend_bases import MouseEvent, KeyEvent
from System import String
from GameClass.MapGenerator import MapStruct
from Preparation.Utility import PlaceType as PT
from Classes.RandomCore import RandomCore
class MapRenderer:
class RenderUnit:
r: int
c: int
tp: str
def __init__(self, _r: int, _c: int, _tp: str) -> None:
self.r = _r
self.c = _c
self.tp = _tp
class CurrentRender:
__cur_gen: Generator[PT, Any, NoReturn]
__cur: PT
def __init__(self, _areas: dict[PT, str]) -> None:
_keys = list(_areas.keys())
self.__cur = _keys[0]
def g():
while True:
for k in _keys:
yield k
self.__cur_gen = g()
def Get(self) -> PT:
return self.__cur
def Switch(self) -> None:
self.__cur = next(self.__cur_gen)
title: str
map: MapStruct
areas: dict[PT, str]
mapf: String
fig: Figure
ax: Axes
rects: list[list[Rectangle]]
queue_render: Queue[RenderUnit]
randomCores: list[RandomCore]
isCursorLift: int # 0: 未提起; 1: 提起未选定; 2: 提起并选定
cursorLift: tuple[int] # 提起坐标
cur: CurrentRender
@property
def Queue_Render(self) -> RenderUnit:
return self.queue_render.get(timeout=0.1)
@Queue_Render.setter
def Queue_Render(self, value: RenderUnit) -> None:
self.queue_render.put(value, timeout=0.1)
def __init__(self, _title, _mapStruct: MapStruct, _areas: dict[PT, str],
_mapf: str, _randoms: list[RandomCore]) -> None:
self.title = _title
self.map = _mapStruct
self.areas = _areas
self.mapf = _mapf
self.randomCores = _randoms
self.fig, self.ax = plt.subplots()
self.rects = [[Rectangle((j, i), 1, 1, facecolor=self.areas[self.map[i, j]])
for j in range(self.map.width)]
for i in range(self.map.height)]
self.queue_render = Queue()
self.isCursorLift = 0
self.cursorLift = None
self.cur = MapRenderer.CurrentRender(_areas)
def MainFrame(self) -> None:
self.fig.set_size_inches(self.map.width, self.map.height)
self.ax.set_xlim(0, self.map.width)
self.ax.set_ylim(self.map.height, 0)
self.ax.xaxis.set_major_locator(MultipleLocator(1))
self.ax.yaxis.set_major_locator(MultipleLocator(1))
self.ax.set_aspect(1)
for i in range(self.map.height):
for j in range(self.map.width):
self.ax.add_patch(self.rects[i][j])
plt.hlines(range(self.map.height + 1), 0, self.map.width)
plt.vlines(range(self.map.width + 1), 0, self.map.height)
self.fig.canvas.mpl_connect('button_press_event', self.on_click)
self.fig.canvas.mpl_connect('key_press_event', self.on_press)
plt.show()
def on_click(self, event: MouseEvent) -> None:
if not event.button:
return
match event.button:
case 1:
r, c = int(event.ydata), int(event.xdata)
match self.isCursorLift:
case 0:
self.map[r, c] = self.cur.Get()
self.Queue_Render = MapRenderer.RenderUnit(r, c, self.areas[self.cur.Get()])
self.Render()
case 1:
self.cursorLift = (r, c)
self.isCursorLift = 2
case 2:
liftr, liftc = self.cursorLift
dir_r, dir_c = (1 if liftr <= r else -1), (1 if liftc <= c else -1)
for i in range(liftr, r + dir_r, dir_r):
for j in range(liftc, c + dir_c, dir_c):
self.map[i, j] = self.cur.Get()
self.Queue_Render = MapRenderer.RenderUnit(i, j, self.areas[self.cur.Get()])
self.Render()
self.isCursorLift = 0
case 3:
self.cur.Switch()
case _:
return
def on_press(self, event: KeyEvent) -> None:
if not event.key:
return
match event.key:
case 'z':
self.isCursorLift = 1
case 'c':
MapStruct.ToFile(self.mapf, self.map)
msgbox(msg='Your map has been saved.', title=self.title)
case 'p':
opt = choicebox(msg='Choose random', title=self.title, choices=[x.Name for x in self.randomCores])
if opt is None:
return
for x in self.randomCores:
if x.Name == opt:
if x.Menu():
x.Random(self.map)
for r in range(self.map.height):
for c in range(self.map.width):
self.Queue_Render = MapRenderer.RenderUnit(r, c, self.areas[self.map[r, c]])
self.Render()
case _:
return
def Render(self) -> None:
while not self.queue_render.empty():
cur = self.Queue_Render
self._render(cur.r, cur.c, cur.tp)
plt.show(block=False)
def _render(self, r: int, c: int, tp: str) -> None:
self.rects[r][c].set_color(tp)
self.ax.draw_artist(self.rects[r][c])

View File

@ -0,0 +1,15 @@
from __future__ import annotations
from abc import abstractmethod, abstractproperty
from GameClass.MapGenerator import MapStruct
class RandomCore:
@abstractproperty
def Name(self) -> str: ...
@abstractmethod
def Menu(self) -> bool: ...
@abstractmethod
def Random(self, mp: MapStruct) -> None: ...

View File

@ -0,0 +1,96 @@
from __future__ import annotations
from typing import Any
from easygui import multenterbox
from perlin_noise import PerlinNoise
from GameClass.MapGenerator import MapStruct
from Preparation.Utility import PlaceType as PT
from Classes.RandomCore import RandomCore
class PerlinRandomCore(RandomCore):
title: str
octaves: float
seed: int | None
@property
def Octaves(self) -> float:
return self.octaves
@Octaves.setter
def Octaves(self, value: float) -> None:
if value > 0:
self.octaves = value
else:
self.octaves = 10
@property
def Seed(self) -> int | None:
return self.seed
@Seed.setter
def Seed(self, value: int | Any) -> None:
if isinstance(value, int) and value > 0:
self.seed = value
else:
self.seed = None
def __init__(self, title: str, octaves: float = 10) -> None:
self.title = title
self.Octaves = octaves
self.Seed = None
@property
def Name(self) -> str:
return 'Perlin'
def Menu(self) -> bool:
try:
(self.Octaves,
self.Seed) = (lambda f1, i2: (float(f1), int(i2) if i2 else i2))(*multenterbox(
msg='Random settings',
title=self.title,
fields=[
'Octaves',
'Seed'
],
values=[
self.Octaves,
self.Seed
]
))
except TypeError:
return False
return True
def Random(self, mp: MapStruct) -> None:
noise = PerlinNoise(self.Octaves, self.Seed)
arr: list[list[float]] = []
arrMax: float = float('-inf')
arrMin: float = float('inf')
for i in range(mp.height):
arr.append([])
for j in range(mp.width):
cur = noise([j / mp.width, i / mp.height])
arr[i].append(cur)
if cur > arrMax:
arrMax = cur
elif cur < arrMin:
arrMin = cur
arr0, arr1, arr2 = arrMin, (2 * arrMin + arrMax) / 3, (arrMin + 2 * arrMax) / 3
for i in range(mp.height):
for j in range(mp.width):
if i == 0 or i == mp.height - 1:
mp[i, j] = PT.Ruin
continue
elif j == 0 or j == mp.width - 1:
mp[i, j] = PT.Ruin
continue
cur = arr[i][j]
if arr0 < cur < arr1:
mp[i, j] = PT.Shadow
elif arr1 < cur < arr2:
mp[i, j] = PT.Null
else:
mp[i, j] = PT.Ruin

View File

@ -0,0 +1,291 @@
from __future__ import annotations
from math import floor
from random import random
from easygui import multenterbox
from GameClass.MapGenerator import MapStruct
from Preparation.Utility import PlaceType as PT
from Classes.RandomCore import RandomCore
class DefaultXuchengRandomSettings:
asteroidWidth = 2
resourceNum = 7
constructionNum = 5
shadowProb = 0.015
shadowCrossBonus = 23
ruinProb = 0.01
ruinCrossBonus = 40
class XuchengRandomCore(RandomCore):
title: str
asteroidWidth: int
resourceNum: int
constructionNum: int
shadowProb: float
shadowCrossBonus: int
ruinProb: float
ruinCrossBonus: int
@property
def AsteroidWidth(self) -> int:
return self.asteroidWidth
@AsteroidWidth.setter
def AsteroidWidth(self, value: int) -> None:
if value < 1 or value > 4:
self.asteroidWidth = DefaultXuchengRandomSettings.asteroidWidth
else:
self.asteroidWidth = value
@property
def ResourceNum(self) -> int:
return self.resourceNum
@ResourceNum.setter
def ResourceNum(self, value: int) -> None:
if value < 1 or value > 10:
self.resourceNum = DefaultXuchengRandomSettings.resourceNum
else:
self.resourceNum = value
@property
def ConstructionNum(self) -> int:
return self.constructionNum
@ConstructionNum.setter
def ConstructionNum(self, value: int) -> None:
if value < 1 or value > 10:
self.constructionNum = DefaultXuchengRandomSettings.constructionNum
else:
self.constructionNum = value
@property
def ShadowProb(self) -> float:
return self.shadowProb
@ShadowProb.setter
def ShadowProb(self, value: float) -> None:
if value < 0 or value > 0.1:
self.shadowProb = DefaultXuchengRandomSettings.shadowProb
else:
self.shadowProb = value
@property
def ShadowCrossBonus(self) -> int:
return self.shadowCrossBonus
@ShadowCrossBonus.setter
def ShadowCrossBonus(self, value: int) -> None:
if value < 1 or value > 50:
self.shadowCrossBonus = DefaultXuchengRandomSettings.shadowCrossBonus
else:
self.shadowCrossBonus = value
@property
def RuinProb(self) -> float:
return self.ruinProb
@RuinProb.setter
def RuinProb(self, value: float) -> None:
if value < 0 or value > 0.1:
self.ruinProb = DefaultXuchengRandomSettings.ruinProb
else:
self.ruinProb = value
@property
def RuinCrossBonus(self) -> int:
return self.ruinCrossBonus
@RuinCrossBonus.setter
def RuinCrossBonus(self, value: int) -> None:
if value < 1 or value > 50:
self.ruinCrossBonus = DefaultXuchengRandomSettings.ruinCrossBonus
else:
self.ruinCrossBonus = value
def __init__(self,
title,
asteroidWidth: int = DefaultXuchengRandomSettings.asteroidWidth,
resourceNum: int = DefaultXuchengRandomSettings.resourceNum,
constructionNum: int = DefaultXuchengRandomSettings.constructionNum,
shadowProb: float = DefaultXuchengRandomSettings.shadowProb,
shadowCrossBonus: int = DefaultXuchengRandomSettings.shadowCrossBonus,
ruinProb: float = DefaultXuchengRandomSettings.ruinProb,
ruinCrossBonus: int = DefaultXuchengRandomSettings.ruinCrossBonus) -> None:
self.title = title
self.AsteroidWidth = asteroidWidth
self.ResourceNum = resourceNum
self.ConstructionNum = constructionNum
self.ShadowProb = shadowProb
self.ShadowCrossBonus = shadowCrossBonus
self.RuinProb = ruinProb
self.RuinCrossBonus = ruinCrossBonus
@property
def Name(self) -> str:
return 'Xucheng'
def Menu(self) -> bool:
try:
(self.AsteroidWidth,
self.ResourceNum,
self.ConstructionNum,
self.ShadowProb,
self.ShadowCrossBonus,
self.RuinProb,
self.RuinCrossBonus) = (lambda i1, i2, i3, f4, i5, f6, i7:
(int(i1), int(i2), int(i3), float(f4), int(i5), float(f6), int(i7)))(*multenterbox(
msg='Random settings',
title=self.title,
fields=[
'Asteroid 宽度',
'Resource 数量',
'Construction 数量',
'Shadow 生成概率',
'Shadow 蔓延加成',
'Ruin 生成概率',
'Ruin 蔓延加成'
],
values=[self.AsteroidWidth,
self.ResourceNum,
self.ConstructionNum,
self.ShadowProb,
self.ShadowCrossBonus,
self.RuinProb,
self.RuinCrossBonus]
))
except TypeError:
return False
return True
def Random(self, mp: MapStruct) -> None:
mp.Clear()
XuchengRandomCore.generateBorderRuin(mp)
XuchengRandomCore.generateHome(mp)
XuchengRandomCore.generateAsteroid(mp, self.asteroidWidth)
XuchengRandomCore.generateResource(mp, self.resourceNum)
XuchengRandomCore.generateConstruction(mp, self.constructionNum)
XuchengRandomCore.generateShadow(mp, self.shadowProb, self.shadowCrossBonus)
XuchengRandomCore.generateRuin(mp, self.ruinProb, self.ruinCrossBonus)
XuchengRandomCore.generateWormhole(mp)
@staticmethod
def isEmptyNearby(mp: MapStruct, x: int, y: int, r: int) -> bool:
for i in range(x - r if x - r >= 0 else 0, (x + r if x + r <= 49 else 49) + 1):
for j in range(y - r if y - r >= 0 else 0, (y - r if y + r <= 9 else 49) + 1):
if mp[i, j] != PT.Null:
return False
return True
@staticmethod
def haveSthNearby(mp: MapStruct, x: int, y: int, r: int, tp: PT) -> int:
ret = 0
for i in range(x - r if x - r >= 0 else 0, (x + r if x + r <= 49 else 49) + 1):
for j in range(y - r if y - r >= 0 else 0, (y - r if y + r <= 9 else 49) + 1):
if mp[i, j] == tp:
ret += 1
return ret
@staticmethod
def haveSthCross(mp: MapStruct, x: int, y: int, r: int, tp: PT) -> int:
ret = 0
for i in range(x - r if x - r >= 0 else 0, (x + r if x + r <= 49 else 49) + 1):
if mp[i, y] == tp:
ret += 1
for j in range(y - r if y - r >= 0 else 0, (y + r if y + r <= 49 else 49) + 1):
if mp[x, j] == tp:
ret += 1
return ret
@staticmethod
def generateBorderRuin(mp: MapStruct) -> None:
for i in range(50):
mp[i, 0] = PT.Ruin
mp[i, 49] = PT.Ruin
mp[0, i] = PT.Ruin
mp[49, i] = PT.Ruin
@staticmethod
def generateHome(mp: MapStruct) -> None:
mp[3, 46] = PT.Home
mp[46, 3] = PT.Home
@staticmethod
def generateAsteroid(mp: MapStruct, width: int = DefaultXuchengRandomSettings.asteroidWidth) -> None:
for i in range(1, 49):
for j in range(24, 24 - width, -1):
mp[i, j] = PT.Asteroid
mp[49 - i, 49 - j] = PT.Asteroid
for i in range(1, 23):
if random() < 0.5 and i != 9 and i != 10 and i != 11 and i != 12:
mp[i, 24 - width] = PT.Asteroid
mp[i, 24 + width] = PT.Null
mp[49 - i, 25 + width] = PT.Asteroid
mp[49 - i, 25 - width] = PT.Null
@staticmethod
def generateResource(mp: MapStruct, num: int = DefaultXuchengRandomSettings.resourceNum) -> None:
i = 0
while i < num:
x = floor(random() * 48) + 1
y = floor(random() * 23) + 1
if XuchengRandomCore.isEmptyNearby(mp, x, y, 2):
mp[x, y] = PT.Resource
mp[49 - x, 49 - y] = PT.Resource
else:
i -= 1
i += 1
@staticmethod
def generateConstruction(mp: MapStruct, num: int = DefaultXuchengRandomSettings.constructionNum) -> None:
i = 0
while i < num:
x = floor(random() * 48) + 1
y = floor(random() * 23) + 1
if XuchengRandomCore.isEmptyNearby(mp, x, y, 1):
mp[x, y] = PT.Construction
mp[49 - x, 49 - y] = PT.Construction
else:
i -= 1
i += 1
@staticmethod
def generateShadow(mp: MapStruct, prob: float = DefaultXuchengRandomSettings.shadowProb,
crossBonus: int = DefaultXuchengRandomSettings.shadowCrossBonus) -> None:
for i in range(50):
for j in range(50):
if (mp[i, j] == PT.Null and
random() < prob * (XuchengRandomCore.haveSthCross(mp, i, j, 1, PT.Shadow) * crossBonus + 1)):
mp[i, j] = PT.Shadow
mp[49 - i, 49 - j] = PT.Shadow
@staticmethod
def generateRuin(mp: MapStruct, prob: float = DefaultXuchengRandomSettings.ruinProb,
crossBonus: int = DefaultXuchengRandomSettings.ruinCrossBonus) -> None:
for i in range(2, 48):
for j in range(2, 48):
if ((mp[i, j] == PT.Null or mp[i, j] == PT.Shadow) and
not XuchengRandomCore.haveSthNearby(mp, i, j, 1, PT.Asteroid) and
not XuchengRandomCore.haveSthNearby(mp, i, j, 1, PT.Home) and
random() < prob
* (XuchengRandomCore.haveSthCross(mp, i, j, 1, PT.Ruin)
* (0 if XuchengRandomCore.haveSthCross(mp, i, j, 1, PT.Ruin) > 1
else crossBonus) + 1)):
mp[i, j] = PT.Ruin
mp[49 - i, 49 - j] = PT.Ruin
@staticmethod
def generateWormhole(mp: MapStruct) -> None:
for i in range(1, 49):
if mp[10, i] == PT.Asteroid:
mp[10, i] = PT.Wormhole
mp[39, 49 - i] = PT.Wormhole
if mp[11, i] == PT.Asteroid:
mp[11, i] = PT.Wormhole
mp[38, 49 - i] = PT.Wormhole
if mp[24, i] == PT.Asteroid:
mp[24, i] = PT.Wormhole
mp[25, 49 - i] = PT.Wormhole

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Stub for C#
from __future__ import annotations
from typing import overload
from System import Array, UInt32, String
from Preparation.Utility import PlaceType as PT
class MapStruct:
height: UInt32
width: UInt32
map: Array[PT]
@overload
def __init__(self, height: UInt32, width: UInt32) -> None: ...
@overload
def __init__(self, height: UInt32, width: UInt32, map: Array[PT]) -> None: ...
@overload
def __init__(self, height: UInt32, width: UInt32, map: Array[UInt32]) -> None: ...
@staticmethod
def FromFile(filename: String) -> MapStruct: ...
@staticmethod
def ToFile(filename: String, src: MapStruct) -> None: ...
def Clear(self) -> None: ...
def __getitem__(self, i: UInt32, j: UInt32) -> PT: ...
def __setitem__(self, i: UInt32, j: UInt32, value: PT) -> None: ...

View File

@ -0,0 +1,46 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[('../../logic/Preparation/bin/Release/net8.0/Preparation.dll', '.'),
('../../logic/GameClass/bin/Release/net8.0/GameClass.dll', '.')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='MapGenerator',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['favicon.ico'],
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='MapGenerator',
)

View File

@ -0,0 +1,15 @@
[[source]]
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
verify_ssl = true
name = "pip_conf_index_global"
[packages]
easygui = "*"
matplotlib = "*"
perlin-noise = "*"
pythonnet = "*"
[dev-packages]
[requires]
python_version = "3.10"

622
map-generator/Python/Pipfile.lock generated Normal file
View File

@ -0,0 +1,622 @@
{
"_meta": {
"hash": {
"sha256": "c836cb6b81d74e4c5af61fc9cdb731390cac9a489341a2d6b9141d1d4fc4728b"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.10"
},
"sources": [
{
"name": "pip_conf_index_global",
"url": "https://pypi.tuna.tsinghua.edu.cn/simple",
"verify_ssl": true
}
]
},
"default": {
"cffi": {
"hashes": [
"sha256:0928df15fc8e63099fa82cf2deb0f67ad740639ae23089fd26c6d919d08f9844",
"sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc",
"sha256:0e074a6dd01c0576710259bef3f008b261ac6fa3252e19370b5d2c466b621f5d",
"sha256:0e4ffd75af0ff2f2ec6ba18e249c6969653d6f06bd7f4a405236c217963dd887",
"sha256:0ed256dd741501dc11c8f536972f54a5a68df018a7959ce97219a8b308b4b881",
"sha256:0ff5cf5f823c507f1449121fe29f31989b8aa2782807e5d0f28a7f8ee2678294",
"sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a",
"sha256:14749dd9f2906b1f3381927d548fa1136f8361253543b20d08c8b3ddf0e88585",
"sha256:1aa49e13394da30a35c772c1042fc21d342c41e8137d1e153d2c467f44201dae",
"sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417",
"sha256:20df2ea98e721ecc58df359bc596092bb43fccb8e692deaf35674d34f868bf37",
"sha256:2361e1a133c9999b4a3eaf03c7ce7f91c69347e617289675e7b3b07fa4392e23",
"sha256:23a0d34f7f10935d798e4a3700f7ebff6bfdfa8476b7e55a56dbf53b8d41da55",
"sha256:24357100aceaf76318b9a826237fe7dc20652daf1d15d6f0db162fea3d665e7b",
"sha256:278037e3e27deab1d9a8d2780371d368e0265c2031ada0554ed81dd2376dfced",
"sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab",
"sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520",
"sha256:2dd553b3ff4817b2dab4c6a9c257dd35f720976815c899d5040297604acd98e3",
"sha256:2de1371afe36f892916da71e83ab00f8766ccd81df40794bacb6eda7a355cd6f",
"sha256:2efec335c2b27a5bdd32f1da827a7d3cec38ad2601f5eddbb79c7eb8230b442a",
"sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36",
"sha256:31fd177716140a5229c30e6e316d49a9eedb13b10eb7726cb892cd4aa5bff84f",
"sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743",
"sha256:32e9fef44dd5c0e5f09dbd75ddec0961be5d919c4fb497a3d2e482e12eea8417",
"sha256:3389f61db8594bb5e996340188aa81a6dc817b29ee80fd1c6471c63d2721e269",
"sha256:33dea583fa13e02af6495232838410fdce42045fe6d7bafc83eec4adb7bf76a8",
"sha256:3591f33b9b0f8a31a612d9f1cefe595973d991233eecce07948d1e74114cc0c1",
"sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8",
"sha256:3743ea0ed69c8cc40cb6f29482d8b7de20235c04d1373406fe2df01b961b9064",
"sha256:384f5328f37ab2c681d925b1d1cc7d79cd355546a9d7e6d901ed4e2083b4b548",
"sha256:3a3a5d6575f5193c305b026ab4b6cfd9faf6b23ad823cf527553cf8e98055ffe",
"sha256:3b478e5cb81139cfb2726f7b7d5b3662e4cbbe8e13da5443db23545dcc4c0d05",
"sha256:3ce9be5bceb74b9f55dbe326e933faf674f891223852eef52a2a70dcb07c523f",
"sha256:3f3637d26849648ca75ffccdf8e24c0bef77cb038f1fc178afa8a12afa5dffb8",
"sha256:3fdc35da8835fd60a7a26153919f90f58ae82822f3d2992cc93170fb76760384",
"sha256:43884e9fe6a612c25b420ed0e62d219c309cfd2cd80132829c577e7d8e50afb8",
"sha256:43d6aa2bde10de152ab417ef701e8db32f1092df368cec4d432fa58b589955ef",
"sha256:462fdd5add40619ae29f4f939c33e69753ed1036dd7094bec4e3afe9f02359c8",
"sha256:4640e7d91fd348f8877a64563ef3fc8f0e600c69860a142d299b21f13babcc98",
"sha256:4766877e1aca2f1d6d93416873ec268f034c2a03ffb11b6daf5db5dcad03709b",
"sha256:478d6a99f78478d7e3b8db69bbd1a648fff31a313e1ae76f87d260dde91e5cd7",
"sha256:4ce6c1a2e8925db47492378860b25a051a73a5fe217261af7dee3d523f2922ba",
"sha256:50e493ab94d425edfc713a2cac4d56a6a6c11638bebf411e86013be69e624e69",
"sha256:52f75ee1a8dd96ee4a96820df4fb079adb29736c0d351235d591bc94aa933689",
"sha256:563f16837d86a5e3fb4625f0baf936898d5b3da03a1192e16592b226c73cfd4a",
"sha256:577320b3b767f3597dff98fef933986b1b8cf077a4bafa43e92cc9bd389788eb",
"sha256:57ddcf5dd192126e62e9ed427ac6c61f36300482938e3f46f5cda1105b09dc90",
"sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed",
"sha256:5926d3caa290106a602b2f70d8d242c885802427134c2f7a700c53da6b1a4d53",
"sha256:5a3bf751ceba6c9165e21b2ef3408830449abfaf3db5f791b6e9fde92a04dea0",
"sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684",
"sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56",
"sha256:5f2240660bb64c4b2d5104688561540d90da8e19edbc7ae904d46ae685d0ab57",
"sha256:62fb88370101ac6c983114fb014679158e359b3d6b6c539b17618acfb6d5539e",
"sha256:6406e237787e3a36951b2f4ab805524e605ab508477be444ebbce1b87845dedd",
"sha256:65cd3cfc9262a82ed9f096cd41dfd9b2b293a009f52bbfe499fb9f246edc4404",
"sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324",
"sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d",
"sha256:678716ca1c06138450b0454ada2245d326765720c2634d370d249cd0d566b992",
"sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235",
"sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e",
"sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088",
"sha256:6b5ae6273853754efa05be54b97b9fb830679f349f425076d7993b0cac7ba4f3",
"sha256:6d8184615e735aff76b2c5546472b5faed19abb48a53b7770eaee3bd4e01b86e",
"sha256:70d591221b7adb3b80e0a4dca42a22b8385635525820a777d43f00b6156d0690",
"sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000",
"sha256:75523efb2bda34d882f8b8c0e41daed350e8cd11307b1154a79e857cb5fa0814",
"sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7",
"sha256:76bac0ad1168d71e9f117b5bbcd4efc5d7328f9a0054fd058b0b0eba88bcf7d6",
"sha256:78faf51033e48213a2ef2d8cb2987e650058a60ebe8085bcc3afe484c61950fb",
"sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e",
"sha256:7d7d38f40905b668e2c6bb0dcfc1428de67438df93e05005b22a1a753ab21dc2",
"sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673",
"sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c",
"sha256:85431bf5729028182587f9bba21c82a567d82e4cddd8e74e1952dcba5fd9f337",
"sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe",
"sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2",
"sha256:8ed16244d7801e7ac6fd004356588433b5f7f421acd5369c3a9b3b3119f2f12d",
"sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098",
"sha256:911868b5d339d866040851c55c7f95d01e21bcb3764641a264f88dc9f314dbef",
"sha256:919b68f21fa046afc4c6093a0deb02c7741f6e189a8af3a3379b0db12093b18f",
"sha256:96df1e57477e0e1387c7207ee3f493b2f0c67d50e6f52f3302ea75bf4f2c1861",
"sha256:9861337fbeab2e421e068cf1068bf080dd742a02b1c65f2c613b9479438e626d",
"sha256:98cf866039b1b41712a71cb448001a0ed1bb38f1d1db583aea1b78cae05ec057",
"sha256:98e2d9d7754509a1e5366c378eb095e9f8a3b67ba6dc822092153fe3c7529d45",
"sha256:993088af255a591351fb1f7e9a2fb459f790ba46b29c3481cb5c0cf54005dc25",
"sha256:9b598e2b6f0f24180482458d644db6dc44e98bcdc9c00914d69b2749994efe0c",
"sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8",
"sha256:9d3943738d1d4bfd66cf42a7e0fef83bd1d6021c018363b47977e00200caf7e6",
"sha256:9e610ae4b2cfd1b262427b9afd5953102137a6b167c025c0a701f9c822b20535",
"sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a",
"sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0",
"sha256:a0a6f27c022be6bbd19b9b7b6c2e584e6aa68586c30cec6ef3505a21e127124f",
"sha256:a10bcc26a395411129016be78b82071f1431ab5763e5c3f25ee18e91bf3f88af",
"sha256:a27f0237f7481a0e48bcce9de390c07d6518a9958c330817ef505f4fe0def1ad",
"sha256:a55f625e389f89e4d06b188f39deb51d3dea7ac96092e1b8cd4182eb761b537e",
"sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b",
"sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896",
"sha256:a9497765f8cfb1451958216298cf1e96fe43b40e38aee4d9c34ca44ee122295b",
"sha256:aac5299ed6c4b56447b6b0c4f99e587e4998c05bb4d633002adcd36be68085e1",
"sha256:ab70e66da8e53534c5b34012b4ba9f9805a7e379902eeb583aaa6e15e18db550",
"sha256:aba626bd9b59d2661c4dd8fbe7c81fdc6436021ce3ce0635de7c442b91e6877d",
"sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e",
"sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9",
"sha256:ae42699a559623cb730602ade2cc0a1f053f8b0ed958c8c1c7ddd0a02254876a",
"sha256:af5b0f7e331ea55232f15e972abd74d2817964accdd6fd3e5c2b8ac354fa993f",
"sha256:b02e33fb7aac7149828a7912dc44751821a74d568984af9946e270ae5708e2fd",
"sha256:b10e6f2060e4c0c5a4f420dac78d229f01dc5ea2ee9951b95e5d252b69859e57",
"sha256:b1d80ef126d3b8e1e1ead94fb8ac44eb1f4ed36990dba3e09fa4b7921426879d",
"sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2",
"sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b",
"sha256:b74012db526dcaa6488d4e2b6cf65ae41a50fcd132a3fef39e99a01f1c71684a",
"sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6",
"sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404",
"sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f",
"sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0",
"sha256:bd06b3b5ffde55cc618538f8db442c51218b703da8fdba0c20969d5f8477fdca",
"sha256:bd43ef97cabb2bab95c09956c28a87a0e05274b9258996521696912bf93da36f",
"sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4",
"sha256:c22b4a9f9f3a172baace6ff2a0dfd7eafa691d1b714aa89978b66d467c6030d7",
"sha256:c3d7f3337c8e2e6287651c0116adb7a1fd1e43d0ffeebd49a38a86425b92c665",
"sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc",
"sha256:c761446abcc82b52f1be155f5266887216a6e20174d3afd7025c95fdd57d527b",
"sha256:c9d9cbc569ef960e841d7777c0996864bf307a73497248bedaf542c3c1f6ce34",
"sha256:cb7df7ab7d13d2d5d6df4d4adb6d9013139be8bfab17f9bedcdf9aa0ae10c6c1",
"sha256:cbf204995c237988376b60021bfe3c6eb161f8be68b2a7546bb4fda9cb1a38e1",
"sha256:d184e5d68d4ddfae311dcc63614ba53d0d7a592339366f6ec5f522ed43f50f20",
"sha256:d411fad9c6b3c9ef6b7fec75f6e57389f63f021e295b76934884dd3682c92a58",
"sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936",
"sha256:d9b57c9037208b92529f14b5b18c5416ebaa84446e7f5172d4f45074b4b4bb61",
"sha256:dacd0caf16ed0c23a1ac105fd129f410ff7a2aa8240c479be2c25adf2095996e",
"sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba",
"sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872",
"sha256:dd8cb96761204564b82c32ae07e2f83121799fe3db2cd6c39135983a2705c028",
"sha256:dfd80e1feaffe8eff95ae26ffa83bdf7ad5f1e24f00b24310c27a95eca51a4b6",
"sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb",
"sha256:e21f83989e4f54eece0347451c4694c6116de04c93b80a422ead425bfbdd18c3",
"sha256:e24ab5f0ea81b1285b93b637ad44d8da1e4928540b2bc554b4533a267bddc575",
"sha256:e2d583f83b5f6e4c284ccf53f220cead00241231e51e573d6324e05ad1e6c879",
"sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614",
"sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1",
"sha256:e654ae5341ba422841ebcb992c0041f9379f18cf0e7f7c70e00e36ff78777420",
"sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d",
"sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969",
"sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b",
"sha256:e9b75f0097a15dc2a6c00571be3d50381b0e921b0942a398fcde7cdf70277f1f",
"sha256:ed737449b6d66429dfe6c513d015d61a3bcd845aa993a630ef5f5a89fadd4070",
"sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4",
"sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627",
"sha256:efadf60f8cc01419369db94d63ca17de3f5a214c77ef260c18a1e64f2e0da02c",
"sha256:f2c9e3946ee71debff0bc2260aa4994e782d4a7e95923c101a20d16eabb075f7",
"sha256:f4a99491edeafd0c41f5fe39ba0540b889a17f86f740d8160ee535fa0303c9ec",
"sha256:f6fc6549854a10cac989e6783436f58f0611aadca07d8179fd377c248c66a22b",
"sha256:f89b29d72d6bcfd2945bf965b1de1b5fc4bfdfe7438e12a6ad4794fb4e5f014c",
"sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956",
"sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"
],
"markers": "python_version >= '3.8'",
"version": "==1.16.0"
},
"clr-loader": {
"hashes": [
"sha256:019348ae6b6a83c7a406d14537c277cecf7a3a53b263ec342c81ded5845a67ee",
"sha256:79bbfee4bf6ac2f4836d89af2c39e0c32dce5d0c062596185aef380f317507a6"
],
"markers": "python_version >= '3.7'",
"version": "==0.2.6"
},
"contourpy": {
"hashes": [
"sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8",
"sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956",
"sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5",
"sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063",
"sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286",
"sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a",
"sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686",
"sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9",
"sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f",
"sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4",
"sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e",
"sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0",
"sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e",
"sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488",
"sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399",
"sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431",
"sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779",
"sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9",
"sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab",
"sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0",
"sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd",
"sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e",
"sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc",
"sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6",
"sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316",
"sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808",
"sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0",
"sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f",
"sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843",
"sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9",
"sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95",
"sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9",
"sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de",
"sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4",
"sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4",
"sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa",
"sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8",
"sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776",
"sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41",
"sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108",
"sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e",
"sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8",
"sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727",
"sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"
],
"markers": "python_version >= '3.9'",
"version": "==1.2.0"
},
"cycler": {
"hashes": [
"sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30",
"sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"
],
"markers": "python_version >= '3.8'",
"version": "==0.12.1"
},
"easygui": {
"hashes": [
"sha256:33498710c68b5376b459cd3fc48d1d1f33822139eb3ed01defbc0528326da3ba",
"sha256:d653ff79ee1f42f63b5a090f2f98ce02335d86ad8963b3ce2661805cafe99a04"
],
"index": "pip_conf_index_global",
"version": "==0.98.3"
},
"fonttools": {
"hashes": [
"sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133",
"sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828",
"sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc",
"sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2",
"sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559",
"sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42",
"sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf",
"sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c",
"sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036",
"sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942",
"sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86",
"sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22",
"sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5",
"sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75",
"sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a",
"sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd",
"sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814",
"sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b",
"sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a",
"sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844",
"sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034",
"sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc",
"sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4",
"sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18",
"sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836",
"sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9",
"sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880",
"sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb",
"sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff",
"sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7",
"sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e",
"sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29",
"sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532",
"sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be",
"sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075",
"sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717",
"sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb",
"sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321",
"sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e",
"sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e",
"sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6",
"sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"
],
"markers": "python_version >= '3.8'",
"version": "==4.49.0"
},
"kiwisolver": {
"hashes": [
"sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf",
"sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e",
"sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af",
"sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f",
"sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046",
"sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3",
"sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5",
"sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71",
"sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee",
"sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3",
"sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9",
"sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b",
"sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985",
"sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea",
"sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16",
"sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89",
"sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c",
"sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9",
"sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712",
"sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342",
"sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a",
"sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958",
"sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d",
"sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a",
"sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130",
"sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff",
"sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898",
"sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b",
"sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f",
"sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265",
"sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93",
"sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929",
"sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635",
"sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709",
"sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b",
"sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb",
"sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a",
"sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920",
"sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e",
"sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544",
"sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45",
"sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390",
"sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77",
"sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355",
"sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff",
"sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4",
"sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7",
"sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20",
"sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c",
"sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162",
"sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228",
"sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437",
"sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc",
"sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a",
"sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901",
"sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4",
"sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770",
"sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525",
"sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad",
"sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a",
"sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29",
"sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90",
"sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250",
"sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d",
"sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3",
"sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54",
"sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f",
"sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1",
"sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da",
"sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238",
"sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa",
"sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523",
"sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0",
"sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205",
"sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3",
"sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4",
"sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac",
"sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9",
"sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb",
"sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced",
"sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd",
"sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0",
"sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da",
"sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18",
"sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9",
"sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276",
"sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333",
"sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b",
"sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db",
"sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126",
"sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9",
"sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09",
"sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0",
"sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec",
"sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7",
"sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff",
"sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9",
"sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192",
"sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8",
"sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d",
"sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6",
"sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797",
"sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892",
"sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"
],
"markers": "python_version >= '3.7'",
"version": "==1.4.5"
},
"matplotlib": {
"hashes": [
"sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7",
"sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4",
"sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea",
"sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1",
"sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407",
"sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba",
"sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900",
"sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa",
"sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26",
"sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357",
"sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01",
"sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161",
"sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65",
"sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb",
"sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7",
"sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635",
"sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f",
"sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5",
"sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0",
"sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4",
"sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c",
"sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f",
"sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e",
"sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7",
"sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc",
"sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39",
"sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec",
"sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"
],
"index": "pip_conf_index_global",
"markers": "python_version >= '3.9'",
"version": "==3.8.3"
},
"numpy": {
"hashes": [
"sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b",
"sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818",
"sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20",
"sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0",
"sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010",
"sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a",
"sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea",
"sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c",
"sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71",
"sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110",
"sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be",
"sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a",
"sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a",
"sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5",
"sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed",
"sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd",
"sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c",
"sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e",
"sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0",
"sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c",
"sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a",
"sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b",
"sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0",
"sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6",
"sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2",
"sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a",
"sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30",
"sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218",
"sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5",
"sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07",
"sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2",
"sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4",
"sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764",
"sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef",
"sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3",
"sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"
],
"markers": "python_version >= '3.9'",
"version": "==1.26.4"
},
"packaging": {
"hashes": [
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
],
"markers": "python_version >= '3.7'",
"version": "==23.2"
},
"perlin-noise": {
"hashes": [
"sha256:01ec42d9f2bc338ae52edbb069b375fb83fec51784e17479366ced1f7063957c",
"sha256:7c65b6671ce06d93cf467e2b59041878e3d5dc40208a8c089de581d3f9d47701"
],
"index": "pip_conf_index_global",
"version": "==1.12"
},
"pillow": {
"hashes": [
"sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8",
"sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39",
"sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac",
"sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869",
"sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e",
"sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04",
"sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9",
"sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e",
"sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe",
"sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef",
"sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56",
"sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa",
"sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f",
"sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f",
"sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e",
"sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a",
"sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2",
"sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2",
"sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5",
"sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a",
"sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2",
"sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213",
"sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563",
"sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591",
"sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c",
"sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2",
"sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb",
"sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757",
"sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0",
"sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452",
"sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad",
"sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01",
"sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f",
"sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5",
"sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61",
"sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e",
"sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b",
"sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068",
"sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9",
"sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588",
"sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483",
"sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f",
"sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67",
"sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7",
"sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311",
"sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6",
"sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72",
"sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6",
"sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129",
"sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13",
"sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67",
"sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c",
"sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516",
"sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e",
"sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e",
"sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364",
"sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023",
"sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1",
"sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04",
"sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d",
"sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a",
"sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7",
"sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb",
"sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4",
"sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e",
"sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1",
"sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48",
"sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"
],
"markers": "python_version >= '3.8'",
"version": "==10.2.0"
},
"pycparser": {
"hashes": [
"sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
"sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
],
"version": "==2.21"
},
"pyparsing": {
"hashes": [
"sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb",
"sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"
],
"markers": "python_full_version >= '3.6.8'",
"version": "==3.1.1"
},
"python-dateutil": {
"hashes": [
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.9.0.post0"
},
"pythonnet": {
"hashes": [
"sha256:62486f860c7955b7dcf470e085e4d2b599512224ca24193f716e857b496c530f",
"sha256:8d4b2e97158a023875f8647458a58f38817f4fe39af60abdd6b0d8adf1d77e75"
],
"index": "pip_conf_index_global",
"markers": "python_version < '3.13' and python_version >= '3.7'",
"version": "==3.0.3"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
}
},
"develop": {}
}

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Stub for C#
from __future__ import annotations
from System import UInt32
class PlaceType(UInt32):
Null: PlaceType
Ruin: PlaceType
Shadow: PlaceType
Asteroid: PlaceType
Resource: PlaceType
Construction: PlaceType
Wormhole: PlaceType
Home: PlaceType

View File

@ -0,0 +1,88 @@
# MapGenerator开发指南
- [MapGenerator开发指南](#mapgenerator开发指南)
- [虚拟环境](#虚拟环境)
- [代码说明](#代码说明)
- [构建项目](#构建项目)
- [其他](#其他)
## 虚拟环境
本项目使用 `pipenv`[^1] 管理虚拟环境.
`Pipfile` 是关于虚拟环境的信息, 包括 `pip` 的信息、项目使用的第三方库和项目的 Python 版本.
`Pipfile.lock` 类似于传统的 `requirements.txt`, 用于确保依赖版本的适配. 使用如下指令可以按照 `Pipfile.lock` 安装依赖:
```shell
pipenv install # 从Pipfile安装
pipenv install --dev # 安装为仅开发
pipenv sync # 从Pipfile.lock安装
```
向环境中加入依赖, 使用:
```shell
pipenv install package # 安装依赖
pipenv install --dev dev_package # 仅开发安装
```
删除依赖, 需要使用:
```shell
pipenv uninstall your_package
```
在虚拟环境中运行脚本, 使用如下指令:
```shell
pipenv run python3 main.py
```
## 代码说明
`./CLR_START.py`、`./CLR_IMPORT.py` 为使用 PythonNet 加载 CLR 的脚本. 在 `./CLR_IMPORT.py` 中有一串 `GameClass``Preparation` 路径, 是所需的 C# DLL 的位置. 如果出现找不到 DLL 的问题, 请检查 C# 是否编译以及编译产物的路径.
`./GameClass/MapGenerator.pyi`、`./Preparation/Utility.pyi` 和 `./System.pyi` 为 C# DLL 的调用存根, 用于语法高亮; 不需要语法高亮请无视或删除.
> 本项目使用了 C# 的 `GameClass.MapGenerator.MapStruct``Preparation.Utility.PlaceType`, 以及 C# 的基础类型 `UInt32`、`string` 和 `Array`.
> PythonNet 可以自动将数字和字符串类型在 Python 和 Dotnet 之间转换.
`./SETTINGS.py` 为设置脚本, 分别为程序窗口标题、地图文件后缀名和地图区域类型所对应的颜色.
`./Classes/MapRenderer.py` 为程序主体, 负责提供 UI 界面和地图渲染及编辑. 其中存在 `on_click()`(鼠标事件侦测) 和 `on_press()`(键盘事件侦测), 可按需修改.
`./Classes/RandomCore.py``RandomCore` 虚基类的所在.
`./Classes/RandomCores/``RandomCore` 的实现.
> 注意: `RandomCore` 的实现具有强的项目依赖性, 请根据项目实际情况重写.
`./main.py` 为启动脚本. 其中需要留意的是 `RandomCore` 的注册——将其改为重写后的实现.
## 构建项目
在代码根据项目实际修改完成后, 先编译依赖 C# DLL.
C# DLL 编译完成后, 再次检查 DLL 的路径, 包括 `./CLR_IMPORT.py` 的路径和 `./MapGenerator.spec``datas` 参数的路径.
检查完成后, 运行下列命令即可:
```shell
# 首次编译
pipenv run pyinstaller ./MapGenerator.spec
# 如果项目编译过一次了, 用这个跳过文件夹清除询问
pipenv run pyinstaller ./MapGenerator.spec -y
```
项目编译在 `./dist/`下.
## 其他
`./pyproject.toml` 目前用于规定 autopep8 代码格式化参数. 想要格式化代码, 只需:
```shell
autopep8 .
```
[^1]: https://pipenv.pypa.io/en/latest/cli.html

View File

@ -0,0 +1,12 @@
from Preparation.Utility import PlaceType as PT
title = 'THUAI7-MapGenerator'
file_suffix = '.thuai7.map'
areas = {PT.Null: '#FFFFFF',
PT.Ruin: '#B97A57',
PT.Shadow: '#22B14C',
PT.Asteroid: '#99D9EA',
PT.Resource: '#A349A4',
PT.Construction: '#FF7F27',
PT.Wormhole: '#880015',
PT.Home: '#ED1C24'}

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Stub for C#
from __future__ import annotations
class UInt32:
def __init__(self, _: int) -> None: ...
class String:
def __init__(self, _: str) -> None: ...
class Array[T]:
@staticmethod
def CreateInstance(T: type, h: int, w: int) -> Array[T]: ...

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,45 @@
from __future__ import annotations
import os
import os.path
import sys
from easygui import multenterbox
import CLR_IMPORT # NOQA: E402
import SETTINGS
from GameClass.MapGenerator import MapStruct
from Classes.MapRenderer import MapRenderer
from Classes.RandomCores.PerlinRandomCore import PerlinRandomCore
from Classes.RandomCores.XuchengRandomCore import XuchengRandomCore
# 命令行接口
if (argc := len(sys.argv)) != 1:
match sys.argv[1]:
# 生成器最小化
case "--min":
randomCore = XuchengRandomCore(SETTINGS.title)
mapStruct = MapStruct(50, 50)
randomCore.Random(mapStruct)
if argc >= 3:
MapStruct.ToFile(sys.argv[2], mapStruct)
else:
MapStruct.ToFile(f"demo{SETTINGS.file_suffix}", mapStruct)
exit(0)
# 获取路径
path: str = multenterbox(msg='', title=SETTINGS.title, fields=[f'Path(*{SETTINGS.file_suffix})'])[0]
if path[-len(SETTINGS.file_suffix):] != SETTINGS.file_suffix:
path += SETTINGS.file_suffix
# 地图加载
if not os.path.exists(path):
height, width = [int(x)
for x in multenterbox(msg='Create new map', title=SETTINGS.title, fields=['Height', 'Width'])]
mapStruct = MapStruct(height, width)
MapStruct.ToFile(path, mapStruct)
else:
mapStruct = MapStruct.FromFile(path)
# 随机核加载
randomCores = [XuchengRandomCore(SETTINGS.title), PerlinRandomCore(SETTINGS.title)]
# 地图渲染
mapRenderer = MapRenderer(SETTINGS.title, mapStruct, SETTINGS.areas, path, randomCores)
mapRenderer.MainFrame()

View File

@ -0,0 +1,5 @@
[tool.autopep8]
max_line_length = 120
aggressive = true
in-place = true
recursive = true