JSFiddle - React, Tailwind, and code Playground
HTML
<table>
<tr>
<td>
Challenge input - write this yourself or generate below
<br>
<textarea id="chal-input" rows="20" cols="30"></textarea>
</td>
<td>
<canvas id="visualisation" width="200" height="200">
</canvas>
<div id="result"></div>
</td>
</tr>
<tr>
<td>
<label>Input size: <input type="text" id="chal-size" style="width: 3em" value="100"></label>
<br>
<button id="gen-challenge">
Generate!
</button>
<button id="vis-challenge">
Visualise!
</button>
<button id="solve-challenge">
Solve!
</button>
</td>
<td>
Challenge output - enter your generated solution
<br>
<textarea id="chal-output" rows="3" cols="30"></textarea>
<br>
<button id="validate-solution">
Validate!
</button>
<button id="vis-solution">
Visualise!
</button>
<button id="rand-solution">
Random circle!
</button>
</td>
</tr>
</table>
CSS
#visualisation {
background-color: white;
}
JavaScript
var print = console.log
function Point(x, y) {
this.x = x
this.y = y
}
Point.prototype.distSq = function(b) {
let a = this
return Math.pow(a.x-b.x,2) + Math.pow(a.y-b.y,2)
}
Point.prototype.dist = function(b) {
return Math.sqrt(this.distSq(b))
}
function Circle(x, y, r) {
this.p = new Point(x,y)
this.r = r
this.r2 = r*r
}
Circle.prototype.show = function() {
return `${this.p.x} ${this.p.y}\n${this.r}`
}
Circle.random = function() {
let r = Math.random()*0.5
let x = r+Math.random()*(1-2*r)
let y = r+Math.random()*(1-2*r)
return new Circle(x,y,r)
}
Circle.prototype.clone = function() {
let c = new Circle(this.p.x, this.p.y, this.r)
c.r2 = this.r2
c.inside = this.inside
c.lastScore = this.lastScore
return c
}
Circle.prototype.mutate = function() {
let c = this.clone()
c.r += 0.7*Math.random()*(0.5-c.r)
c.p.x += 0.5*( (c.r-c.p.x) * Math.random()*(1-2*c.r) )
c.p.y += 0.5*( (c.r-c.p.y) * Math.random()*(1-2*c.r) )
c.r2 = c.r*c.r
return c
}
// print(Circle.random().show())
Circle.prototype.score = function(points) {
let inside = 0
for(let p of points)
if( this.p.distSq(p) <= this.r2 )
inside++
this.inside = inside
this.lastScore = Math.abs(inside/points.length - 0.5)
+ this.r
return this.lastScore
}
var popSize = 100
var topSize = parseInt(popSize/4)
var iterations = 1000
function solve(points) {
let population = []
for(let i=0; i < popSize; i++)
population.push(Circle.random())
best = {score: 1}
for(let it=0; it < iterations; it++) {
for(let c of population)
c.score(points)
_population = population.sort((a,b)=>a.lastScore-b.lastScore)
if(_population[0].lastScore < best.score)
best = _population[0].clone()
population = []
for(let i=0; i < topSize; i++) {
population.push(_population[i].mutate())
population.push(_population[i].mutate())
population.push(_population[i].mutate())
}
while(population.length < popSize)
population.push(Circle.random())
}
return best
}
function parseInput(input)...