139 lines
4.5 KiB
GDScript
139 lines
4.5 KiB
GDScript
@tool
|
|
extends GridMap
|
|
|
|
# Godot ne supporte pas les types nested, c'est triste mais on fait un tool button pour nous aider
|
|
#@export var adjacency : Array[Array]
|
|
@export var adjacency : Dictionary[Globals.Blocks, AdjacencyRessource]
|
|
@export_tool_button("Step") var step_action = step
|
|
|
|
var dict_grid_map : Dictionary[Vector3i, Array] = {}
|
|
|
|
|
|
func get_cell_neighbor(cell_coords : Vector3i) -> Dictionary[Vector3i, Globals.Blocks]:
|
|
var neighbor : Dictionary[Vector3i, Globals.Blocks]
|
|
var delta : Vector3i
|
|
for dx in [-1, 0, 1]:
|
|
for dy in [-1, 0, 1]:
|
|
for dz in [-1, 0, 1]:
|
|
delta = Vector3i(dx, dy, dz)
|
|
if delta == Vector3i(0, 0, 0): continue
|
|
var cell_item = get_cell_item(delta)
|
|
neighbor[delta] = cell_item
|
|
|
|
return neighbor
|
|
|
|
func get_proba():
|
|
var used_cells := get_used_cells()
|
|
print("used_cells")
|
|
print(used_cells)
|
|
dict_grid_map = {}
|
|
#var adjacent_cells : Dictionary[Vector3i, bool] = {} # Cells sur la bordure
|
|
var used_cells_hah_set : Dictionary[Vector3i, bool] = {} # For fast look up
|
|
for cell in used_cells:
|
|
used_cells_hah_set.set(cell, true)
|
|
|
|
for cell_coords in used_cells:
|
|
var neighbors := get_cell_neighbor(cell_coords)
|
|
var current_cell := get_cell_item(cell_coords)
|
|
var adj_at_cell_coords := adjacency[current_cell].get_adjacency_dict()
|
|
#print("adj_at_cell_coords")
|
|
#print(adj_at_cell_coords)
|
|
|
|
for diff_n in neighbors:
|
|
var neighbor_pos = cell_coords + diff_n
|
|
if used_cells_hah_set.get(neighbor_pos): continue
|
|
|
|
if not neighbor_pos in dict_grid_map:
|
|
dict_grid_map.set(neighbor_pos, [])
|
|
dict_grid_map[neighbor_pos].resize(Globals.Blocks.size())
|
|
dict_grid_map[neighbor_pos].fill(1.0)
|
|
|
|
var proba_neighbor = dict_grid_map[neighbor_pos]
|
|
#print(adj_at_cell_coords[diff_n])
|
|
for block in range(dict_grid_map[neighbor_pos].size()):
|
|
if block in adj_at_cell_coords[diff_n]:
|
|
dict_grid_map[neighbor_pos][block] *= adj_at_cell_coords[diff_n][block]
|
|
else:
|
|
dict_grid_map[neighbor_pos][block] *= 0.0
|
|
|
|
|
|
#for block in range(proba_neighbor.size()):
|
|
#var proba_adj = adj_at_cell_coords[diff_n][current_cell] if\
|
|
#current_cell in adj_at_cell_coords[diff_n] else 0.0
|
|
#dict_grid_map[neighbor_pos][block] *= proba_adj
|
|
|
|
# Normalisation des probas
|
|
for cell_cooords in dict_grid_map:
|
|
var probas_array = dict_grid_map[cell_cooords]
|
|
var sum = probas_array.reduce(func(a, b): return a+b)
|
|
for block in range(probas_array.size()):
|
|
if sum < 0.001:
|
|
dict_grid_map[cell_cooords][block] = 1.0 / Globals.Blocks.size()
|
|
else:
|
|
dict_grid_map[cell_cooords][block] /= sum
|
|
|
|
print(dict_grid_map)
|
|
print("----\n---\n---\n---")
|
|
|
|
# Oui on utilise Shanon comme des sigma, les autres betas sur internet disent "entropy = nb de possibilites", mais on est sigma ici
|
|
func calculate_entropy(cell_coords : Vector3i):
|
|
var proba_array := dict_grid_map[cell_coords]
|
|
print(proba_array)
|
|
var entropy = 0.0
|
|
for prob in proba_array:
|
|
entropy += -(prob+0.001) * log(prob+0.001) # I'm afraid of log(0) guys
|
|
return entropy
|
|
|
|
func weighted_random_choice_index(weights: Array[float]) -> int:
|
|
if weights.is_empty():
|
|
printerr("weighted_random_choice_index: Input weights array cannot be empty.")
|
|
return -1
|
|
|
|
var total_weight: float = 0.0
|
|
for w in weights:
|
|
if w < 0.0:
|
|
printerr("weighted_random_choice_index: Weights cannot be negative.")
|
|
return -1
|
|
total_weight += w
|
|
|
|
if total_weight <= 0.0:
|
|
return randi() % weights.size()
|
|
|
|
var rnd: float = randf() * total_weight
|
|
for i in range(weights.size()):
|
|
var w = weights[i]
|
|
rnd -= w
|
|
if rnd <= 0.0:
|
|
return i
|
|
|
|
# Fallback (due to potential float inaccuracies)
|
|
return weights.size() - 1
|
|
|
|
func step():
|
|
get_proba()
|
|
print(dict_grid_map)
|
|
var lowest_entropy = 100.0
|
|
var best_cell_coords : Vector3i
|
|
for cell_coords in dict_grid_map.keys():
|
|
var entropy = calculate_entropy(cell_coords)
|
|
print("cell_coords {} entropy {}".format([cell_coords, entropy], "{}"))
|
|
if entropy < lowest_entropy:
|
|
lowest_entropy = entropy
|
|
best_cell_coords = cell_coords
|
|
|
|
var arr_float : Array[float] = Array(dict_grid_map[best_cell_coords], TYPE_FLOAT, "", null)
|
|
var best_cell = weighted_random_choice_index(arr_float)
|
|
|
|
|
|
if not best_cell in Globals.ShouldRotate:
|
|
set_cell_item(best_cell_coords, best_cell)
|
|
else:
|
|
# Rotate 90 degrees around the Y-axis
|
|
var rotation_axis = Vector3.UP
|
|
var rotation_angle_rad = deg_to_rad(90)
|
|
var desired_basis = Basis.IDENTITY.rotated(rotation_axis, rotation_angle_rad)
|
|
var orientation_index = get_orthogonal_index_from_basis(desired_basis)
|
|
|
|
set_cell_item(best_cell_coords, best_cell, orientation_index)
|
|
|
|
|