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

Initial commit.

parents
Branches
No related tags found
No related merge requests found
# 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 "eslint-config"]
path = eslint-config
url = git@git.unl.edu:csce-310/eslint-config.git
# Tests-Only Starter Code
A minimal project to be used as starter code for Homework 3 in the 250 section
of the CSCE 310 course at UNL.
# Quick Start
Recursively clone this repository and `cd` into the root folder:
```
$ git clone --recursive git@git.unl.edu:csce-310/2021-fall-homework-3.git
$ cd 2021-fall-homework-3
```
(If you forget `--recursive` when cloning, you can `cd` into your clone and run
`git submodule update --init --recursive` instead.)
Install dependencies:
```
$ npm install
```
# Instructions
See <https://canvas.unl.edu/courses/114253/assignments/1102860>.
Subproject commit 24df42fb655d234b83c93b0fb24d012e4d9ecb58
{
"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/homework-3-implementation",
"version": "1.0.0",
"description": "A minimal project to be used as starter code for Homework 3.",
"type": "module",
"private": true,
"license": "UNLICENSED",
"scripts": {
"lint:js": "eslint --max-warnings 0 ./src",
"lint": "run-s --continue-on-error lint:**",
"test-once": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watchAll --coverage"
},
"dependencies": {
"npm-run-all": "^4.1.5"
},
"devDependencies": {
"@unlsoft/eslint-config": "file:../eslint-config",
"eslint": "^7.30.0",
"jest": "^27.0.6",
"jest-environment-node": "^27.0.6"
},
"eslintConfig": {
"extends": "@unlsoft"
},
"jest": {
"clearMocks": true,
"collectCoverageFrom": [
"src/**/*.js",
"!src/testing/**/*.js"
],
"resetMocks": false,
"restoreMocks": false,
"testEnvironment": "./src/testing/failFast.js",
"transform": {}
},
"//": [
"See https://github.com/facebook/jest/issues/9430 for information on Jest+ES6."
]
}
export class Pattern {
constructor(goal, behaviors) {
this.goal = goal;
this._behaviors = behaviors;
}
get duration() {
return this._behaviors.length;
}
matches(behaviors, endingIndex) {
if (endingIndex < this._behaviors.length) {
return false;
}
// eslint-disable-next-line no-sequences
for (let i = this._behaviors.length, j = endingIndex; j--, i--;) {
if (this._behaviors[i] !== behaviors[j]) {
return false;
}
}
return true;
}
}
// INSTRUCTIONS: Uncomment and implement this class.
// class Backpointer {
// constructor() {
// }
//
// toString() {
// return '…';
// }
// }
export function inferGoals(behaviors, patterns) {
// INSTRUCTIONS: In a goal-inference problem, a subject's behaviors are
// observed, and then the objective is to label those behaviors with the
// goal(s) that motivated them. For example, if the subject's behaviors are
// unpackaging a loaf of bread, removing two slices, retrieving various
// toppings out of a refrigerator, etc., then goal inference should be able to
// guess from these actions that the subject's goal is to make a sandwich.
//
// In this simplified version of the goal-inference problem, you may assume
// that:
//
// * The subject always pursues a goal using a known goal-specific behavioral
// pattern.
//
// * The subject never pursues more than one goal at a time.
//
// * The subject always completes one goal before moving on to the next.
//
// For the functional correctness points, complete this JavaScript function so
// that, given a sequence of behaviors and a collection of patterns, it
// returns a list of strings describing the subject's inferred goals in the
// format
//
// > [name of goal] for [duration] unit(s) of time
//
// where the string should be exactly
//
// > undefined for 1 unit(s) of time
//
// for every behavior that cannot be associated with goals. Your algorithm
// should always choose an explanation that minimizes the number of strings
// used in the explanation.
//
// For the performance points, use dynamic programming to minimize the
// asymptotic time and memory usage of your code. You will have to determine
// what DAG to use and design an appropriate backpointer class. Based on this
// design, you should implement a constructor and a `toString` method in the
// class above, and it is also a good idea to implement the logic to choose a
// backpointer in its own helper function. Furthermore, you will need to read
// and understand the logic in the `Pattern` class so that you can use its
// public fields and methods.
return [];
}
import { Pattern, inferGoals } from './goalInference.js';
describe('the inferGoals function', () => {
test('infers no goals when no behaviors are given', () => {
expect(inferGoals(
'',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
],
)).toEqual([]);
});
test('infers undefined goals when no patterns are given', () => {
expect(inferGoals(
'aabaab',
[],
)).toEqual([
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('infers undefined goals when no useful patterns are given', () => {
expect(inferGoals(
'aabaab',
[
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('infers a single goal when a pattern matches exactly once', () => {
expect(inferGoals(
'aa',
[
new Pattern('X', 'aa'),
],
)).toEqual([
'X for 2 unit(s) of time',
]);
});
test('infers a repeated goal when a pattern repeats', () => {
expect(inferGoals(
'aaaaaa',
[
new Pattern('X', 'aa'),
],
)).toEqual([
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
]);
});
test('infers defined goals where a pattern matches but undefined goals elsewhere', () => {
expect(inferGoals(
'aabaab',
[
new Pattern('X', 'aa'),
],
)).toEqual([
'X for 2 unit(s) of time',
'undefined for 1 unit(s) of time',
'X for 2 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('minimizes the number of inferred goals when not needing to infer undefined goals', () => {
expect(inferGoals(
'aabaab',
[
new Pattern('X', 'aa'),
new Pattern('Y', 'aab'),
],
)).toEqual([
'Y for 3 unit(s) of time',
'Y for 3 unit(s) of time',
]);
});
test('minimizes the number of inferred goals even when needing to infer undefined goals', () => {
expect(inferGoals(
'aabaab',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'X for 3 unit(s) of time',
'Y for 2 unit(s) of time',
]);
});
test('infers goals even when given extra useless patterns', () => {
expect(inferGoals(
'aabaab',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'X for 3 unit(s) of time',
'Y for 2 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 0', () => {
expect(inferGoals(
'bbaaaaaaaa',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 1', () => {
expect(inferGoals(
'abbabba',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'Y for 2 unit(s) of time',
'Z for 3 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 2', () => {
expect(inferGoals(
'babababa',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'Z for 3 unit(s) of time',
'Y for 2 unit(s) of time',
'X for 3 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 3', () => {
expect(inferGoals(
'aaaaabbab',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
'Y for 2 unit(s) of time',
'Z for 3 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 4', () => {
expect(inferGoals(
'bbabb',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'Z for 3 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 5', () => {
expect(inferGoals(
'bbbabbabbb',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'Z for 3 unit(s) of time',
'Z for 3 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 6', () => {
expect(inferGoals(
'aabaaa',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'X for 3 unit(s) of time',
'X for 2 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 7', () => {
expect(inferGoals(
'ababab',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'X for 3 unit(s) of time',
'Z for 3 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 8', () => {
expect(inferGoals(
'bbaaabbbaaab',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'X for 2 unit(s) of time',
'Y for 2 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'X for 2 unit(s) of time',
'Y for 2 unit(s) of time',
]);
});
test('infers goals in sample behaviors sequence 9', () => {
expect(inferGoals(
'aaaaababaabbbaababbbabbb',
[
new Pattern('X', 'aa'),
new Pattern('X', 'aba'),
new Pattern('Y', 'ab'),
new Pattern('Z', 'bab'),
],
)).toEqual([
'X for 2 unit(s) of time',
'X for 2 unit(s) of time',
'Y for 2 unit(s) of time',
'X for 3 unit(s) of time',
'Y for 2 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
'X for 2 unit(s) of time',
'Z for 3 unit(s) of time',
'undefined for 1 unit(s) of time',
'Z for 3 unit(s) of time',
'undefined for 1 unit(s) of time',
'undefined for 1 unit(s) of time',
]);
});
});
// INSTRUCTIONS: Uncomment and implement this class.
// class Backpointer {
// constructor() {
// }
// }
export function scheduleShifts(predictedCustomerCounts, targetCustomersPerShift) {
// INSTRUCTIONS: In this problem a retailer wants to divide their store's
// hours into work shifts so that an employee working one shift will see
// approximately the same number of customers as an employee working a
// different shift even though the number of customers shopping varies with
// the time of day.
//
// For the functional correctness points, complete this JavaScript function so
// that, given the retailer's forecasts for number of customers shopping each
// hour and the ideal number of customers for an employee to interact with
// during one shift, it returns a list of shift lengths, in whole hours, that
// come as close as possible to that ideal. You may assume that the
// unfairness of a shift is the squared difference between the forecast number
// of customers during the shift and the ideal number and that an ideal
// schedule is one minimizing the total unfairness.
//
// For the performance points, use dynamic programming to minimize the
// asymptotic time and memory usage of your code. You will have to determine
// what DAG to use and design an appropriate backpointer class. Based on your
// design, you should implement a constructor in the class above, and it is
// also a good idea to implement the logic to choose a backpointer in its own
// helper function.
return [];
}
/* eslint-disable no-magic-numbers */
import { scheduleShifts } from './scheduling.js';
describe('the scheduleShifts function', () => {
test('schedules no shifts if there are no business hours', () => {
expect(scheduleShifts([], 0)).toEqual([]);
});
test('scheduless minimum length shifts if the target customer count is zero', () => {
expect(scheduleShifts([1, 3, 2, 4, 6, 2, 1, 1], 0)).toEqual([1, 1, 1, 1, 1, 1, 1, 1]);
});
test('schedules one shift if the total expected business exactly matches the target for a shift', () => {
expect(scheduleShifts([1, 3, 2, 4, 6, 2, 1, 1], 20)).toEqual([8]);
});
test('schedules exact shifts if possible with level predictions', () => {
expect(scheduleShifts([4, 4, 4, 4, 4, 4, 4, 4], 8)).toEqual([2, 2, 2, 2]);
});
test('schedules exact shifts if possible with varying predictions', () => {
expect(scheduleShifts([4, 4, 1, 3, 3, 1, 4, 4], 8)).toEqual([2, 4, 2]);
});
test('schedules equally approximate shifts if possible with level predictions', () => {
expect(scheduleShifts([5, 5, 5, 5, 5, 5, 5, 5], 8)).toEqual([2, 2, 2, 2]);
});
test('schedules one shift if the total expected business is less than the target for a shift', () => {
expect(scheduleShifts([1, 3, 2, 4, 6, 2, 1, 1], 30)).toEqual([8]);
});
test('schedules one shift if the total expected business only slightly exceeds the target for a shift', () => {
expect(scheduleShifts([1, 3, 2, 4, 6, 2, 1, 1], 15)).toEqual([8]);
});
test('schedules two shifts if half the total expected business is close to the target for a shift', () => {
expect(scheduleShifts([1, 3, 2, 4, 6, 2, 1, 1], 13)).toEqual([4, 4]);
});
test('schedules longer shifts during the off hours', () => {
expect(scheduleShifts([2, 3, 2, 4, 6, 2, 1, 1], 6)).toEqual([2, 2, 1, 3]);
});
test('schedules shifts for example prediction sequence 0', () => {
expect(scheduleShifts([5, 6, 4], 8)).toEqual([1, 2]);
});
test('schedules shifts for example prediction sequence 1', () => {
expect(scheduleShifts([3, 4, 3, 8], 8)).toEqual([3, 1]);
});
test('schedules shifts for example prediction sequence 2', () => {
expect(scheduleShifts([3, 8, 1, 7, 2], 8)).toEqual([2, 3]);
});
test('schedules shifts for example prediction sequence 3', () => {
expect(scheduleShifts([4, 6, 6, 4, 5, 6], 8)).toEqual([2, 1, 2, 1]);
});
test('schedules shifts for example prediction sequence 4', () => {
expect(scheduleShifts([4, 0, 4, 1, 0, 0, 5], 8)).toEqual([3, 4]);
});
test('schedules shifts for example prediction sequence 5', () => {
expect(scheduleShifts([3, 4, 3, 2, 1, 2, 3, 4], 8)).toEqual([2, 4, 2]);
});
test('schedules shifts for example prediction sequence 6', () => {
expect(scheduleShifts([0, 0, 8, 0, 1, 8, 2, 8, 3], 8)).toEqual([5, 2, 2]);
});
test('schedules shifts for example prediction sequence 7', () => {
expect(scheduleShifts([1, 8, 1, 1, 9, 1, 1, 10, 1, 1], 8)).toEqual([4, 3, 3]);
});
test('schedules shifts for example prediction sequence 8', () => {
expect(scheduleShifts([2, 1, 8, 1, 1, 9, 1, 1, 10, 1, 1], 8)).toEqual([4, 4, 3]);
});
test('schedules shifts for example prediction sequence 9', () => {
expect(scheduleShifts([6, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 5], 8)).toEqual([1, 1, 2, 6, 2]);
});
});
import NodeEnvironment from 'jest-environment-node';
export default class FailFastEnvironment extends NodeEnvironment {
constructor(...rest) {
super(...rest);
this.failed = false;
}
async handleTestEvent(event, state) {
switch (event.name) {
case 'hook_failure':
case 'test_fn_failure':
this.failed = true;
break;
case 'test_start':
if (this.failed) {
event.test.mode = 'skip';
}
break;
default:
}
if (super.handleTestEvent !== undefined) {
await super.handleTestEvent(event, state);
}
}
}
This diff is collapsed.
{
"name": "@unlsoft/homework-3",
"version": "1.0.0",
"description": "A project skeleton to be used as starter code for Homework 3.",
"private": true,
"license": "UNLICENSED",
"scripts": {
"postinstall:eslint-config": "cd eslint-config && npm install",
"postinstall:app": "cd homework-3 && npm install",
"postinstall": "run-s postinstall:**",
"lint:app": "cd homework-3 && npm run lint",
"lint": "run-s --continue-on-error lint:**",
"test-once:closestPair": "cd homework-3 && npm run test-once:closestPair",
"test-once:sumToN": "cd homework-3 && npm run test-once:sumToN",
"test-once:intervals": "cd homework-3 && npm run test-once:intervals",
"test-once:trains": "cd homework-3 && npm run test-once:trains",
"test-once": "cd homework-3 && npm run test-once",
"test": "run-s test-once",
"start": "cd homework-3 && npm run start",
"build:app": "cd homework-3 && npm run build",
"build": "run-s build:**"
},
"devDependencies": {
"ghooks": "^2.0.4",
"npm-run-all": "^4.1.5"
},
"config": {
"ghooks": {
"pre-commit": "npm run lint"
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment