Compare commits

...

10 Commits

2 changed files with 153 additions and 1 deletions

View File

@ -0,0 +1,150 @@
<script lang="js">
import { createData } from '$lib/createData';
import { scaleData } from '$lib/scaleData';
import { error } from '@sveltejs/kit';
import { onMount } from 'svelte';
// Constants / Parameters
const FPS = 20;
const AMOUNT = 100;
// System variables
const data = scaleData(createData(AMOUNT));
/** @type {HTMLCanvasElement} */
let canvas;
/** @type {CanvasRenderingContext2D} */
let context;
/** @type {number} */
let width;
/** @type {number} */
let interv;
onMount(() => {
// Initialize the canvas dimensions
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Try getting 2D context
const ctx = canvas.getContext('2d');
if (!ctx) error(417, 'Canvas not supported');
// Initialize global variables
context = ctx;
width = canvas.width / AMOUNT;
// Start continuous animation
interv = setInterval(animate, 1000 / FPS);
// Assign first job over the entire array
queue.push(new Job(data, 0, data.length));
});
/** @type {Job[]} */
let queue = [];
/** Response type for the quicksort algorithm */
class Response {
/**
* @param {boolean} done
* @param {number|null} index
* @param {number|null} start
* @param {number|null} end
*/
constructor(done, index, start, end) {
this.done = done;
this.index = index;
this.start = start;
this.end = end;
}
/**
* Generates follow up jobs from response.
* @param {number[]} array
* @returns {Job[]}
*/
generate(array) {
if (this.done) return [];
return [
new Job(array, this.start ?? 0, this.index ?? 0),
new Job(array, this.index ?? 0 + 1, this.end ?? 0)
];
}
}
/** Represent a call to the quicksort algorithm. */
class Job {
/**
* @param {number[]} array
* @param {number} start
* @param {number} end
*/
constructor(array, start, end) {
this.array = array;
this.start = start;
this.end = end;
this.pivot = array[end - 1];
this.index = start;
this.compr = start;
}
/**
* @returns {Response|void}
*/
step() {
// Base case, end condition
if (this.start >= this.end - 1 || this.start < 0) return new Response(true, null, null, null);
// Comparator reached end of range, swap pivot
if (this.compr >= this.end - 1) {
[this.array[this.index], this.array[this.end - 1]] = [
this.array[this.end - 1],
this.array[this.index]
];
return new Response(false, this.index, this.start, this.end);
}
// Compare with pivot to split range in two
if (this.array[this.compr] <= this.pivot) {
[this.array[this.index], this.array[this.compr]] = [
this.array[this.compr],
this.array[this.index]
];
this.index++;
}
this.compr++;
}
}
/** Render a single frame of the sorting algorithm at a time on the canvas. */
function animate() {
// Clear canvas with black background
context.fillStyle = 'black';
context.fillRect(0, 0, canvas.width, canvas.height);
// Display datapoints as lines
context.fillStyle = 'white';
data.forEach((d, i) => {
let color = 'white';
// Try chosing color based on all job indecies
queue.forEach((q) => {
const { index, compr } = q;
if (i === index) color = 'red';
else if (i === compr) color = 'lime';
});
// Display datapoint with chosen color
context.fillStyle = color;
context.fillRect(i * width, canvas.height, width - 1, -d * canvas.height);
});
// Step job and handle result
const result = queue[0].step();
if (result) {
queue.shift();
if (!result.done) queue.push(...result.generate(data));
}
}
</script>
<canvas bind:this={canvas} class="fixed top-0 left-0" />

View File

@ -16,6 +16,8 @@
let context;
/** @type {number} */
let width;
/** @type {number} */
let interv;
onMount(() => {
// Initialize the canvas dimensions
canvas.width = window.innerWidth;
@ -30,7 +32,7 @@
width = canvas.width / AMOUNT;
// Start continuous animation
setInterval(animate, 1000 / FPS);
interv = setInterval(animate, 1000 / FPS);
});
/** Render a single frame of the sorting algorithm at a time on the canvas. */