generated from Nekojimi/GodotTemplate
239 lines
7.0 KiB
GDScript
239 lines
7.0 KiB
GDScript
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]
|