code:
# Godot-specific ignores
.import/
export.cfg
export_presets.cfg

# Imported translations (automatically generated from CSV files)
*.translation

# Mono-specific ignores
.mono/
data_*/

#rust

/rust/target

repo_name: QuiteUnusualDev/golados

path: .gitignore

license: unknown


code:
extends Container

export(int) var columns = 10
export(int) var rows = 10
var sep= 4

func _notification(what):
	match (what):
		NOTIFICATION_SORT_CHILDREN:
			var child = get_child(0)
			var min_dim = min(rect_size.x-((rows-1)*sep),rect_size.y-((columns-1)*sep))
#				print("size:"+str(floor(min_dim - ((rows- 1)*2) / rows)))
			var x_size = ((rows-1)*sep)+floor(min_dim / rows)*rows
			var y_size = ((columns-1)*sep)+floor(min_dim / columns)*columns
			var c_size = Vector2(x_size, y_size)
			child.rect_position = (rect_size - c_size)/2
			child.rect_size =c_size

			var child2: Node2D = get_child(1)
			child2.position = (rect_size - c_size)/2

func _notification_old(what):
	match (what):
		NOTIFICATION_SORT_CHILDREN:
			for i in get_child_count():
				var child = get_child(i)
				var min_dim = min(rect_size.x-((rows-1)*sep),rect_size.y-((columns-1)*sep))
#				print("size:"+str(floor(min_dim - ((rows- 1)*2) / rows)))
				var x_size = ((rows-1)*sep)+floor(min_dim / rows)*rows
				var y_size = ((columns-1)*sep)+floor(min_dim / columns)*columns
				var c_size = Vector2(x_size, y_size)
				child.rect_position = (rect_size - c_size)/2
				child.rect_size =c_size


code:
extends Node2D

signal finished
signal movette_done(movette)

# Declare member variables here. Examples:
# var a: int = 2
# var b: String = "text"
var pos1:=Vector2(0,0)
var pos2:=Vector2(0,0)
var pos3:=Vector2(0,0)

var speed : = 1.0
var target_step_size : = speed / 60.0
var last_step_size : float

var player:=Vector2(0,0)
var clock := INF
var avg :=Vector2(0,0)

var midway1 := 0.5
var midway2 := 0.5
var midway3 := 0.5

var animating = 0

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.

func spawn(square:Control):
	pos1 = square.rect_position+(square.rect_size/2)

func murderize(killer1:Control, killer2:Control, vic:Control):
	pos1 = killer1.rect_position+(killer1.rect_size/2)
	pos2 = killer2.rect_position+(killer2.rect_size/2)
	pos3 = vic.rect_position+(vic.rect_size/2)

	avg = (pos1 + pos2 + pos3)/3

	midway1 = calc_midway(player, avg, pos1)
	midway2 = calc_midway(pos1, avg, pos2)
	midway3 = calc_midway(pos2, avg, pos3)

	clock =0.0
	#yield()
	animating = 1
	self.visible = true

func reparam(p, midway):
	var ret = 0
	if p < 0.5:
		ret = (midway*(p*2))
	else:
		ret = (midway + (( p- 0.5) * ((1 - midway) / (1 - 0.5))))
	if (ret <0) or(ret > 1):
#		print("ani 54: beeping")
		return(0.5)
	else:
		return(ret)

func calc_midway(a : Vector2, b : Vector2, c : Vector2):
	var ab = (b-a).length()
	var bc = (c-b).length()
	return(ab/(ab+bc))
	#we wan t 0.5 to be ab /(ab+bc)

func _process(delta: float) -> void:
	if animating > 0:
		clock +=delta/1.5

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta: float) -> void:
#	pass
func _draw():
	draw_circle(pos1, 3, Color.red)
	draw_circle(pos2, 3, Color.green)
	draw_circle(pos3, 3, Color.blue)

	# animate murder
	if animating > 0:
		if animating <= 4:
			if clock < 1:
				if animating == 1:
					animating = 2
				draw_circle(_quadratic_bezier(player, avg, pos1, reparam(clock, midway1)), 5, Color.black)
			elif clock < 2:
				if animating == 2:
					animating = 3
					emit_signal("movette_done",1)
				draw_circle(_quadratic_bezier(pos1, avg, pos2, reparam(clock - 1, midway2)),5, Color.black)
			elif clock < 3:
				if animating == 3:
					animating = 4
					emit_signal("movette_done",2)
				draw_circle(_quadratic_bezier(pos2, avg, pos3, reparam(clock - 2, midway3)),5, Color.black)
			else:
				animating = 0
				emit_signal("movette_done",3)
				emit_signal("finished")
				visible = false
		elif animating <= 7:
			if clock < 1:
				if animating == 4:
					animating = 5
					emit_signal("movette_done",4)
				draw_circle(player.linear_interpolate(pos1, clock), 5, Color.black)
			elif clock < 2:
				if animating == 5:
					animating = 6
					emit_signal("movette_done",5)
				draw_circle(pos1.linear_interpolate(player, clock - 1), 5, Color.black)
			else:
				animating = 0
				emit_signal("movette_done",6)
				emit_signal("finished")
				visible = false

func _quadratic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, t: float):
	var q0 = p0.linear_interpolate(p1, t)
	var q1 = p1.linear_interpolate(p2, t)
	return(q0.linear_interpolate(q1, t))


code:
extends Node
# keep list of players spawn and  mad_kills happy_kills
#
#  turns_used = max(0, (kappy_kills - (spawns * 2))) + happy_spawns + mad_kills
# is_valid_move_set = (available_turn >= turns_used) and ((kappy_kills - (spawns * 2)) >= 0)
signal animate_board

export(PackedScene) var cell_scene

# Declare member variables here. Examples:
# var a: int = 2
# var b: String = "text"
export(int) var cols = 10
export(int) var rows = 10

var game : = GameOfLifeAndDeath.new()
var changed_cells : = {}

enum {KILL, BIRTH}
var sacrifices : = []
var births : = []
onready var GUI_board :Container = $Board/Background/Pieces
onready var board_cont : Container = $Board
onready var finish_btn = $VBoxContainer/Finish
onready var hand_animate = $Board/HandAnimation

onready var GUI_cur_happy = $VBoxContainer/HBoxContainer/Happy/Hbar/Current
onready var GUI_happy_diff = $VBoxContainer/HBoxContainer/Happy/Hbar/Diff
onready var GUI_cur_mad = $VBoxContainer/HBoxContainer/Mad/Hbar/Current
onready var GUI_mad_diff = $VBoxContainer/HBoxContainer/Mad/Hbar/Diff
onready var GUI_hints = $VBoxContainer/Hints
onready var GUI_moves_left = $VBoxContainer/MovesLeft

var current_happiness
var current_madness
var moves_left : int

var player1= "human"

var swaps_to_make = []

var AI_thinking =false
var AI_thoughts setget AI_thoughs_setter

var animating_board : = false

var clock : = 0

var murder_regex : = RegEx.new()
var spawn_regex : = RegEx.new()

func AI_thoughs_setter(x):
	assert(x)
	AI_thoughts =x

func _process(_delta: float) -> void:
	hand_animate.update()
	if AI_thinking:
		var temp = AI_thoughts.resume()
		if temp:
			self.AI_thoughts = temp

func set_players_pos():
	hand_animate.player=$VBoxContainer/HBoxContainer/Mad/Hbar/TextureRect.rect_global_position

# recaiver of the 'movette_done' signal from $MuderAnimation when it's time to swap the pieces
func animate_piece_swap(movette):
	var swap = swaps_to_make.pop_front()
	var pos = swap.pos
	logy("69", "pos =" + str(pos))
	var piece = swap.piece
	var cell = GUI_board.get_child((cols * pos.y) + pos.x)
	logy("rel 70", "animating swap" + str(movette) + "=" + str(pos) + " to" + str(piece))
	cell.finalize(piece)

func receive_ai_move(move):
	AI_thinking = false
	play_move(move, -1)

func play_move(move, player):
	var murder_match = murder_regex.search(move)
	if murder_match:
		logy("rel 86", "muder match")
		var killer = [int(murder_match.get_string(1)), int(murder_match.get_string(2))]
		var	accomplice = [int(murder_match.get_string(3)), int(murder_match.get_string(4))]
		var victum = [int(murder_match.get_string(5)), int(murder_match.get_string(6))]
		swaps_to_make = [
			{
				"pos" : {'x' : killer[0], 'y' : killer[1] },
				"piece": 0
			},
			{
				"pos": {'x' : accomplice[0], 'y' : accomplice[1]},
				"piece": 0
			},
			{
				"pos": {'x' : victum[0], 'y' : victum[1]},
				"piece": 0
			}
		]
		hand_animate.murderize(pos2cell2(killer), pos2cell2(accomplice), pos2cell2(victum))
		yield(hand_animate, "finished")
	else:
		var spawn_match = spawn_regex.search(move)
		if spawn_match:
			var spawn = [int(spawn_match.get_string(1)), int(spawn_match.get_string(2))]
			swaps_to_make = [
				{
					"pos" : {'x' : spawn[0], 'y' : spawn[1] },
					"piece": 4 * player
				}
			]
			hand_animate.spawn(pos2cell2(spawn))
			yield(hand_animate, "finished")
		else:
			logy('rel 119', "*BEEP* didn't get a valid move from the AI")
	for x in swaps_to_make:
		game.set_cell(x.pos.x, x.pos.y, x.piece)
	finish_btn.disabled = false

	update_display()
	update_preview()
	for child in GUI_board.get_children():
		child.enable()

