Skip to content

Commit

Permalink
Merge pull request #717 from devsoc-unsw/master-sorting
Browse files Browse the repository at this point in the history
unstable sorting added
  • Loading branch information
allleeeex authored Sep 22, 2024
2 parents 9a1fab9 + 8b51944 commit 6dd8f9d
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 9 deletions.
50 changes: 50 additions & 0 deletions client/src/visualiser-src/common/RandomNumGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,53 @@ export const generateNumbers = () => {
set.forEach((num) => result.push(num));
return result;
};

// generates a random list of sorting numbers
// min and max represent the range of total nodes to be be created
export const generateSortingNumbers = () => {
const result = [];
const min = 8;
const max = 12;
const totalNodes = Math.floor(Math.random() * (max - min + 1) + min);
// Choose an index between 0 and 2 to be selected for duplication
const dupeIndex = Math.floor(Math.random() * 3);
// Choose either 3 or 4 numbers to be duplicated
const dupeCount = Math.floor(Math.random() * 2) + 3;
// Storing all the indices that will have duplicated values in result array
const dupedIndices = [];
for (let i = 0; i < dupeCount; i++) {
// Produce random number in range [dupeIndex + 1, totalNodes - 1] inclusive
const randomNumber = dupeIndex + 1 + Math.floor(Math.random() * (totalNodes - dupeIndex - 1));
// If the random index was already generated, regenerate
if (dupedIndices.includes(randomNumber)) {
i--;
} else {
dupedIndices.push(randomNumber);
}
}
for (let i = 0; i < totalNodes; i += 1) {
// 90% of the time we generate a new value.
// 10% chance to randomly choose some existing value in the array to be
// duplicated, that is not the value that is already chosen to be
// duplicated 3-4 times.
const willGenerateNewVal = Math.random() < 0.9;

if (dupedIndices.includes(result.length)) {
result.push(result[dupeIndex]);
} else if (result.length === 0 || willGenerateNewVal) {
const num = Math.ceil(Math.random() * 99);
result.push(num);
} else {
// Duplicate a random value from the array, that is not the value
// that is already chosen to be duplicated 3-4 times.
let randomIndex = dupeIndex;
while (result[randomIndex] === result[dupeIndex]) {
randomIndex = Math.floor(Math.random() * result.length);
// Break loop if only value in array is the duplicated value
if (result.every((val) => val === result[dupeIndex])) break;
}
result.push(result[randomIndex]);
}
}
return result;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Documentation } from 'visualiser-src/common/typedefs';
import GraphicalDataStructure from 'visualiser-src/common/GraphicalDataStructure';
import { injectIds } from 'visualiser-src/common/helpers';
import { CANVAS } from 'visualiser-src/linked-list-visualiser/util/constants';
import { generateNumbers } from 'visualiser-src/common/RandomNumGenerator';
import { generateSortingNumbers } from 'visualiser-src/common/RandomNumGenerator';
import GraphicalSortsElement from './GraphicalSortsElement';
import SortsBubbleAnimationProducer from '../animation-producer/SortsBubbleAnimationProducer';
import SortsMergeAnimationProducer from '../animation-producer/SortsMergeAnimationProducer';
Expand All @@ -19,6 +19,7 @@ import {
selectedColor,
redColour,
} from '../util/constants';
import { countOccurences, letterMap } from '../util/helpers';

export default class GraphicalSortList extends GraphicalDataStructure {
public elementList: GraphicalSortsElement[] = [];
Expand Down Expand Up @@ -67,22 +68,37 @@ export default class GraphicalSortList extends GraphicalDataStructure {
public append(values: number[]): AnimationProducer {
const producer = new SortsCreateAnimationProducer();
values.forEach((value) => {
const element = GraphicalSortsElement.from(value);
producer.addBlock(value, this.elementList.length, element);
const numbers = this.data;
const occurrences = countOccurences(numbers);
const numberCount = occurrences[value];
let element;
if (numberCount === undefined) {
element = GraphicalSortsElement.from(value, `${value}`);
producer.addBlock(value, this.elementList.length, element);
} else {
element = GraphicalSortsElement.from(value, `${value}${letterMap[numberCount - 1]}`);
producer.addBlock(value, this.elementList.length, element);
}
this.elementList.push(element);
});
return producer;
}

public delete(values: number[]): AnimationProducer {
const producer = new SortsCreateAnimationProducer();
const listValues = this.elementList
.map((element) => element.data.value)
.filter((x) => !values.includes(x));

const remainingElements = [...this.elementList];
values.forEach((value) => {
const index = remainingElements.findIndex((element) => element.data.value === value);
if (index !== -1) {
remainingElements.splice(index, 1);
}
});

// Clear the canvas, and re-insert the existing values in the list into the canvas
SVG(CANVAS).clear();
this.elementList = [];
const listValues = remainingElements.map((element) => element.data.value);
this.append(listValues);

return producer;
Expand Down Expand Up @@ -541,7 +557,7 @@ export default class GraphicalSortList extends GraphicalDataStructure {
}

public generate(): void {
const numbers = generateNumbers();
const numbers = generateSortingNumbers();
this.append(numbers);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface SVGData {

interface GraphicalSortsElementData {
value: number;
displayValue: string;
svgData: SVGData;
}

Expand All @@ -32,16 +33,17 @@ export default class GraphicalSortsElement {
return pointer;
}

public static from(input: number) {
public static from(input: number, displayInput: string) {
const canvas = SVG(`#${VISUALISER_CANVAS_ID}`) as Svg;
const blockShape = canvas
.rect()
.attr(shapeAttributes)
.width(boxWidth)
.height(Math.sqrt(input * 90));
const elementValue = canvas.text(String(input)).attr(textAttributes);
const elementValue = canvas.text(String(displayInput)).attr(textAttributes);
return new GraphicalSortsElement({
value: input,
displayValue: displayInput,
svgData: {
numberTarget: elementValue,
boxTarget: blockShape,
Expand Down
39 changes: 39 additions & 0 deletions client/src/visualiser-src/sorting-visualiser/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,42 @@ export function getCx(index): number {
export function getY(value): number {
return textCy - 10 - Math.sqrt(value * 90);
}

export const countOccurences = (arr: number[]): { [key: number]: number } => {
const counts: { [key: number]: number } = {};

arr.forEach((num) => {
counts[num] = counts[num] ? counts[num] + 1 : 1;
});

return counts;
};

export const letterMap = [
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
];

0 comments on commit 6dd8f9d

Please sign in to comment.