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>
    </td>
  </tr>
  <tr>
    <td>
      <label>Input size: <input type="text" id="chal-size" style="width: 3em" value="10"></label>
      <br>
      <button id="gen-challenge">
        Generate!
      </button>
      <button id="vis-challenge">
        Visualise!
      </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>
    </td>
  </tr>
</table>

CSS

#visualisation {
  background-color: white;
}

JavaScript

function generateSolution() {
	var inputText = document.getElementById('chal-size');
	var inputSize = parseInt(inputText.value);
  if(isNaN(inputSize) || inputSize % 2 === 1) {
  	alert('Invalid input size, please enter an even number.');
  }
  
  var outputText = '' + inputSize;
  for(var i = 0; i < inputSize; i++) {
  	outputText += '\n' + Math.round(100000 * Math.random()) / 100000
                + ' ' + Math.round(100000 * Math.random()) / 100000;
  }
  
  return outputText;
}

function validateSolution(input, output) {
  var count  = 0;
  for(var i = 0; i < input.length; i++) {
  	var p = input[i];
    var dx = p.x - output.x, dy = p.y - output.y;
    var d2 = dx * dx + dy * dy;
    if(d2 - output.r * output.r < 0.000000001) {
    	count += 1;
    }
  }
  
  if(count * 2 === input.length) {
  	alert('Valid!');
  } else {
  	alert('' + count + '/' + input.length + ' points inside circle (should be ' + input.length / 2 + ')');
  }
}

function getInput() {
	var text = document.getElementById('chal-input').value;
  var lines = text.split('\n');
  var input = [];
  for(var i = 1; i < lines.length; i++) {
  	var line = lines[i].split(' ');
    input.push({
    	x: parseFloat(line[0]),
      y: parseFloat(line[1])
    });
  }
  return input;
}

function renderInput(input) {
	var c = document.getElementById('visualisation').getContext('2d');
  c.clearRect(0, 0, 200, 200);
  c.fillStyle = 'red';
  for(var i = 0; i < input.length; i++) {
  	var p = input[i];
    var x = p.x * 200;
    var y = (1 - p.y) * 200;
    c.fillRect(x - 0.5, y - 0.5, 2, 2);
  }
}

function getOutput() {
	var text = document.getElementById('chal-output').value;
  var lines = text.split('\n');
  var pos = lines[0].split(' ');
  return {
  	x: parseFloat(pos[0]),
    y: parseFloat(pos[1]),
    r: parseFloat(lines[1])
  };
}

function renderOutput(output) {
	var c = document.getElementById('visualisation').getContext('2d');
  c.strokeStyle = 'green';
  c.beginPath();
  var x = output.x * 200;
 ...