func receive_thought(board):
	pass
#	update_display(board, rows, cols)
#	update_preview_GUI(board)

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
# warning-ignore:return_value_discarded
	murder_regex.compile("M(\\d+):(\\d+)\\|(\\d+):(\\d+)\\|(\\d+):(\\d+)")
# warning-ignore:return_value_discarded
	spawn_regex.compile("S(\\d+):(\\d+)")

	game._ready()

	set_players_pos()

	setup()
	pass # Replace with function body.

func update_cur_happy(x):
	current_happiness = x
	GUI_cur_happy.text = str(x)

func update_happy_diff(x):
	if x < 0:
		GUI_happy_diff.add_color_override("font_color", Color.red)
		GUI_happy_diff.text = str(x)
	else:
		GUI_happy_diff.add_color_override("font_color", Color.white)
		GUI_happy_diff.text = "+" + str(x)

func update_mad_diff(x):
	if x < 0:
		GUI_mad_diff.add_color_override("font_color", Color.red)
		GUI_mad_diff.text = str(x)
	else:
		GUI_mad_diff.add_color_override("font_color", Color.white)
		GUI_mad_diff.text = "+" + str(x)

func update_cur_mad(x):
	current_madness = x
	GUI_cur_mad.text = str(x)

#####
# setup fuctions
static func delete_children(node):
	for n in node.get_children():
		node.remove_child(n)
		n.queue_free()

func setup():
	moves_left = 1
	delete_children(GUI_board)
	GUI_board.columns = cols
	board_cont.columns = cols
	board_cont.rows = rows
	game.new_game(rows, cols)
	game.connect("AI_move", self, "receive_ai_move")
	for c in range(cols):
		for r in rows:
			var pos = GameOfLifeAndDeath.Position.new(r,c)
			var life = GameOfLifeAndDeath.rand_life()
			game.set_cell(r, c, life)
			var new_cell = cell_scene.instance()
			GUI_board.add_child(new_cell)
			new_cell.btn.connect("pressed",self, "player_moved",[pos])
			if OK != self.connect("animate_board",new_cell, "animate",[pos]):
				logy("rel 150", "failed to connect 'animate_board' to 'animate in cell'")

	var score = game.tick_game()
	update_display()
	update_cur_happy(score[0])
	update_cur_mad(score[1])

	update_preview()

#connected to the Finish button
func next_player():
	for child in GUI_board.get_children():
		child.disable()
	animating_board = true
#	GUI_board.get_child(0).connect("finished_piece_transition", self, "_on_board_animation_stage_1_finished")
	run_board()
	if current_happiness == "0" and current_madness == "0":
		logy("rel 167", "tie")
		GUI_cur_happy.text="Tie!"
		GUI_cur_mad.text = "Tie!"
	elif current_happiness == "0":
		GUI_cur_happy.text="Winner!"
	elif current_madness == "0":
		GUI_cur_mad.text="Winner!"
	yield(GUI_board.get_child(0), "finished_piece_transition")
	print("rel 189: preview done")
	update_preview()
	yield(GUI_board.get_child(0), "finished_preview_transition")
	print("rel 192: borad tran finished")
	animating_board =false

	AI_thinking =true
	finish_btn.disabled = true

	game.get_ai_move()
#	self.AI_thoughts = AI.get_move(current_board, current_happiness, current_madness)

func run_board():
	var score = game.tick_game()
	update_display()
	update_cur_happy(score[0])
	update_cur_mad(score[1])
	game.reset_preview()

#####################################################
#handin using interactions
## convers the posing to the gui repersentation on it.
func pos2cell(pos : GameOfLifeAndDeath.Position):
	return(GUI_board.get_child((cols * pos.y) + pos.x))

func pos2cell2(pos : Array):
	logy("212", " pos = "+str(pos))
	return(GUI_board.get_child((cols * int(pos[1])) + int(pos[0])))

## changes a cell in the GUI and player's board
func player_set_piece(pos: GameOfLifeAndDeath.Position, piece:int, debug=false):
	if debug:
		print("rel 200:seting" + str(pos) + " to " + str(piece))
	game.set_preview_cell(pos.x, pos.y, piece)
	var cell = pos2cell(pos)
	cell.set_piece(piece)

func update_birthing():
	var regex = RegEx.new()
	regex.compile("(.*):(.*)")
	var x = sacrifices.size()
	for pos in births:
		var result = regex.search(pos)
		pos = GameOfLifeAndDeath.Position.new(int(result.get_string(1)), int(result.get_string(2)))
		logy("rel 222", pos)
		var cell = pos2cell(pos)
		if x >= 2:
			logy("rel 229", "birthing set")
			cell.set_piece(GameOfLifeAndDeath.H4)
		elif x == 1:
			cell.half_full()
		else:
			cell.birthing()
		x -=2
	if x >0 :
		GUI_hints.text = str(0 - x) + " sacrifices needed"

func player_moved(pos):
	var pid = pos.id()
	if pid in changed_cells:
		logy("rel 242", "changes set peice")
		player_set_piece(pos, changed_cells[pid])
		changed_cells.erase(pid)
		if pid in sacrifices:
			sacrifices.erase(pid)
		elif pos in births:
			births.erase(pos)
		if sacrifices.size() < births.size() * 2:
			finish_btn.disabled = true
			update_birthing()
		else:
			if changed_cells.size() > moves_left:
				 finish_btn.disabled = true
			else:
				finish_btn.disabled = false
	# pos not in changed_cells
	else:
		var cur_piece = game.get_cur_piece(pos.x, pos.y)
		#are we spawning?
		logy('debug', "piece =" + str(cur_piece))
		if cur_piece == 0:
			logy("rel 254", "start spawn")
			#player_set_piece(pos, GameOfLifeAndDeath.H4)
			births.append(pos.id())
			update_birthing()
			changed_cells[pid] = cur_piece
		#are we sacrificing.
		else:
			if cur_piece > 0:
				logy("debug", "player selectd one of his own")
				sacrifices.append(pid)
			player_set_piece(pos, GameOfLifeAndDeath.DEAD)
			changed_cells[pid] = cur_piece
		if changed_cells.size() > moves_left:
			 finish_btn.disabled = true
		else:
			finish_btn.disabled = false

	GUI_moves_left.text = str(moves_left - changed_cells.size()) + " moves left."
	update_preview()

func update_pos(pos : GameOfLifeAndDeath.Position, piece):
	var cell = GUI_board.get_child((cols * pos.y) + pos.x)
	cell.set_piece(piece)

func update_preview():
	var preview = game.get_preview()
	update_happy_diff(preview[1] - int(current_happiness))
	update_mad_diff(preview[2] - int(current_madness))

	update_preview_GUI(preview[0])

func update_display():
	var board = game.get_board()
	for y in range(cols):
		for x in range(rows):
			var pos = GameOfLifeAndDeath.Position.new(x, y)
			if board.cell_alive_ka(pos):
				update_pos(pos, board.get_cell(pos))
			else:
				update_pos(pos, GameOfLifeAndDeath.DEAD)

func preview_pos(pos : GameOfLifeAndDeath.Position, piece: int):
	var cell = GUI_board.get_child((cols * pos.y) + pos.x)
	cell.set_preview(piece)

func update_preview_GUI(board: GameOfLifeAndDeath.Board):
	for y in range(cols):
		for x in range(rows):
			var pos = GameOfLifeAndDeath.Position.new(x, y)
			if board.cell_alive_ka(pos):
				preview_pos(pos, board.get_cell(pos))
			else:
				preview_pos(pos, GameOfLifeAndDeath.DEAD)

# Called eve  ry frame. 'delta' is the elapsed time since the previous frame.
#func _process    delta: float) -> void:
#	pass

func logy(lvl, msg):
	var temp = get_stack()
	if temp.size() > 1:
		msg = temp[1].source + " " + "%3d" % temp[1].line + ":" + str(msg)
	else:
		msg = 'Relationship.gd  ??' + str(msg)
	print(msg)


code:
[gd_scene load_steps=8 format=2]

[ext_resource path="res://Relationship.gd" type="Script" id=1]
[ext_resource path="res://square.tscn" type="PackedScene" id=2]
[ext_resource path="res://assets/HappyFace.2.png" type="Texture" id=3]
[ext_resource path="res://assets/MadFace.2.png" type="Texture" id=4]
[ext_resource path="res://Board.gd" type="Script" id=5]
[ext_resource path="res://Node2D.gd" type="Script" id=7]

