Skip to content
Snippets Groups Projects
Commit 5a248ba0 authored by Brady James Garvin's avatar Brady James Garvin
Browse files

Initial commit.

parents
Branches main
No related tags found
No related merge requests found
Showing
with 874 additions and 0 deletions
# Disable line-ending conversions for this repository.
* -text
# dependencies
/node_modules
# testing
/coverage
# production
/build
# environments
.env.local
.env.development.local
.env.test.local
.env.production.local
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# misc
*~
.DS_Store
[submodule "stylelint-config"]
path = stylelint-config
url = git@git.unl.edu:soft-core/soft-260/stylelint-config.git
[submodule "eslint-config"]
path = eslint-config
url = git@git.unl.edu:soft-core/soft-260/eslint-config.git
Subproject commit a85278e2bd62f637800bc32fa6b372bc2855546e
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.eol": "LF",
"files.exclude": {
"**/node_modules": true
},
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true
}
}
# dependencies
/node_modules
# testing
/coverage
# production
/build
# environments
.env.local
.env.development.local
.env.test.local
.env.production.local
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# misc
*~
.DS_Store
This diff is collapsed.
{
"name": "@unlsoft/greedy-algorithms",
"version": "1.0.0",
"description": "Starter code for the lab on greedy algorithms.",
"private": true,
"license": "UNLICENSED",
"scripts": {
"lint:css": "stylelint \"**/*.css\" \"**/*.module.css\" \"!coverage/**\"",
"lint:js": "eslint --max-warnings 0 ./src",
"lint": "run-s --continue-on-error lint:**",
"test-once": "react-scripts test --watchAll=false --coverage",
"test": "react-scripts test --watchAll --coverage",
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject"
},
"homepage": ".",
"dependencies": {
"@reduxjs/toolkit": "^1.8.3",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.3.0",
"classnames": "^2.3.1",
"npm-run-all": "^4.1.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.2",
"react-router-dom": "^6.3.0",
"react-scripts": "^5.0.1",
"workbox-background-sync": "^6.5.3",
"workbox-broadcast-update": "^6.5.3",
"workbox-cacheable-response": "^6.5.3",
"workbox-core": "^6.5.3",
"workbox-expiration": "^6.5.3",
"workbox-google-analytics": "^6.5.3",
"workbox-navigation-preload": "^6.5.3",
"workbox-precaching": "^6.5.3",
"workbox-range-requests": "^6.5.3",
"workbox-routing": "^6.5.3",
"workbox-strategies": "^6.5.3",
"workbox-streams": "^6.5.3"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@unlsoft/eslint-config": "file:../eslint-config",
"@unlsoft/stylelint-config": "file:../stylelint-config",
"eslint-plugin-jest-dom": "^4.0.2",
"stylelint": "^14.9.1"
},
"stylelint": {
"extends": "@unlsoft/stylelint-config"
},
"eslintConfig": {
"extends": [
"react-app",
"@unlsoft/eslint-config/react"
]
},
"jest": {
"clearMocks": true,
"collectCoverageFrom": [
"src/features/**/*.js"
],
"resetMocks": false,
"restoreMocks": false
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<meta
name="description"
content="Starter code for the lab on greedy algorithms."
/>
<meta name="theme-color" content="#d00000" />
<link rel="icon" href="%PUBLIC_URL%/logo.png" />
<link rel="icon" href="%PUBLIC_URL%/logo.svg" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.svg" />
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/logo.png" />
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/logo.svg" />
<title>Greedy Algorithms Lab</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
greedy-algorithms/public/logo.png

9.58 KiB

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 152 152">
<rect x="0" y="0" width="152" height="152" fill="rgba(0 0 0 / 100%)" />
<path d="M147,1H90V42h10V75.673L53.532,2.393,52.648,1H2V42H12v66H2v41H62V108H52V74.336l46.467,73.271L99.351,149H150V108H140V42h10V1Z" stroke-width="3" stroke="rgba(255 255 255 / 100%)" fill="rgba(208 0 0 / 100%)">
</path>
</svg>
{
"short_name": "Greedy Algorithms",
"name": "Greedy Algorithms Lab",
"description": "Starter code for the lab on greedy algorithms.",
"icons": [
{
"src": "logo.svg",
"type": "image/svg+xml",
"sizes": "192x192 512x512",
"purpose": "any maskable"
},
{
"src": "logo.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "any maskable"
}
],
"start_url": ".",
"display": "standalone",
"orientation": "portrait",
"theme_color": "#d00000",
"background_color": "#ffffff"
}
import { Routes, Route } from 'react-router-dom';
import { Solution } from './features/electrical/solution.js';
export function App() {
const page =
<>
<h1>Electrical Lines Problem</h1>
<Solution />
</>;
return (
<Routes>
<Route path={'/*'} element={page} />
</Routes>
);
}
export class PriorityQueue {
constructor() {
this._vertices = [];
}
get size() {
return this._vertices.length;
}
insert(element, measure) {
let index = this._vertices.length;
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this._vertices[parentIndex];
if (parent.measure < measure) {
break;
}
this._vertices[index] = parent;
index = parentIndex;
}
this._vertices[index] = {
element,
measure,
};
}
remove() {
console.assert(this._vertices.length > 0, 'Cannot remove an element from an empty priority queue');
const result = this._vertices[0].element;
const vertex = this._vertices[this._vertices.length - 1];
for (let index = 0; ;) {
this._vertices[index] = vertex;
let swapIndex = index;
for (const candidateIndex of [2 * index + 1, 2 * index + 2]) {
if (candidateIndex < this._vertices.length - 1 &&
this._vertices[candidateIndex].measure < this._vertices[swapIndex].measure) {
swapIndex = candidateIndex;
}
}
if (swapIndex === index) {
this._vertices[index] = vertex;
this._vertices.pop();
return result;
}
this._vertices[index] = this._vertices[swapIndex];
index = swapIndex;
}
}
}
import { Building, planElectricalLines } from './solver.js';
import styles from './solution.module.css';
const WIDTH = 20;
const HEIGHT = 30;
const COUNT = 100;
function generateRandomBuildings() {
const pool = [];
for (let x = 0; x < WIDTH; ++x) {
for (let y = 0; y < HEIGHT; ++y) {
pool.push(new Building(x, y));
}
}
const results = [];
for (let i = 0; i < COUNT; ++i) {
results.push(...pool.splice(Math.floor(Math.random() * pool.length), 1));
}
return results;
}
const BUILDINGS = generateRandomBuildings();
export function Solution() {
const lines = planElectricalLines(BUILDINGS).map((line, index) =>
<line
key={index}
stroke={'rgba(0, 0, 255, 1)'}
strokeWidth={0.2}
x1={line.firstBuilding.x}
y1={line.firstBuilding.y}
x2={line.secondBuilding.x}
y2={line.secondBuilding.y} />,
);
const buildings = BUILDINGS.map((building, index) =>
<circle key={index} fill={'rgba(0, 0, 0, 1)'} cx={building.x} cy={building.y} r={0.3} />,
);
return (
<svg xmlns={'http://www.w3.org/2000/svg'} viewBox={`-1 -1 ${WIDTH + 1} ${HEIGHT + 1}`} className={styles.map}>
{lines}
{buildings}
</svg>
);
}
.map {
width: 100%;
}
export class Building {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ElectricalLine {
constructor(firstBuilding, secondBuilding) {
this.firstBuilding = firstBuilding;
this.secondBuilding = secondBuilding;
}
get length() {
const dx = this.firstBuilding.x - this.secondBuilding.x;
const dy = this.firstBuilding.y - this.secondBuilding.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
export function planElectricalLines(buildings) {
return []; // TODO: stub
}
import { Building, planElectricalLines } from './solver.js';
function buildingsByCoordinates(firstBuilding, secondBuilding) {
if (firstBuilding.x !== secondBuilding.x) {
return firstBuilding.x - secondBuilding.x;
}
return firstBuilding.y - secondBuilding.y;
}
function linesByCoordinates([firstBuilding, secondBuilding], [firstOtherBuilding, secondOtherBuilding]) {
const candidate = buildingsByCoordinates(firstBuilding, firstOtherBuilding);
if (candidate !== 0) {
return candidate;
}
return buildingsByCoordinates(secondBuilding, secondOtherBuilding);
}
function canonicalizeNetwork(network) {
return network.map(
(line) => [line.firstBuilding, line.secondBuilding].sort(buildingsByCoordinates),
).sort(linesByCoordinates);
}
describe('planElectricalLines minimizes cable length', () => {
test('when there are no buildings', () => {
expect(canonicalizeNetwork(planElectricalLines([]))).toEqual([]);
});
test('when there is one building', () => {
const a = new Building(0, 0);
expect(canonicalizeNetwork(planElectricalLines([
a,
]))).toEqual([]);
});
test('when there are two buildings', () => {
const a = new Building(0, 0);
const b = new Building(0, 1);
expect(canonicalizeNetwork(planElectricalLines([
a, b,
]))).toEqual([
[a, b],
]);
});
test('when there are three buildings', () => {
const a = new Building(0, 0);
const b = new Building(0, 1);
const c = new Building(1, 0);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c,
]))).toEqual([
[a, b],
[a, c],
]);
});
test('when there are four buildings with none isolated', () => {
const a = new Building(0, 0);
const b = new Building(0, 1);
const c = new Building(4, 0);
const d = new Building(5, 1);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d,
]))).toEqual([
[a, b],
[a, c],
[c, d],
]);
});
test('when there are four buildings with one isolated', () => {
const a = new Building(0, 0);
const b = new Building(0, 1);
const c = new Building(4, 0);
const d = new Building(3, 5);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d,
]))).toEqual([
[a, b],
[a, c],
[b, d],
]);
});
test('on random imput #0', () => {
const a = new Building(0, 4);
const b = new Building(1, 5);
const c = new Building(2, 7);
const d = new Building(5, 8);
const e = new Building(7, 3);
const f = new Building(8, 8);
const g = new Building(8, 9);
const h = new Building(9, 1);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h,
]))).toEqual([
[a, b],
[b, c],
[c, d],
[d, f],
[e, f],
[e, h],
[f, g],
]);
});
test('on random imput #1', () => {
const a = new Building(0, 8);
const b = new Building(1, 0);
const c = new Building(1, 3);
const d = new Building(4, 7);
const e = new Building(5, 5);
const f = new Building(5, 6);
const g = new Building(7, 3);
const h = new Building(8, 8);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h,
]))).toEqual([
[a, d],
[b, c],
[c, e],
[d, f],
[e, f],
[e, g],
[f, h],
]);
});
test('on random imput #2', () => {
const a = new Building(0, 2);
const b = new Building(0, 4);
const c = new Building(1, 0);
const d = new Building(1, 4);
const e = new Building(5, 8);
const f = new Building(6, 5);
const g = new Building(7, 6);
const h = new Building(8, 2);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h,
]))).toEqual([
[a, b],
[a, c],
[b, d],
[d, f],
[e, g],
[f, g],
[f, h],
]);
});
test('on random imput #3', () => {
const a = new Building(3, 3);
const b = new Building(4, 0);
const c = new Building(4, 5);
const d = new Building(5, 9);
const e = new Building(7, 2);
const f = new Building(7, 9);
const g = new Building(8, 1);
const h = new Building(9, 4);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h,
]))).toEqual([
[a, b],
[a, c],
[b, e],
[c, d],
[d, f],
[e, g],
[e, h],
]);
});
test('on random imput #4', () => {
const a = new Building(0, 7);
const b = new Building(2, 1);
const c = new Building(3, 6);
const d = new Building(4, 7);
const e = new Building(6, 0);
const f = new Building(8, 5);
const g = new Building(9, 2);
const h = new Building(9, 3);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h,
]))).toEqual([
[a, c],
[b, e],
[c, d],
[d, f],
[e, g],
[f, h],
[g, h],
]);
});
test('on random imput #5', () => {
const a = new Building(0, 18);
const b = new Building(1, 15);
const c = new Building(2, 1);
const d = new Building(3, 8);
const e = new Building(4, 4);
const f = new Building(7, 10);
const g = new Building(11, 19);
const h = new Building(12, 1);
const i = new Building(13, 16);
const j = new Building(13, 19);
const k = new Building(15, 7);
const l = new Building(15, 13);
const m = new Building(15, 14);
const n = new Building(16, 12);
const o = new Building(17, 1);
const p = new Building(17, 19);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p,
]))).toEqual([
[a, b],
[b, d],
[c, e],
[d, e],
[d, f],
[f, i],
[g, j],
[h, o],
[i, j],
[i, m],
[j, p],
[k, n],
[k, o],
[l, m],
[l, n],
]);
});
test('on random imput #6', () => {
const a = new Building(0, 4);
const b = new Building(1, 17);
const c = new Building(3, 4);
const d = new Building(4, 4);
const e = new Building(4, 8);
const f = new Building(5, 19);
const g = new Building(6, 0);
const h = new Building(6, 2);
const i = new Building(8, 11);
const j = new Building(13, 15);
const k = new Building(15, 11);
const l = new Building(15, 18);
const m = new Building(17, 4);
const n = new Building(17, 12);
const o = new Building(18, 15);
const p = new Building(19, 16);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p,
]))).toEqual([
[a, c],
[b, f],
[c, d],
[d, e],
[d, h],
[e, i],
[f, i],
[g, h],
[i, j],
[j, l],
[k, m],
[k, n],
[l, o],
[n, o],
[o, p],
]);
});
test('on random imput #7', () => {
const a = new Building(0, 12);
const b = new Building(0, 18);
const c = new Building(1, 7);
const d = new Building(3, 0);
const e = new Building(3, 7);
const f = new Building(6, 0);
const g = new Building(7, 14);
const h = new Building(7, 19);
const i = new Building(9, 18);
const j = new Building(10, 3);
const k = new Building(13, 10);
const l = new Building(13, 18);
const m = new Building(15, 0);
const n = new Building(16, 9);
const o = new Building(17, 5);
const p = new Building(18, 6);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p,
]))).toEqual([
[a, b],
[a, c],
[b, h],
[c, e],
[d, e],
[d, f],
[f, j],
[g, i],
[h, i],
[i, l],
[j, m],
[k, n],
[m, o],
[n, p],
[o, p],
]);
});
test('on random imput #8', () => {
const a = new Building(0, 19);
const b = new Building(3, 14);
const c = new Building(4, 6);
const d = new Building(5, 10);
const e = new Building(7, 18);
const f = new Building(8, 17);
const g = new Building(10, 17);
const h = new Building(10, 18);
const i = new Building(12, 1);
const j = new Building(14, 3);
const k = new Building(14, 11);
const l = new Building(16, 0);
const m = new Building(16, 12);
const n = new Building(18, 18);
const o = new Building(19, 1);
const p = new Building(19, 4);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p,
]))).toEqual([
[a, b],
[b, d],
[b, e],
[c, d],
[e, f],
[f, g],
[g, h],
[g, k],
[i, j],
[j, k],
[j, l],
[k, m],
[l, o],
[m, n],
[o, p],
]);
});
test('on random imput #9', () => {
const a = new Building(0, 7);
const b = new Building(1, 0);
const c = new Building(1, 9);
const d = new Building(4, 3);
const e = new Building(4, 6);
const f = new Building(6, 13);
const g = new Building(6, 15);
const h = new Building(7, 5);
const i = new Building(7, 15);
const j = new Building(8, 16);
const k = new Building(12, 4);
const l = new Building(12, 11);
const m = new Building(17, 14);
const n = new Building(17, 19);
const o = new Building(19, 5);
const p = new Building(19, 12);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p,
]))).toEqual([
[a, c],
[a, e],
[b, d],
[c, f],
[d, e],
[e, h],
[f, g],
[f, l],
[g, i],
[h, k],
[i, j],
[l, m],
[m, n],
[m, p],
[o, p],
]);
});
test('on random imput #10', () => {
const a = new Building(0, 2);
const b = new Building(0, 15);
const c = new Building(1, 11);
const d = new Building(1, 23);
const e = new Building(4, 9);
const f = new Building(4, 29);
const g = new Building(6, 21);
const h = new Building(7, 9);
const i = new Building(8, 15);
const j = new Building(11, 24);
const k = new Building(14, 2);
const l = new Building(16, 13);
const m = new Building(17, 12);
const n = new Building(18, 24);
const o = new Building(19, 1);
const p = new Building(20, 25);
const q = new Building(21, 12);
const r = new Building(23, 24);
const s = new Building(24, 24);
const t = new Building(28, 20);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t,
]))).toEqual([
[a, e],
[b, c],
[c, e],
[d, f],
[d, g],
[e, h],
[g, i],
[g, j],
[h, i],
[h, k],
[i, l],
[j, n],
[k, o],
[l, m],
[m, q],
[n, p],
[p, r],
[r, s],
[s, t],
]);
});
test('on random imput #11', () => {
const a = new Building(0, 21);
const b = new Building(1, 27);
const c = new Building(2, 15);
const d = new Building(3, 2);
const e = new Building(3, 18);
const f = new Building(10, 18);
const g = new Building(11, 10);
const h = new Building(13, 13);
const i = new Building(13, 27);
const j = new Building(19, 1);
const k = new Building(19, 11);
const l = new Building(21, 1);
const m = new Building(21, 2);
const n = new Building(21, 16);
const o = new Building(22, 3);
const p = new Building(22, 21);
const q = new Building(24, 4);
const r = new Building(25, 8);
const s = new Building(25, 12);
const t = new Building(29, 26);
expect(canonicalizeNetwork(planElectricalLines([
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t,
]))).toEqual([
[a, b],
[a, e],
[c, e],
[d, g],
[e, f],
[f, h],
[f, i],
[g, h],
[h, k],
[j, l],
[k, n],
[l, m],
[m, o],
[n, p],
[n, s],
[o, q],
[p, t],
[q, r],
[r, s],
]);
});
});
export class UnionFind {
constructor() {
this.lastUsedRepresentatives = new Map();
}
_representative(vertex, newRepresentative = undefined) {
console.assert(
newRepresentative === undefined || this.lastUsedRepresentatives.get(newRepresentative) === newRepresentative,
`Attempted to set the representative of ${vertex} to ${newRepresentative}, which is not a representative.`,
);
const path = [];
let current = vertex;
for (;;) {
path.push(current);
const candidate = this.lastUsedRepresentatives.get(current);
if (candidate === current || candidate === undefined) {
break;
}
current = candidate;
}
const representative = newRepresentative !== undefined ? newRepresentative : current;
for (const toUpdate of path) {
this.lastUsedRepresentatives.set(toUpdate, representative);
}
return representative;
}
connect(firstVertex, secondVertex) {
this._representative(secondVertex, this._representative(firstVertex));
}
areConnected(firstVertex, secondVertex) {
return this._representative(firstVertex) === this._representative(secondVertex);
}
}
:root {
/* Colors */
--letterbox-color: rgba(0 0 0 / 100%);
--app-background-color: rgba(239 239 239 / 100%);
--font-color: rgba(0 0 0 / 100%);
/* Sizes */
--minimum-app-size: 300px;
}
body {
margin: 0;
font-family: sans-serif;
text-align: center;
color: var(--font-color);
}
#root {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: var(--letterbox-color);
}
#portrait {
position: relative;
box-sizing: border-box;
margin: auto;
padding: 1em;
min-width: var(--minimum-app-size);
min-height: var(--minimum-app-size);
width: 100%;
height: 100%;
max-width: 62.5vh;
background: var(--app-background-color);
overflow-x: hidden;
overflow-y: scroll;
transform: scale(1);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment