Hashi/hashi_generator.py
2020-12-16 20:47:09 +01:00

233 lines
7.3 KiB
Python

import random
class Hashi:
def __init__(self, size):
if size < 2:
size = 2
print("Size cant be 1 or lower.")
self.size = size
self.node_limit_lower = size # lower limit
self.node_upper_limit = int(size ** 1.4) + 1 # upper limit
self.node_count = 0
self.low_lim = 0
self.high_lim = size
self.map = [[Node([x, y]) for y in range(size)] for x in range(size)]
def generate_map(self):
# down, up, right, left
first = [random.randint(0, self.size-1), random.randint(0, self.size-1)]
self.node_count += 1
node = self.get_node(first)
self.write_node(node)
nodes_to_do = self.get_new_nodes(node)
while len(nodes_to_do) != 0:
for n in nodes_to_do:
node = self.get_node(n)
self.write_node(node)
nodes_to_do = nodes_to_do + self.get_new_nodes(node)
nodes_to_do.remove(n)
def get_node(self, cords):
ways = [0, 0, 0, 0] # down, up, right, left
possibilities = 0
if self.node_count >= self.node_upper_limit:
node = {"ways": [0, 0, 0, 0],
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
if cords[1] - 1 > -1 and self.map[cords[0]][cords[1] - 1].locked is False:
ways[0] += 1
possibilities += 1
if cords[1] + 1 < self.size and self.map[cords[0]][cords[1] + 1].locked is False:
ways[1] += 1
possibilities += 1
if cords[0] + 1 < self.size and self.map[cords[0] + 1][cords[1]].locked is False:
ways[2] += 1
possibilities += 1
if cords[0] - 1 > -1 and self.map[cords[0] - 1][cords[1]].locked is False:
ways[3] += 1
possibilities += 1
if possibilities:
attempts = [x+1 if random.randint(0, 1) == 0 else x for x in ways]
# making the puzzle forcefully bigger
if self.node_count < self.node_limit_lower:
while 2 not in attempts:
attempts = [x + 1 if random.randint(0, 1) == 0 else x for x in ways]
# getting the starting distances
distances = [1 if x > 1 else 0 for x in attempts]
# getting possible distance up to 6
if attempts[0] > 1:
for i in range(2, self.size):
if cords[1] - i > -1 and self.map[cords[0]][cords[1] - i].locked is False:
distances[0] += 1
else:
break
if attempts[1] > 1:
for i in range(2, self.size):
if cords[1]+i < self.size and self.map[cords[0]][cords[1]+i].locked is False:
distances[1] += 1
else:
break
if attempts[2] > 1:
for i in range(2, self.size):
if cords[0] + i < self.size and self.map[cords[0]+i][cords[1]].locked is False:
distances[2] += 1
else:
break
if attempts[3] > 1:
for i in range(2, self.size):
if cords[0] - i > -1 and self.map[cords[0] - i][cords[1]].locked is False:
distances[3] += 1
else:
break
final_decision = [random.randint(1, x)if x != 0 else 0 for x in distances]
node = {"ways": final_decision,
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
else:
node = {"ways": [0, 0, 0, 0],
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
def write_node(self, node):
pos = node["pos"]
i = 0
sum_of_bridges = 0
for item in node["ways"]:
if item != 0:
sum_of_bridges += node["num_of_bridges"][i]
# adding the bridges to new nodes
if i == 0:
self.map[pos[0]][pos[1] - item].bridge_num += node["num_of_bridges"][i]
elif i == 1:
self.map[pos[0]][pos[1] + item].bridge_num += node["num_of_bridges"][i]
elif i == 2:
self.map[pos[0] + item][pos[1]].bridge_num += node["num_of_bridges"][i]
elif i == 3:
self.map[pos[0] - item][pos[1]].bridge_num += node["num_of_bridges"][i]
i += 1
self.map[pos[0]][pos[1]].locked = True
self.map[pos[0]][pos[1]].bridge_num += sum_of_bridges
def get_new_nodes(self, node):
pos = node["pos"]
# down, up, right, left
nodes_to_send = []
for nodeX in range(1, node["ways"][0]+1):
self.map[pos[0]][pos[1] - nodeX].locked = True
if nodeX == node["ways"][0]:
nodes_to_send.append(self.map[pos[0]][pos[1] - nodeX].pos)
for nodeX in range(1, node["ways"][1]+1):
self.map[pos[0]][pos[1] + nodeX].locked = True
if nodeX == node["ways"][1]:
nodes_to_send.append(self.map[pos[0]][pos[1] + nodeX].pos)
for nodeX in range(1, node["ways"][2]+1):
self.map[pos[0] + nodeX][pos[1]].locked = True
if nodeX == node["ways"][2]:
nodes_to_send.append(self.map[pos[0] + nodeX][pos[1]].pos)
for nodeX in range(1, node["ways"][3]+1):
self.map[pos[0] - nodeX][pos[1]].locked = True
if nodeX == node["ways"][3]:
nodes_to_send.append(self.map[pos[0] - nodeX][pos[1]].pos)
self.node_count += len(nodes_to_send)
return nodes_to_send
def save(self, path):
final_string = ""
for y in range(self.size):
for x in range(self.size):
final_string += str(self.map[x][y].bridge_num) + " "
final_string += "\n"
with open(path, "w") as f:
f.write(final_string)
f.close()
def print(self, bridges=False):
final_string = "_" * ((self.size * 2) + 3) + "\n"
for y in range(self.size):
final_string += "| "
for x in range(self.size):
if bridges is False:
final_string += str(self.map[x][y].bridge_num) + " "
else:
final_string += f" |* {self.map[x][y].bridge_num} *,{str(self.map[x][y].locked)[0]}| "
final_string += "|\n"
final_string += "¯" * ((self.size * 2) + 3)
print(final_string)
def __len__(self):
return self.node_count
def __str__(self):
final_string = "_" * ((self.size*2)+3) + "\n"
for y in range(self.size):
final_string += "| "
for x in range(self.size):
final_string += str(self.map[x][y].bridge_num) + " "
final_string += "|\n"
final_string += "¯" * ((self.size*2)+3)
return final_string
def __add__(self, other):
return self.node_count + other.node_count
class Node:
def __init__(self, pos, bridge_num=0):
self.pos = pos
self.bridge_num = bridge_num
self.locked = False