233 lines
7.3 KiB
Python
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
|