LoopyTest/scripts/GameScene.gd

239 lines
7.0 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node2D
export var boardSize: Vector2 = Vector2(10,7)
class_name GameScene
var reality: GameState
var simulate: GameState
func _ready() -> void:
reality = GameState.new()
reality.init_arrays(boardSize)
var cellScene: PackedScene = load("res://scenes/Cell.tscn")
var lineScene: PackedScene = load("res://scenes/Line.tscn")
for cellIdx in range(reality.get_cell_count()):
var cell: Node = cellScene.instance()
cell.idx = cellIdx
add_child(cell)
for lineIdx in range(reality.get_line_count()):
var line: Node = lineScene.instance()
line.idx = lineIdx
add_child(line)
line.connect("line_clicked", self, "_line_clicked")
print("Lines at 0,0: %s" % [get_lines_by_grid(Vector2(0,0))])
print("Lines at 0,1: %s" % [get_lines_by_grid(Vector2(0,1))])
func _line_clicked(lineIdx: int):
var line: LineAccessor = get_line(lineIdx)
line.set_owner(1)
var surrounds: int = test_line_surrounds(lineIdx)
print("Line %d clicked! Surrounded: %d" % [lineIdx, surrounds])
# +ve: down and left
# -ve: up and right
var cell: CellAccessor = null
if surrounds > 0:
if line.get_horizontal():
cell = get_cell_by_grid(line.get_grid1() + Vector2(0,1))
else:
cell = get_cell_by_grid(line.get_grid1())
elif surrounds < 0:
if line.get_horizontal():
cell = get_cell_by_grid(line.get_grid1())
else:
cell = get_cell_by_grid(line.get_grid1() + Vector2(1,0))
if cell != null:
flood_owner(cell, 1)
func flood_owner(cell: CellAccessor, owner: int):
if cell.get_owner() != 0:
return
cell.set_owner(owner)
if get_line_by_grid(cell.get_grid() - Vector2(0,1), true).get_owner() == 0:
flood_owner(get_cell_by_grid(cell.get_grid() - Vector2(0,1)), owner)
if get_line_by_grid(cell.get_grid(), true).get_owner() == 0:
flood_owner(get_cell_by_grid(cell.get_grid() + Vector2(0,1)), owner)
if get_line_by_grid(cell.get_grid() - Vector2(1,0), false).get_owner() == 0:
flood_owner(get_cell_by_grid(cell.get_grid() - Vector2(1,0)), owner)
if get_line_by_grid(cell.get_grid(), false).get_owner() == 0:
flood_owner(get_cell_by_grid(cell.get_grid() + Vector2(1,0)), owner)
func test_line_surrounds(startIdx: int) -> int:
var startLine: LineAccessor = get_line(startIdx)
var grid0: Vector2 = startLine.get_grid0()
var grid1: Vector2 = startLine.get_grid1()
var openSet: Array = [grid0] # points yet to visit
var closedSet: Array = [] # points visited already
while openSet.size() > 0:
var point: Vector2 = openSet.pop_front()
closedSet.push_back(point)
var lines: Array = get_lines_by_grid(point)
for line in lines:
if line.get_owner() == 0:
continue # don't follow unowned lines
if line.idx == startIdx:
continue # don't follow the start line
var otherSide: Vector2 = line.get_grid_other_end(point)
if otherSide == grid1:
closedSet.append(otherSide)
print("Loop found: %s" % [closedSet])
return calulate_winding(closedSet) # we made it!
if otherSide in closedSet:
continue # been there done that
elif otherSide in openSet:
continue # we already plan to go there
else:
openSet.push_back(otherSide)
return 0
func calulate_winding(points: Array) -> int:
# Sum over the edges, (x2 x1)(y2 + y1).
# If the result is positive the curve is clockwise, if it's negative the curve is counter-clockwise.
# (The result is twice the enclosed area, with a +/- convention.)
var ret: int = 0
for idx in range(points.size()):
var point1: Vector2 = points[idx-1]
var point2: Vector2 = points[idx]
ret += int(point2.x - point1.x) * int(point2.y + point1.y)
return ret/2
func get_cell(idx: int) -> CellAccessor:
var ret: CellAccessor = CellAccessor.new()
ret.gameScene = self
ret.idx = idx
return ret
func get_cell_idx_by_grid(pos: Vector2) -> int:
return int((pos.y * boardSize.x) + pos.x)
func get_cell_by_grid(pos: Vector2) -> CellAccessor:
return get_cell(get_cell_idx_by_grid(pos))
func get_line(idx: int) -> LineAccessor:
var ret: LineAccessor = LineAccessor.new()
ret.idx = idx
ret.gameScene = self
return ret
func get_line_by_grid(pos: Vector2, horizontal: bool) -> LineAccessor:
var idx: int
if horizontal:
idx = get_cell_idx_by_grid(pos)
else:
var cellsLastRow: int = int ((boardSize.x * boardSize.y) - boardSize.x)
idx = int(cellsLastRow + pos.y + (pos.x * boardSize.y))
return get_line(idx)
func get_lines_by_grid(grid: Vector2) -> Array:
var ret: Array = []
if grid.y >= 0:
ret.append(get_line_by_grid(grid, false))
if grid.x >= 0:
ret.append(get_line_by_grid(grid, true))
ret.append(get_line_by_grid(grid + Vector2(0,1),false))
ret.append(get_line_by_grid(grid + Vector2(1,0),true))
return ret
class CellAccessor:
var gameScene: GameScene
var idx: int
func get_state(real: bool = true): # NOTE: duplicated
if real:
return gameScene.reality
else:
return gameScene.simulate
func get_owner(real: bool = true) -> int:
return get_state(real).cellOwners[idx]
func set_owner(owner: int, real: bool = true):
get_state(real).cellOwners[idx] = owner
func get_grid() -> Vector2:
var col: int = idx % int(gameScene.boardSize.x)
var row: int = idx / int(gameScene.boardSize.x)
return Vector2(col,row)
func get_pos() -> Vector2:
return get_grid() * 75
class LineAccessor:
var gameScene: GameScene
var idx: int
func get_state(real: bool = true): # NOTE: duplicated
if real:
return gameScene.reality
else:
return gameScene.simulate
func get_owner(real: bool = true) -> int:
return get_state(real).lineOwners[idx]
func set_owner(owner: int, real: bool = true):
get_state(real).lineOwners[idx] = owner
func get_cellIdx() -> int:
var cellsLastRow: int = int ((gameScene.boardSize.x * gameScene.boardSize.y) - gameScene.boardSize.x)
if idx < cellsLastRow:
return idx
else:
var ln: int = idx - cellsLastRow
var row: int = ln % int(gameScene.boardSize.y)
var col: int = ln / int(gameScene.boardSize.y)
return (row * int(gameScene.boardSize.x)) + col
func get_horizontal() -> bool:
var cellsLastRow: int = int ((gameScene.boardSize.x * gameScene.boardSize.y) - gameScene.boardSize.x)
return idx <= cellsLastRow
func get_point0() -> Vector2:
return (get_grid0() * 75) + Vector2(85,85)
func get_point1() -> Vector2:
return (get_grid1() * 75) + Vector2(85,85)
func get_grid0() -> Vector2:
var grid1: Vector2 = get_grid1()
if get_horizontal():
return grid1 - Vector2(1,0)
else:
return grid1 - Vector2(0,1)
func get_grid1() -> Vector2:
# NOTE: duplicated
var cellIdx: int = get_cellIdx()
var col: int = cellIdx % int(gameScene.boardSize.x)
var row: int = cellIdx / int(gameScene.boardSize.x)
return Vector2(col,row)
func get_grid_other_end(grid: Vector2):
if grid == get_grid0():
return get_grid1()
elif grid == get_grid1():
return get_grid0()
else:
assert(false)
func get_neighbours() -> Array:
var ret: Array = []
for line in gameScene.get_lines_by_grid(get_grid0()):
ret.append(line)
for line in gameScene.get_lines_by_grid(get_grid1()):
ret.append(line)
ret.remove(ret.find(self))
return ret
func _to_string() -> String:
return "Line %d" % [idx]