[sub_resource type="StyleBoxFlat" id=1]
bg_color = Color( 0, 0, 0, 1 )

[node name="GoLaD" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
cell_scene = ExtResource( 2 )

[node name="Board" type="Container" parent="."]
margin_right = 490.0
margin_bottom = 480.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 5 )

[node name="Background" type="PanelContainer" parent="Board"]
margin_right = 100.0
margin_bottom = 100.0
rect_min_size = Vector2( 10, 10 )
size_flags_horizontal = 3
size_flags_vertical = 3
custom_styles/panel = SubResource( 1 )

[node name="Pieces" type="GridContainer" parent="Board/Background"]
margin_right = 100.0
margin_bottom = 100.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/vseparation = 4
custom_constants/hseparation = 4

[node name="HandAnimation" type="Node2D" parent="Board"]
script = ExtResource( 7 )

[node name="Tween" type="Tween" parent="Board/HandAnimation"]

[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 494.0
margin_right = 640.0
margin_bottom = 480.0
rect_min_size = Vector2( 0, 100 )

[node name="Finish" type="Button" parent="VBoxContainer"]
margin_right = 146.0
margin_bottom = 20.0
text = "Step"

[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 24.0
margin_right = 146.0
margin_bottom = 63.0

[node name="Happy" type="PanelContainer" parent="VBoxContainer/HBoxContainer"]
margin_right = 71.0
margin_bottom = 39.0

[node name="Hbar" type="HBoxContainer" parent="VBoxContainer/HBoxContainer/Happy"]
margin_left = 7.0
margin_top = 7.0
margin_right = 64.0
margin_bottom = 32.0

[node name="TextureRect" type="TextureRect" parent="VBoxContainer/HBoxContainer/Happy/Hbar"]
margin_right = 25.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
texture = ExtResource( 3 )
expand = true

[node name="Current" type="Label" parent="VBoxContainer/HBoxContainer/Happy/Hbar"]
margin_left = 29.0
margin_top = 5.0
margin_right = 37.0
margin_bottom = 19.0
text = "0"

[node name="Diff" type="Label" parent="VBoxContainer/HBoxContainer/Happy/Hbar"]
margin_left = 41.0
margin_top = 5.0
margin_right = 57.0
margin_bottom = 19.0
text = "+0"

[node name="Mad" type="PanelContainer" parent="VBoxContainer/HBoxContainer"]
margin_left = 75.0
margin_right = 146.0
margin_bottom = 39.0

[node name="Hbar" type="HBoxContainer" parent="VBoxContainer/HBoxContainer/Mad"]
margin_left = 7.0
margin_top = 7.0
margin_right = 64.0
margin_bottom = 32.0

[node name="TextureRect" type="TextureRect" parent="VBoxContainer/HBoxContainer/Mad/Hbar"]
margin_right = 25.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
texture = ExtResource( 4 )
expand = true

[node name="Current" type="Label" parent="VBoxContainer/HBoxContainer/Mad/Hbar"]
margin_left = 29.0
margin_top = 5.0
margin_right = 37.0
margin_bottom = 19.0
text = "0"

[node name="Diff" type="Label" parent="VBoxContainer/HBoxContainer/Mad/Hbar"]
margin_left = 41.0
margin_top = 5.0
margin_right = 57.0
margin_bottom = 19.0
text = "+0"

[node name="Hints" type="Label" parent="VBoxContainer"]
margin_top = 67.0
margin_right = 146.0
margin_bottom = 81.0

[node name="MovesLeft" type="Label" parent="VBoxContainer"]
margin_top = 85.0
margin_right = 146.0
margin_bottom = 99.0

[connection signal="movette_done" from="Board/HandAnimation" to="." method="animate_piece_swap"]
[connection signal="pressed" from="VBoxContainer/Finish" to="." method="next_player"]
[connection signal="item_rect_changed" from="VBoxContainer/HBoxContainer/Mad/Hbar/TextureRect" to="." method="set_players_pos"]


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/HappyFace.2.png-751eb2efb41b80a65c0fa92b7d24ed88.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/HappyFace.2.png"
dest_files=[ "res://.import/HappyFace.2.png-751eb2efb41b80a65c0fa92b7d24ed88.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/HappyFace.png-86fb92e8cf5bb50d722464adf12fee07.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/HappyFace.png"
dest_files=[ "res://.import/HappyFace.png-86fb92e8cf5bb50d722464adf12fee07.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/MadFace.2.png-786203564dbf288889e2730585a25832.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/MadFace.2.png"
dest_files=[ "res://.import/MadFace.2.png-786203564dbf288889e2730585a25832.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/MadeFace.png-40740ea983a1ab1c92432d4ea3d502f0.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/MadeFace.png"
dest_files=[ "res://.import/MadeFace.png-40740ea983a1ab1c92432d4ea3d502f0.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/empty_heart.png-d5162c5e8e7a097759d4ac469ed443a5.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/empty_heart.png"
dest_files=[ "res://.import/empty_heart.png-d5162c5e8e7a097759d4ac469ed443a5.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/grouchy Emoji.png-3dee223737c6be5a9cfffb5c278a5789.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/grouchy Emoji.png"
dest_files=[ "res://.import/grouchy Emoji.png-3dee223737c6be5a9cfffb5c278a5789.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

path: assets/grouchy Emoji.png.import


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/half_heart.png-5c30ee2b2176ebed4d19e9c95fd51dc1.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/half_heart.png"
dest_files=[ "res://.import/half_heart.png-5c30ee2b2176ebed4d19e9c95fd51dc1.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/heart.png-9a2fa56e49d8a002fed7c28ce07513e0.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart.png"
dest_files=[ "res://.import/heart.png-9a2fa56e49d8a002fed7c28ce07513e0.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile000.png-25bbbfe6236eaf54cf90b91e9e792b32.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile000.png"
dest_files=[ "res://.import/tile000.png-25bbbfe6236eaf54cf90b91e9e792b32.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile001.png-e05eedc1fa29da8731a87051b4c23eb8.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile001.png"
dest_files=[ "res://.import/tile001.png-e05eedc1fa29da8731a87051b4c23eb8.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile002.png-bc3de822b0c9953eb1e03bcb2f11a6f5.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile002.png"
dest_files=[ "res://.import/tile002.png-bc3de822b0c9953eb1e03bcb2f11a6f5.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile003.png-e4f539108b642b2a14629c5ef23dd9e6.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile003.png"
dest_files=[ "res://.import/tile003.png-e4f539108b642b2a14629c5ef23dd9e6.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile004.png-4f21ff513a358fa6b0451ee6ec01aaa2.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile004.png"
dest_files=[ "res://.import/tile004.png-4f21ff513a358fa6b0451ee6ec01aaa2.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile005.png-b3cd5f06fd906ec81d5c0ab2941a6792.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile005.png"
dest_files=[ "res://.import/tile005.png-b3cd5f06fd906ec81d5c0ab2941a6792.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile006.png-74f08ff8a6b7e981b51cfccb264a3c9e.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile006.png"
dest_files=[ "res://.import/tile006.png-74f08ff8a6b7e981b51cfccb264a3c9e.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile007.png-80e06f7c9ad4b75ba238044e2c98f212.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile007.png"
dest_files=[ "res://.import/tile007.png-80e06f7c9ad4b75ba238044e2c98f212.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile008.png-917d51243c240e06f4ce3523a16914a7.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile008.png"
dest_files=[ "res://.import/tile008.png-917d51243c240e06f4ce3523a16914a7.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile009.png-1c97385e535f5c783ffdd92a74c31a2c.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile009.png"
dest_files=[ "res://.import/tile009.png-1c97385e535f5c783ffdd92a74c31a2c.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile010.png-fd51a1174f656f3c3a9536f7d0d1507d.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile010.png"
dest_files=[ "res://.import/tile010.png-fd51a1174f656f3c3a9536f7d0d1507d.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile011.png-06058758550ef65ea8992764626849a0.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile011.png"
dest_files=[ "res://.import/tile011.png-06058758550ef65ea8992764626849a0.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile012.png-5ea587bd5c963978ffae30a1c9410fbb.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile012.png"
dest_files=[ "res://.import/tile012.png-5ea587bd5c963978ffae30a1c9410fbb.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile013.png-0b45321edc10d97929449fb81f07fd13.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile013.png"
dest_files=[ "res://.import/tile013.png-0b45321edc10d97929449fb81f07fd13.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile014.png-2d9663e86c01f76811bcbc0f83d553bb.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile014.png"
dest_files=[ "res://.import/tile014.png-2d9663e86c01f76811bcbc0f83d553bb.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile015.png-6ba984c641e203a212e0e2e7c6214060.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile015.png"
dest_files=[ "res://.import/tile015.png-6ba984c641e203a212e0e2e7c6214060.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile016.png-2c9a3364f87543d022ee02bc3b46eec5.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile016.png"
dest_files=[ "res://.import/tile016.png-2c9a3364f87543d022ee02bc3b46eec5.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile017.png-4461803f734e4f18cc48a1e93ebfd76f.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile017.png"
dest_files=[ "res://.import/tile017.png-4461803f734e4f18cc48a1e93ebfd76f.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile018.png-ef9fd85cd681d7282a128dccef905e3e.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile018.png"
dest_files=[ "res://.import/tile018.png-ef9fd85cd681d7282a128dccef905e3e.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile019.png-ad2f54a83618196232dace156fc30b8a.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile019.png"
dest_files=[ "res://.import/tile019.png-ad2f54a83618196232dace156fc30b8a.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile020.png-86d3251df0dc72947981c0b5aa6e36cc.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile020.png"
dest_files=[ "res://.import/tile020.png-86d3251df0dc72947981c0b5aa6e36cc.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile021.png-026644da5418dd1a2ed8e9a1d7c1a1a0.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile021.png"
dest_files=[ "res://.import/tile021.png-026644da5418dd1a2ed8e9a1d7c1a1a0.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile022.png-149e626ebb9121ae254eb826d15d6a40.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile022.png"
dest_files=[ "res://.import/tile022.png-149e626ebb9121ae254eb826d15d6a40.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile023.png-ecf018cccdef1b62f758ff6b6bfe4ddd.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile023.png"
dest_files=[ "res://.import/tile023.png-ecf018cccdef1b62f758ff6b6bfe4ddd.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile024.png-7a907898fcdfe3e1dc31e74ecfb1fb2c.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile024.png"
dest_files=[ "res://.import/tile024.png-7a907898fcdfe3e1dc31e74ecfb1fb2c.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile025.png-8add6d004c04376b649ed25ecc60e152.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile025.png"
dest_files=[ "res://.import/tile025.png-8add6d004c04376b649ed25ecc60e152.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile026.png-3bb1bab0fd643f1b8b4178a5fe3b7e1d.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile026.png"
dest_files=[ "res://.import/tile026.png-3bb1bab0fd643f1b8b4178a5fe3b7e1d.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile027.png-10b21b3e8db6d503afe80a3c026883c7.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile027.png"
dest_files=[ "res://.import/tile027.png-10b21b3e8db6d503afe80a3c026883c7.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile028.png-0e5a7c64d40f99ab5695793e3df31c5f.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile028.png"
dest_files=[ "res://.import/tile028.png-0e5a7c64d40f99ab5695793e3df31c5f.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tile029.png-7dd2680d503af1da05523b0edd97ba53.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/heart_animation/tile029.png"
dest_files=[ "res://.import/tile029.png-7dd2680d503af1da05523b0edd97ba53.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/huff.png-13ccc90cc03d2eea5c602bf4018db6eb.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/huff.png"
dest_files=[ "res://.import/huff.png-13ccc90cc03d2eea5c602bf4018db6eb.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/jealous emoji.png-ee2b06e984b4c0a1a5d6177091ddef21.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/jealous emoji.png"
dest_files=[ "res://.import/jealous emoji.png-ee2b06e984b4c0a1a5d6177091ddef21.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

path: assets/jealous emoji.png.import


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/kill.png-b86415de66c622cbf6bea8010050e6f7.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/kill.png"
dest_files=[ "res://.import/kill.png-b86415de66c622cbf6bea8010050e6f7.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/mending_heart.png-d4bea7255be53a6fc38c94021bc22b2c.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/mending_heart.png"
dest_files=[ "res://.import/mending_heart.png-d4bea7255be53a6fc38c94021bc22b2c.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/murdering.png-0227f9f94a7714a4671c70861cf64064.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/murdering.png"
dest_files=[ "res://.import/murdering.png-0227f9f94a7714a4671c70861cf64064.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/sad emoji.png-85a024cf9b185e542cdb3a26bd50d9ee.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/sad emoji.png"
dest_files=[ "res://.import/sad emoji.png-85a024cf9b185e542cdb3a26bd50d9ee.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

path: assets/sad emoji.png.import


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/sparkle_heart.2.png-db2818c5a4ab176e7d3e9f39f28669f2.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/sparkle_heart.2.png"
dest_files=[ "res://.import/sparkle_heart.2.png-db2818c5a4ab176e7d3e9f39f28669f2.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/sparkle_heart.png-47cb5c3a3fff5af53d76acfe976829b6.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/sparkle_heart.png"
dest_files=[ "res://.import/sparkle_heart.png-47cb5c3a3fff5af53d76acfe976829b6.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/tracking.png-6c5be1f81430f92b2f43e30cf196b69c.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://assets/tracking.png"
dest_files=[ "res://.import/tracking.png-6c5be1f81430f92b2f43e30cf196b69c.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
[gd_resource type="Environment" load_steps=2 format=2]

[sub_resource type="ProceduralSky" id=1]

[resource]
background_mode = 2
background_sky = SubResource( 1 )


code:
extends Node

signal murder_set(set)
signal spawn_set(set)
signal thought(board)
signal move(move)

var rng
var murders := []
var spawns := []
func _ready():
	rng = RandomNumberGenerator.new()
# warning-ignore:return_value_discarded
	connect("murder_set",self, "receive_murders")
# warning-ignore:return_value_discarded
	connect("spawn_set",self, "receive_spawns")

func receive_spawns(set):
	spawns= set
func receive_murders(set):
	murders= set

class Murder:
	var victim : GameOfLifeAndDeath.Position
	var killer1 : GameOfLifeAndDeath.Position
	var killer2 : GameOfLifeAndDeath.Position
	func _to_string() -> String:
		return("{V:" + str(victim) + " K1:" + str(killer1) + " K2:" + str(killer2)+"}")
# find the happy whos murder removes the most happyness
func mad_murder(board):
	var best_moves = []
	var best_score = INF

	var seperated = board.seperate_board()
	var _open : Array = seperated[0]
	var mad : Array = seperated[2].duplicate()
	var happy : Array = seperated[1]

	for test_killer1_id in range(mad.size()):
		for test_killer2_id  in range(test_killer1_id + 1, mad.size()):
			assert(test_killer1_id != test_killer2_id)
			var _best_board
			for test_victim in happy:
				var test_board = GameOfLifeAndDeath.new(board.board.duplicate(true), board.dim_x, board.dim_y)
				var test_killer1 = mad[test_killer1_id]
				var test_killer2 = mad[test_killer2_id]
				test_board.set_cell(test_killer1, GameOfLifeAndDeath.DEAD)
				test_board.set_cell(test_killer2, GameOfLifeAndDeath.DEAD)
				test_board.set_cell(test_victim, GameOfLifeAndDeath.DEAD)
				var results = test_board.GOL_board(GameOfLifeAndDeath.new({}, test_board.dim_x, test_board.dim_y))
		#		print("ai 51:" + str(results[1]))
				if results[1] <= best_score:

					emit_signal("thought", test_board)
					yield()

					_best_board = test_board
					var new_murder = Murder.new()
					new_murder.victim = test_victim
					new_murder.killer1 = test_killer1
					new_murder.killer2 = test_killer2
					if best_score == results[1]:
						best_moves.append(new_murder)
					else :
						best_moves = [new_murder]
						best_score = results[1]
		yield()

	emit_signal("murder_set", [best_score, best_moves])

func mad_spawn(board:GameOfLifeAndDeath):
	var best_moves : =[]#GameOfLifeAndDeath.Position
	var best_score = INF

	for y in range(board.dim_y):
		for x in range(board.dim_x):
			var pos = GameOfLifeAndDeath.Position.new(x, y)
			if not board.cell_alive_ka(pos):
				var test_board = GameOfLifeAndDeath.new(board.board.duplicate(true), board.dim_x, board.dim_y)
#				test_board.set_cell(pos, -4)
				var results = test_board.GOL_board(GameOfLifeAndDeath.new({}, test_board.dim_x, test_board.dim_y))
				if results[1] <= best_score:
					emit_signal("thought", test_board)
					yield()
					if results[1] < best_score:
						best_moves=[pos]
						best_score = results[1]
					else:
						best_moves.append(pos)
	emit_signal("spawn_set", [best_score, best_moves])

func get_move(current_board : GameOfLifeAndDeath, cur_happy : int, _cur_mad : int):
	print("ai 95: ai started")

	var thinking = mad_murder(current_board)
	yield()
	while thinking:
		thinking = thinking.resume()
		yield()
	thinking = mad_spawn(current_board)
	while thinking:
		thinking = thinking.resume()
		yield()

	var move =[{"piece": -4, "pos":spawns[1][rng.randi_range(0,spawns[1].size()-1)]}]
	if min(murders[0],spawns[0])<cur_happy:
		if murders[0] < spawns[0]:
			print("ai 105:murding")
			var seleced:Murder = murders[1][rng.randi_range(0,murders[1].size()-1)]
			move=[{"pos":seleced.victim, "piece":GameOfLifeAndDeath.DEAD},
			{"pos":seleced.killer1, "piece":GameOfLifeAndDeath.DEAD},
			{"pos":seleced.killer2, "piece":GameOfLifeAndDeath.DEAD}]
		else:
			print("ai 111: spawning")
			move=[{"pos":spawns[1][rng.randi()%spawns[1].size()], "piece":GameOfLifeAndDeath.M4}]
	else:
		print("ai 114: Huff!")
		move=[]
	print("ai 120: ai done")
	emit_signal("move",move)

func happy_tidy(board : GameOfLifeAndDeath):
	var best_move : GameOfLifeAndDeath.Position
	var best_score = -1

	for test_pos in board:
		var test_board = (GameOfLifeAndDeath.new(board.board, board.dim_x, board.dim_y))
		test_board.erase(test_pos)
		var results = test_board.GOL_board(GameOfLifeAndDeath.new({}, test_board.dim_x, test_board.dim_y))
		if (results[2] > best_score):
			best_move = test_pos
			best_score = results[2]
	return([best_score, best_move])

func happy_colonize(board : GameOfLifeAndDeath):

	var best_colony : GameOfLifeAndDeath.Position
	var best_settler1 : GameOfLifeAndDeath.Position
	var best_settler2 : GameOfLifeAndDeath.Position
	var best_score = -1

	var seperated = board.seperate_board()
	var me :Dictionary = seperated[1]
	var open : Dictionary = seperated[0]

	var pool : = me.keys()
	for test_settler1_id in range(pool.size()):
		for test_settler2_id  in range(test_settler1_id + 1, pool.size()):
			for test_colony in open:
				var test_board = GameOfLifeAndDeath.new(board.board, board.dim_x, board.dim_y)
				var test_settler1 = me[test_settler1_id]
				var test_settler2 = me[test_settler2_id]
				test_board.erase(test_settler1)
				test_board.erase(test_settler2)
				test_board[test_colony] = 4
				var results = test_board.GOL_board(GameOfLifeAndDeath.new({}, test_board.dim_x, test_board.dim_y))
				if results[2] > best_score:
					best_colony = test_colony
					best_settler1 = test_settler1
					best_settler2 = test_settler2
	return([best_score, best_colony, best_settler1, best_settler2])

### mad AI


code:
class_name GameOfLifeAndDeath

signal AI_move(move)

const H2 = 2
const H3 = 3
const H4 = 4
const DEAD = 0
const M2 = -2
const M3 = -3
const M4 = -4

var cell_regex : = RegEx.new()
var score_regex : = RegEx.new()

onready var web_ka : = OS.get_name() == "HTML5"

class Position:
	var x : int
	var y : int
	func _init(a, b):
		x = a
		y = b
	func _to_string():
		return("Pos x:"+str(x) +" Y:" +str(y))
	func id():
		return(str(x) +":" +str(y))

class Board:
	var _board : = {}
	func _to_string():
		var output : = "board="
		for x in _board:
			output += x + str(_board[x]) + " "
		return(output)

	func cell_alive_ka(pos: Position) -> bool:
		return(_board.has(pos.id()))

	func get_cell(pos: Position)-> int:
		return(_board[pos.id()])

	func set_cell(pos: Position, piece: int):
		if piece != 0:
			_board[pos.id()] = piece
		else:
			if cell_alive_ka(pos):
	# warning-ignore:return_value_discarded
				_board.erase(pos.id())

	func raw_set(pos_id, piece: int):
		if piece != 0:
			_board[pos_id] = piece
		else:
			if _board.has(pos_id):
	# warning-ignore:return_value_discarded
				_board.erase(pos_id)

func _ready():
	logy("golad 65|", cell_regex.compile("{(\\d+:\\d+) (-?\\d+)"))
	score_regex.compile("H=(\\d+) M=(\\d+)")

func piece2int(x:String):
	if x == "-4":
		return(0)
	elif x == "-3":
		return(-3)
	elif x == "-2":
		return(-2)
	elif x == "0":
		return(0)
	elif x == "2":
		return(2)
	elif x == "3":
		return(3)
	elif x == "4":
		return(4)

func get_board():
	var board : = Board.new()
	var JS_result : String
	if web_ka:
		JS_result = str(JavaScript.eval("gameLogic.shortBoard()", true))
		logy("Golad 94",JS_result)
	else:
		logy("Golod 96", "faking geting board")
		JS_result = "{4:7 2} {2:5 2} {7:7 2} {8:3 2} {6:1 2} {3:7 3} {3:3 3} {2:9 -3} {3:9 -3} {8:5 -3} {4:2 -2} {6:7 2} {5:6 3} {9:3 3} {1:2 -2} {2:7 -2} {0:5 2} {5:2 -2} {7:3 3} {4:6 3} {7:9 -3} {5:8 -3} {9:5 2} {7:1 3} {0:6 2} {1:1 -3} {2:2 -3} {1:4 3} {1:5 2}"
	var found_cells = cell_regex.search_all(JS_result)
	for cell in found_cells:
		#logy("golad 100", " '" + cell.get_string(1) + "' '" + cell.get_string(2) + "'")
		board.raw_set(cell.get_string(1), piece2int(cell.get_string(2)))
	return(board)

func get_cur_piece(x, y):
	var JS_result : float
	if web_ka:
		JS_result = JavaScript.eval("gameLogic.getGameCell(" + str(x) + ", " + str(y) + ")", true)
		logy("golad 109", JS_result)
	else:
		JS_result=0
	return(int(JS_result))

func get_preview():
	var JS_result : String
	if web_ka:
		JS_result = str(JavaScript.eval("gameLogic.preview()", true))
		logy("Golad 109", JS_result)
	else:
		JS_result = "H=6 M=9 {4:7 2} {2:5 2} {7:7 2} {8:3 2} {6:1 2} {3:7 3} {3:3 3} {2:9 -3} {3:9 -3} {8:5 -3} {4:2 -2} {6:7 2} {5:6 3} {9:3 3} {1:2 -2} {2:7 -2} {0:5 2} {5:2 -2} {7:3 3} {4:6 3} {7:9 -3} {5:8 -3} {9:5 2} {7:1 3} {0:6 2} {1:1 -3} {2:2 -3} {1:4 3} {1:5 2}"
		logy("golad 122", "faking preview")
	var board : = Board.new()
	var found_cells = cell_regex.search_all(JS_result)
	for cell in found_cells:
		board.raw_set(cell.get_string(1), piece2int(cell.get_string(2)))
	var my_match = score_regex.search(JS_result)
	return([board, int(my_match.get_string(1)), int(my_match.get_string(2))])

func new_game(rows, cols):
	logy("golad 122", JavaScript.eval("gameLogic.newBoard(" + str(rows) + ", " + str(cols) + """);
	gameLogic.resetPlayerState();
	""", true))

func reset_preview():
	logy("Golad 101:", JavaScript.eval("gameLogic.resetPlayerState()", true))

func set_cell(x, y, piece):
	JavaScript.eval("gameLogic.setGameCell(" + str(x) + ", " + str(y) + ", " + str(piece) + ")", true)

func set_preview_cell(x, y, piece):
	logy("Golad 136", JavaScript.eval("gameLogic.setPlayerCell(" + str(x) + ", " + str(y) + ", " + str(piece) + ")", true))

func tick_game() -> Array:
	var JS_result : String
	if web_ka:
		JS_result = str(JavaScript.eval("gameLogic.tickGame()", true))
		logy("golad 143:", JS_result)
	else:
		logy("golad 145", "faking score for game tick on" + OS.get_name())
		JS_result = "H=1 M=2"
	var my_match = score_regex.search(JS_result)
	if my_match:
		logy("golad 117", "scored reg worked")
	return([my_match.get_string(1), my_match.get_string(2)])

func get_ai_move():
	var JS_result : String
	if web_ka:
		JS_result = str(JavaScript.eval("gameLogic.getAIMove()", true))
	else:
		JS_result = "M1:1|2:2|3:3"
	logy("golad 122:", JS_result)
	emit_signal("AI_move", JS_result)

################################################################################
# for setup

static func rand_life()-> int:
	if randf() <.4:
		return(rand_piece())
	else:
		return(DEAD)

static func rand_piece()-> int:
	match (randi()%2):
		1:
			return(H3)
		0:
			return(M3)
		_:
			print("game_golad.gd 157:oops")
			return(M4)

func logy(lvl, msg):
	match lvl:
		_:
			var temp = get_stack()
			if temp.size() > 1:
				msg = temp[1].source + " " + "%3d" % temp[1].line + ":" + str(msg)
			else:
				msg = 'game_golad.gd  ??' + str(msg)
	print(msg)


code:
[remap]

importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]

[params]

compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0


code:
<!DOCTYPE html>

		<meta charset='utf-8' />
		<meta name='viewport' content='width=device-width, user-scalable=no' />
		<title>$GODOT_PROJECT_NAME</title>

	$GODOT_HEAD_INCLUDE

		<canvas id='canvas'>
			HTML5 canvas appears to be unsupported in the current browser.

			Please try updating or use a different browser.
		</canvas>


code:
<!DOCTYPE html>
<html>
    <head>
        <title>My hopefully this works</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <canvas id="canvas"></canvas>
        <script src="$GODOT_URL"></script>
        <script>
            let gameLogic
	    async function main() {
	        gameLogic = await import ("./golados_rust.js");
	        await gameLogic.default();

                var engine = new Engine($GODOT_CONFIG);
                engine.startGame();
            };
main();

        </script>
    </body>
</html>


code:
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
;   [section] ; section goes between []
;   param=value ; assign values to parameters

config_version=4

_global_script_classes=[ {
"base": "Reference",
"class": "GameOfLifeAndDeath",
"language": "GDScript",
"path": "res://game_golad.gd"
} ]
_global_script_class_icons={
"GameOfLifeAndDeath": ""
}

[application]

config/name="Golados"
run/main_scene="res://Relationship.tscn"
config/icon="res://icon.png"

[display]

window/size/width=640
window/size/height=480

[physics]

common/enable_pause_aware_picking=true

[rendering]

quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_environment="res://default_env.tres"


code:
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
 "memchr",
]

[[package]]
name = "bumpalo"
version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "golados-rust"
version = "0.1.0"
dependencies = [
 "regex",
 "thats_so_random",
 "wasm-bindgen",
]

[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
 "cfg-if",
]

[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"

[[package]]
name = "once_cell"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"

[[package]]
name = "proc-macro2"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "regex"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
 "aho-corasick",
 "memchr",
 "regex-syntax",
]

[[package]]
name = "regex-syntax"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"

[[package]]
name = "syn"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "thats_so_random"
version = "0.1.0"
source = "git+https://github.com/DrAlta/thats_so_random.rs.git#9ea817708098f942b27e6c6e0901e0d5263d53d3"

[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"

[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
 "cfg-if",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
 "bumpalo",
 "log",
 "once_cell",
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"


code:
[package]
name = "golados-rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
regex = "1"
wasm-bindgen = "0.2.83"
thats_so_random = { git = "https://github.com/DrAlta/thats_so_random.rs.git" }

[build]
target = "web"


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>GoDoLdos Rust engine test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />


code:
//use std::cmp::min;
use crate::golad::Position;
use crate::golad::Board;
use crate::golad::CellType;
use crate::golad::Birth::User;
use thats_so_random::Pcg32;

#[allow(dead_code)]
#[derive(Debug)]
pub enum Move{
    Murder{victim: Position, killer: Position, accomplice: Position},
    Spawn(Position),
    Colonize{colony: Position, colonizer: Position, colonizess: Position},
    Tidy(Position),
}

fn random_item<T>(mut list:  Vec<T>, rng: &mut Pcg32) -> T{
    list.remove(rng.next_u32() as usize % list.len())
}

pub fn mad_move(board:&Board, rng: &mut Pcg32) -> Option<Move>{
    let current_happy_count = board.separate_happy_mad().0.len() as i32;
    let murders = murder(board);
    let spawns = spawn(board);
    if (murders.0 != None) && (murders.0.unwrap() < current_happy_count) {
        if (spawns.0 != None) && (spawns.0.unwrap() < murders.0.unwrap()) {
            return Some(Move::Spawn(random_item(spawns.1, rng)));
        } else { // acceptable murder and  spawn is worst that murdering
            return Some(random_item(murders.1, rng));
        }
    } else { // no acceptable murders
        if (spawns.0 != None) && (spawns.0.unwrap() < current_happy_count) {
            return Some(Move::Spawn(random_item(spawns.1, rng)));
        }
        //no acceptable murders or spawns
        return None
    }
}

/*
pub fn murder(board:&Board) -> (i32, Vec<Move>){
    let mut best_moves:Vec<Move> = Vec::new();
    let mut best_score = i32::MAX;

    let (happy, mad) = board.separate_happy_mad();
    let mad_count = mad.len();
    let mut test_killer_id = 0;
    while test_killer_id < mad_count {
        let mut test_accomplice_id = test_killer_id + 1;
        while test_accomplice_id < mad_count {
            for test_victim in &happy {
                let mut test_board = board.clone();
                test_board.set_cell(test_victim, &CellType::Dead);
                test_board.set_cell(&mad[test_killer_id], &CellType::Dead);
                test_board.set_cell(&mad[test_accomplice_id], &CellType::Dead);

                let result = test_board.tick().1;
                if result <= best_score {
                    if result < best_score {
                        best_score = result;
                        best_moves.clear();
                    };
                    best_moves.push(Murder { victim: *test_victim, killer: mad[test_killer_id], accomplice: mad[test_accomplice_id] });
                };
            }
        test_accomplice_id += 1;
        }
    test_killer_id += 1;
    }
    (best_score, best_moves)
}*/

pub fn murder(board:&Board) -> (Option<i32>, Vec<Move>){
    let mut best_moves:Vec<Move> = Vec::new();
    let mut best_score:Option<i32> = None;

    let (happy, mad) = board.separate_happy_mad();
    let mad_count = mad.len();
    let mut test_killer_id = 0;
    while test_killer_id < mad_count {
        let mut test_accomplice_id = test_killer_id + 1;
        while test_accomplice_id < mad_count {
            for test_victim in &happy {
                let mut test_board = board.clone();
                test_board.set_cell(test_victim, &CellType::Dead);
                test_board.set_cell(&mad[test_killer_id], &CellType::Dead);
                test_board.set_cell(&mad[test_accomplice_id], &CellType::Dead);

                let result = test_board.tick().1;
                if let Some(x) = best_score {
                    if result <= x {
                        if result < x {
                            best_score = Some(result);
                            best_moves.clear();
                        };
                        best_moves.push(Move::Murder { victim: *test_victim, killer: mad[test_killer_id], accomplice: mad[test_accomplice_id] });
                    };
                } else {
                    best_score = Some(result);
                    best_moves.push(Move::Murder { victim: *test_victim, killer: mad[test_killer_id], accomplice: mad[test_accomplice_id] })

                };
            }
        test_accomplice_id += 1;
        }
    test_killer_id += 1;
    }
    (best_score, best_moves)
}
/*
pub fn spawn(board:&Board, peek_ahead_count: i32) -> (Option<i32>, Vec<Position>){
    let mut best_moves:Vec<Position> = Vec::new();
    let mut best_score = None;

    let mut y = 0;
    while y < board.height{
        let mut x = 0;
        while x < board.width{
            let pos = Position { x:x, y:y };
            if !board.cell_alive_ka(&pos) {
                let mut test_board = board.clone();
                test_board.set_cell(&pos,&CellType::Mad(4));

                let result = test_board.tick();
                // if the move doesn't change the number of happy look ahead another tick; this is fore 2 by 2 squares of happy
                let test_score = if result.1 == peek_ahead_count {
                    result.0.tick().1
                } else {
                    result.1
                };
                if test_score <= best_score {
                    if test_score < best_score {
                        best_score = test_score;
                        best_moves.clear();
                    };
                    best_moves.push(pos);
                };
            };
        x += 1
        };
    y += 1;
    };
    (best_score, best_moves)
}*/

pub fn spawn(board:&Board) -> (Option<i32>, Vec<Position>){
    let mut best_moves:Vec<Position> = Vec::new();
    let mut best_score_maybe : Option<i32> = None;

    let mut y = 0;
    while y < board.height{
        let mut x = 0;
        while x < board.width{
            let pos = Position { x:x, y:y };
            if !board.cell_alive_ka(&pos) {
                let mut test_board = board.clone();
                test_board.set_cell(&pos,&CellType::Mad(User));

                let test_score = test_board.tick().1;
                if let Some(best_score) = best_score_maybe{
                    if test_score <= best_score {
                        if test_score < best_score {
                            best_score_maybe = Some(test_score);
                            best_moves.clear();
                        };
                        best_moves.push(pos);
                    };
                } else{
                    best_score_maybe = Some(test_score);
                    best_moves.push(pos);
                };
            };
        x += 1
        };
    y += 1;
    };
    (best_score_maybe, best_moves)
}
/*
/// this version is too good. getting the ai to not being able to make move that
/// will reduce the happiness is import for the other sub games
/// I could have the ai return a flag saying she could find a move that will
/// reduce happiness. or just check to see if happiness if lower after the
/// move it made.
pub fn spawn_old(board:&Board, peek_ahead_count: i32) -> (Option<i32>, Vec<Position>){
    let mut best_moves:Vec<Position> = Vec::new();
    let mut best_score_maybe : Option<i32> = None;

    let mut y = 0;
    while y < board.height{
        let mut x = 0;
        while x < board.width{
            let pos = Position { x:x, y:y };
            if !board.cell_alive_ka(&pos) {
                let mut test_board = board.clone();
                test_board.set_cell(&pos,&CellType::Mad(4));

                let result = test_board.tick();
                // if the move doesn't change the number of happy look ahead another tick; this is fore 2 by 2 squares of happy
                let test_score = if result.1 == peek_ahead_count {
                    result.0.tick().1
                } else {
                    result.1
                };
                if let Some(best_score) = best_score_maybe{
                    if test_score <= best_score {
                        if test_score < best_score {
                            best_score_maybe = Some(test_score);
                            best_moves.clear();
                        };
                        best_moves.push(pos);
                    };
                } else{
                    best_score_maybe = Some(test_score);
                    best_moves.push(pos);
                };
            };
        x += 1
        };
    y += 1;
    };
    (best_score_maybe, best_moves)
}

#[allow(dead_code)]
pub fn mad_spawn_old2(board:Board) -> Vec<Position>{
    let mut best_moves:Vec<Position> = Vec::new();
    let mut best_score: Option<i32> = None;
    let (open, happy, _mad) = board.separate();
    let happy_count = happy.len();

    for pos in open{
        let mut test_board = board.clone();
        test_board.set_cell(&pos,&CellType::Mad(4));

        let result = test_board.tick();
        // if the move doesn't change the number of happy look ahead another tick; this is fore 2 by 2 squares of happy
        let test_score = if result.1 as usize == happy_count {
            result.0.tick().1
        } else {
            result.1
        };
        if let Some(x) = best_score {
            if test_score <= x {
                if test_score < x {
                    best_score = Some(test_score);
                    best_moves.clear();
                };
                best_moves.push(pos);
            };
        } else {
            best_score = Some(test_score);
            best_moves.push(pos);

        };
    }
    best_moves
}

pub fn mad_spawn_old(board:Board) -> Vec<Position>{
    let mut best_moves:Vec<Position> = Vec::new();
    let mut best_score: Option<i32> = None;

    let mut y = 0;
    while y < board.height{
        let mut x = 0;
        while x < board.width{
            let pos = Position { x:x, y:y };
            if !board.cell_alive_ka(&pos) {
                let mut test_board = board.clone();
                test_board.set_cell(&pos,&CellType::Mad(4));
                let result = test_board.tick().0.tick().1;

                if let Some(x) = best_score {
                    if result <= x {
                        if result < x {
                            best_score = Some(result);
                            best_moves.clear();
                            println!("bs {}", best_score.unwrap());
                        };
                        best_moves.push(pos);
                    };
                } else {
                    best_score = Some(result);
                    best_moves.push(pos);

                };

            };
        x += 1
        };
    y += 1;
    };
    best_moves

}
*/
#[allow(dead_code)]
pub fn tidy(board: &Board) -> (Option<i32>, Vec<Position>){
    let mut best_score_maybe: Option<i32> = None;
    let mut best_moves:Vec<Position> = Vec::new();
    let (happies, mads) = board.separate_happy_mad();

    for pos in happies {
        let mut test_board = board.clone();
        test_board.set_cell(&pos,&CellType::Dead);
        let test_score = test_board.tick().1;

        if let Some(best_score) = best_score_maybe {
            if test_score <= best_score {
                if test_score < best_score {
                    best_score_maybe = Some(test_score);
                    best_moves.clear();
                };
                best_moves.push(pos);
            };
        } else {
            best_score_maybe = Some(test_score);
            best_moves.push(pos);

        };
    };

    for pos in mads {
        let mut test_board = board.clone();
        test_board.set_cell(&pos,&CellType::Dead);
        let test_score = test_board.tick().1;

        if let Some(best_score) = best_score_maybe {
            if test_score <= best_score {
                if test_score < best_score {
                    best_score_maybe = Some(test_score);
                    best_moves.clear();
                };
                best_moves.push(pos);
            };
        } else {
            best_score_maybe = Some(test_score);
            best_moves.push(pos);
        };
    };

    (best_score_maybe, best_moves)
}

#[allow(dead_code)]
pub fn colonize(board:&Board, peek_ahead_count: i32) -> (Option<i32>, Vec<Move>){
    let mut best_moves:Vec<Move> = Vec::new();
    let mut best_score_maybe:Option<i32> = None;

    let mad = board.separate_happy_mad().1;
    let mad_count = mad.len();
    let mut colonizer_id = 0;
    while colonizer_id < mad_count {
        let mut colonizess_id = colonizer_id + 1;
        while colonizess_id < mad_count {
            let mut y = 0;
            while y < board.height{
                let mut x = 0;
                while x < board.width{
                    let pos = Position { x:x, y:y };
                    if !board.cell_alive_ka(&pos) {
                        let mut test_board = board.clone();
                        test_board.set_cell(&pos,&CellType::Happy(User));
                        test_board.set_cell(&mad[colonizer_id], &CellType::Dead);
                        test_board.set_cell(&mad[colonizess_id], &CellType::Dead);

                        let result = test_board.tick();
                        // if the move doesn't change the number of happy look ahead another tick; this is fore 2 by 2 squares of happy
                        let test_score = if result.1 == peek_ahead_count {
                            result.0.tick().1
                        } else {
                            result.1
                        };
                        if let Some(best_score) = best_score_maybe{
                            if test_score <= best_score {
                                if test_score < best_score {
                                    best_score_maybe = Some(test_score);
                                    best_moves.clear();
                                };
                                best_moves.push(Move::Colonize{colony:pos, colonizer:mad[colonizer_id], colonizess:mad[colonizess_id]});
                            };
                        } else{
                            best_score_maybe = Some(test_score);
                            best_moves.push(Move::Colonize{colony:pos, colonizer:mad[colonizer_id], colonizess:mad[colonizess_id]});
                        };
                    };
                x += 1
                };
            y += 1;
            };
        colonizess_id += 1;
        }
    colonizer_id += 1;
    }
    (best_score_maybe, best_moves)
}

#[allow(dead_code)]
pub fn happy_move(board: &Board, rng: &mut Pcg32) -> Option<Move>{
    let current_mad_count = board.separate_happy_mad().1.len() as i32;
    let colonies = colonize(board, current_mad_count);
    let tidies = tidy(board);
    if (colonies.0 != None) && (colonies.0.unwrap() < current_mad_count) {
        if (tidies.0 != None) && (tidies.0.unwrap() < colonies.0.unwrap()) {
            return Some(Move::Tidy(random_item(tidies.1, rng)));
        } else { // acceptable murder and  spawn is worst that murdering
            return Some(random_item(colonies.1, rng));
        }
    } else { // no acceptable murders
        if (tidies.0 != None) && (tidies.0.unwrap() < current_mad_count) {
            return Some(Move::Tidy(random_item(tidies.1, rng)));
        }
        //no acceptable murders or spawns
        return None
    }
}


code:
use std::fmt;
use std::collections::HashMap;
use Birth::{Mixed, Pure, User};

//##########################################################3
//Pos
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub struct Position {
    pub x: u8,
    pub y: u8,
}

impl Position{
    pub fn short_str(&self) -> String {
        format!("{}:{}", self.x, self.y)
    }
}
impl fmt::Display for Position {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Write strictly the first element into the supplied output
        // stream: `f`. Returns `fmt::Result` which indicates whether the
        // operation succeeded or failed. Note that `write!` uses syntax which
        // is very similar to `println!`.
        write!(f, "X:{} Y:{}", self.x, self.y)
    }

}

#[derive(Debug, PartialEq, Clone)]
pub enum CellType {
    Dead,
    Happy(Birth),
    Mad(Birth)
}

impl CellType{
    pub fn short_str(&self) -> &str {
        match *self {
            CellType::Dead => "0",
            CellType::Happy(x) => {
                match x {
                    Birth::Mixed => {
                        "2"
                    },
                    Birth::Pure => {
                        "3"
                    },
                    Birth::User => {
                        "4"
                    },
                }
            },
            CellType::Mad(x) => {
                match x {
                    Birth::Mixed => {
                        "-2"
                    },
                    Birth::Pure => {
                        "-3"
                    },
                    Birth::User => {
                        "-4"
                    },
                }
            },
        }
    }
}

impl fmt::Display for CellType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Write strictly the first element into the supplied output
        // stream: `f`. Returns `fmt::Result` which indicates whether the
        // operation succeeded or failed. Note that `write!` uses syntax which
        // is very similar to `println!`.
        match *self {
            CellType::Dead => write!(f, "Dead"),
            CellType::Happy(x) => write!(f, "Happy{}", x),
            CellType::Mad(x) => write!(f, "Mad{}", x),
        }
    }

}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Birth {
    Mixed,
    Pure,
    User,
}

impl fmt::Display for Birth {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Birth::Mixed => write!(f, "2"),
            Birth::Pure => write!(f, "3"),
            Birth::User => write!(f, "4"),
        }
    }

}

#[derive(Debug, Clone)]
pub struct Board {
    pub width: u8,
    pub height: u8,
    pub cells: HashMap<Position, CellType>,
}

impl fmt::Display for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut output: String = format!("{{W:{} H:{} ", self.width, self.height);
        let mut first = true ;
        for key in self.cells.keys() {
            if let Some(x) = self.cells.get(key) {
                output =
                   if first {
                        first= false;
                        format!("{}[{}={}]", output, key, x)
                        }
                    else{
                        format!("{}, [{}={}]", output, key, x)
                        };
            }
        }
        write!(f, "{}}}", output)
    }
}

impl Board {
    pub fn new(columns: u8, rows: u8) -> Board {
        Board {
            width: columns,
            height: rows,
            cells: HashMap::new(),
        }
    }

    pub fn cell_alive_ka(&self, pos: &Position) -> bool {
        self.cells.contains_key(&self.wrap_position(pos))
    }

    pub fn short_str(&self)-> String{
        let mut output = "".to_string();
        for (pos, value) in &self.cells{
            output.push_str("{");
            output.push_str(pos.short_str().as_str());
            output.push_str(" ");
            output.push_str(value.short_str());
            output.push_str("} ");
        }
        output.pop();
        output
    }

    pub fn ascii_art(&self)->String{
        let mut output = "".to_string();
        let mut y = 0;
        while y < self.height{
            let mut x = 0;
            while x < self.width{
                let pos = Position { x:x, y:y };
                match self.get_cell(&pos) {
                    CellType::Dead => output = format!("{} ", output),
                    CellType::Happy(_) => output = format!("{}H", output),
                    CellType::Mad(_) => output = format!("{}M", output),
                };
                x += 1;
            }
            output = format!("{}\n", output);
            y += 1;
        }
     output
    }

   pub fn get_cell(&self, pos: &Position) -> CellType {
        let wrapped = self.wrap_position(pos);
        match self.cells.get(&wrapped) {
            Some(&CellType::Happy(x)) => CellType::Happy(x),
            Some(&CellType::Mad(x)) => CellType::Mad(x),
            Some(&CellType::Dead) => unreachable!(),
            None => CellType::Dead
        }
    }

#[allow(dead_code)]
    pub fn separate(&self) -> (Vec<Position>, Vec<Position>, Vec<Position>) {
        let mut happy:Vec<Position> = Vec::new();
        let mut mad:Vec<Position> = Vec::new();
        let mut open:Vec<Position> = Vec::new();

        let mut y = 0;
        while y < self.height{
            let mut x = 0;
            while x < self.width{
                let pos = Position { x:x, y:y };
                    match self.get_cell(&pos) {
                        CellType::Dead => open.push(pos),
                        CellType::Happy(_) => happy.push(pos),
                        CellType::Mad(_) => mad.push(pos),
                    };
            x += 1
            };
        y += 1;
        };
        (open, happy, mad)
    }

    pub fn separate_happy_mad(&self) -> (Vec<Position>, Vec<Position>) {
        let mut happy:Vec<Position> = Vec::new();
        let mut mad:Vec<Position> = Vec::new();

        let mut y = 0;
        while y < self.height{
            let mut x = 0;
            while x < self.width{
                let pos = Position { x:x, y:y };
                    match self.get_cell(&pos) {
                        CellType::Dead => {},
                        CellType::Happy(_) => happy.push(pos),
                        CellType::Mad(_) => mad.push(pos),
                    };
            x += 1
            };
        y += 1;
        };
        (happy, mad)
    }

    pub fn set_cell(&mut self, pos:&Position, piece: &CellType) {
        if piece == &CellType::Dead {
            self.cells.remove(pos);
        } else {
            self.cells.insert(pos.clone(), piece.clone());
        };
    }

    pub fn do_tidy(&mut self, pos:&Position) {
        self.set_cell(pos, &CellType::Dead)
    }

    pub fn do_happy_spawn(&mut self, pos:&Position) {
        self.set_cell(pos, &CellType::Happy(User))
    }

    pub fn do_mad_spawn(&mut self, pos:&Position) {
        self.set_cell(pos, &CellType::Mad(User))
    }

    pub fn do_murder(&mut self, victum:&Position, killer:&Position, accomplice:&Position) {
        self.set_cell(victum, &CellType::Dead);
        self.set_cell(killer, &CellType::Dead);
        self.set_cell(accomplice, &CellType::Dead);
    }
    pub fn do_happy_colonize(&mut self, colony:&Position, coloner:&Position, coloness:&Position) {
        self.set_cell(colony, &CellType::Happy(User));
        self.set_cell(coloner, &CellType::Dead);
        self.set_cell(coloness, &CellType::Dead);
    }

//returns the next board, the number of happy cell, the number of mad cells.
    pub fn tick(&self) -> (Board, i32, i32) {
        let mut new_happy_count = 0;
        let mut new_mad_count = 0;

        let mut next = Ooze::new(self.width, self.height);

        for row in 0..self.height {
            for col in 0..self.width {
                let pos = Position {x: row, y: col};
                let cell = self.tick_cell(&pos);
                match cell {
                    CellType::Happy(_) => new_happy_count += 1,
                    CellType::Mad(_) => new_mad_count += 1,
                    _ => ()
                }
                next = next.cell(pos, cell);
            }
        }

        (next.spawn(), new_happy_count, new_mad_count)
    }

#[allow(dead_code)]
    fn tick_delta(&self) -> (Board, i32, i32, HashMap<Position, CellType>) {
        let mut new_happy_count = 0;
        let mut new_mad_count = 0;
        let mut delta:HashMap<Position, CellType> = HashMap::new();

        let mut next = Ooze::new(self.width, self.height);

        for row in 0..self.height {
            for col in 0..self.width {
                let pos = Position {x: row, y: col};
                let (cell, new) = self.tick_cell_new(&pos);
                if new {
                    delta.insert(pos.clone(), cell.clone());
                };
                match cell {
                    CellType::Happy(_) => {
                        new_happy_count += 1;
                        if self.cell_alive_ka(&pos){

                        }
                    },
                    CellType::Mad(_) => new_mad_count += 1,
                    _ => ()
                }
                next = next.cell(pos, cell);
            }
        }

        (next.spawn(), new_happy_count, new_mad_count, delta)
    }

    fn tick_cell(&self, pos: &Position) -> CellType {
        let mut live_neighbor_count = 0u8;
        let mut happy_neighbor_count = 0u8;

        for delta_row in [self.height - 1, 0, 1].iter().cloned() {
            for delta_col in [self.width - 1, 0, 1].iter().cloned() {
                if delta_row != 0 || delta_col != 0 {
                    let neighbor = Position {x: (self.width + pos.x + delta_row) % self.width,
                                             y: (self.height + pos.y + delta_col) % self.height};
                    if self.cells.contains_key(&neighbor) {
                        match self.cells.get(&neighbor) {
                            Some(CellType::Happy(_)) => {
                                live_neighbor_count += 1;
                                happy_neighbor_count += 1;
                            },
                            Some(CellType::Mad(_)) => {
                                live_neighbor_count += 1;
                            },
                            _ => {},
                        }
                    }
                }
            }
            //
            }
        match (live_neighbor_count, happy_neighbor_count) {
            (3, 3) => CellType::Happy(Pure),
            (3, 2) => CellType::Happy(Mixed),
            (3, 1) => CellType::Mad(Mixed),
            (3, 0) => CellType::Mad(Pure),
            (2, _) => self.get_cell(pos),
            _ => CellType::Dead,

        }
    }
/// returns (next_cell_state, will_cell_state_changed)
    fn tick_cell_new(&self, pos: &Position) -> (CellType, bool) {
        let mut live_neighbor_count = 0u8;
        let mut happy_neighbor_count = 0u8;

        for delta_row in [self.height - 1, 0, 1].iter().cloned() {
            for delta_col in [self.width - 1, 0, 1].iter().cloned() {
                if delta_row != 0 || delta_col != 0 {
                    let neighbor = Position {x: (self.width + pos.x + delta_row) % self.width,
                                             y: (self.height + pos.y + delta_col) % self.height};
                    if self.cells.contains_key(&neighbor) {
                        match self.cells.get(&neighbor) {
                            Some(CellType::Happy(_)) => {
                                live_neighbor_count += 1;
                                happy_neighbor_count += 1;
                            },
                            Some(CellType::Mad(_)) => {
                                live_neighbor_count += 1;
                            },
                            _ => {},
                        }
                    }
                }
            }
            //
            }
        match (live_neighbor_count, happy_neighbor_count) {
            (3, 3) => (CellType::Happy(Pure),true),
            (3, 2) => (CellType::Happy(Mixed),true),
            (3, 1) => (CellType::Mad(Mixed),true),
            (3, 0) => (CellType::Mad(Pure),true),
            (2, _) => (self.get_cell(pos), false),
            _ => (CellType::Dead, true),

        }
    }

    fn wrap_position(&self, pos: &Position) -> Position {
        Position {x: pos.x % self.width, y: pos.y % self.height}
    }

}

pub struct Ooze {
    width: u8,
    height: u8,
    cells: HashMap<Position, CellType>,
}
/// build a new Game of Life and Death board
impl Ooze {
    pub fn new(columns: u8, rows: u8) -> Ooze {
        Ooze {
            width: columns,
            height: rows,
            cells: HashMap::new(),
        }
    }
    /// Add a cell to the board
    pub fn cell(mut self, pos: Position, life: CellType) -> Ooze {
        if life != CellType::Dead {
            self.cells.insert(pos, life);
        };
        self
    }
    /// Generate the board
    pub fn spawn(self) -> Board {
        Board { width:self.width, height: self.height, cells: self.cells}
    }
}