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]