import Staging._
import math.pow,math.random
// Tangle based on Planarity
clear()
// ES sets difficulty level
val ES=4;val AS=ES*ES
val Ra=10
// Edge is a line between two nodes
case class EdgeP(n1:NodeP,n2:NodeP){
var e=line(n1.x,n1.y,n2.x,n2.y)
}
// edges is all the edges, initially empty
var edges=Vector[EdgeP]()
// Node is a circle which is dragable. Redraws edges when dragged
case class NodeP(var x:Double,var y:Double){
val n=circle(x,y,Ra)
n.setFillColor(blue)
def goTo(gx:Double,gy:Double){
x=gx ; y=gy
n.setPosition(gx,gy)
}
n.onMouseDrag{(mx, my) => {n.setPosition(mx, my);x=mx;y=my;drawEdges(edges)}}
}
// Create and link all nodes topologically in a square
val p=(0 until AS).foldLeft(Vector[NodeP]())((v,i)=>{v :+ NodeP(0,0)})
// Create all edges, link to adjacent nodes
edges=(0 until AS).foldLeft(Vector[EdgeP]())(
(ev,i)=>{
val x=i/ES; val y=i%ES
val te=if(y<ES-1) {ev :+ EdgeP(p(i),p(i+1))} else ev
if(x<ES-1) {te :+ EdgeP(p(i),p(i+ES))} else te
})
// draw all edges
putRand(p)
// Button for new game
val b=square(-ES*35,-ES*35, 20)
b.setFillColor(red)
b.onMouseClick { (x, y) =>putRand(p)}
// randomise node positions
def putRand(p:Vector[NodeP]){
p.foreach(tn=>tn.goTo(ES*Ra*6*(random - 0.5),ES*Ra*6*(random - 0.5)))
drawEdges(edges)
}
//draw edges between nodes and start line from circumference of circle
def drawEdges(ev:Vector[EdgeP]){
ev.foreach(te=>{
val x1=te.n1.x ; val y1=te.n1.y
val x2=te.n2.x ; val y2=te.n2.y
val len=sqrt(pow(x2-x1,2) + pow(y2-y1,2))
val xr=Ra/len*(x2-x1) ; val yr=Ra/len*(y2-y1)
te.e.erase;
te.e=line(x1+xr,y1+yr,x2-xr,y2-yr)
})
}