Skip to content

Commit

Permalink
feat: compare numbers worksheet
Browse files Browse the repository at this point in the history
  • Loading branch information
asartalo committed Jul 25, 2022
1 parent ddc772e commit b74a840
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 2 deletions.
5 changes: 5 additions & 0 deletions cypress/e2e/navigation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ it('can visit all subpages', () => {

cy.contains(/Printable Materials for Education/i);

// Compare Numbers Worksheets
clickWorksheetLink(/compare.+numbers/i);
cy.hasCustomizeFormHeading(/compare.+numbers/i);

// Addition Worksheets
goBackHome();
clickWorksheetLink(/addition.+fill.+blank/i);
cy.hasCustomizeFormHeading(/addition.+fill.+blank/i);

Expand Down
24 changes: 24 additions & 0 deletions cypress/e2e/worksheet_compare_numbers.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
it('can create compare numbers worksheet', () => {
cy.visitWorksheetCompareNumbers();

cy.findByLabelText(/count/i).clearType('8');
cy.findByLabelText(/magnitude/i).select('Hundreds');
cy.findByLabelText(/columns/i).clearType('2');
cy.withinPreview(() => {
cy.findByRole('list', { name: 'Problems' }).within((subject) => {
cy.wrap(subject).findAllByRole('listitem')
.should('have.length', 8)
.each(($li) => {
cy.wrap($li).contains(/\d+\s+_+\s+\d+/);
});
});

cy.findByRole('list', { name: 'Answers' }).within((subject) => {
cy.wrap(subject).findAllByRole('listitem')
.should('have.length', 8)
.each(($li) => {
cy.wrap($li).contains(/\d+\s+(<|>|=)\s+\d+/);
});
});
});
});
1 change: 1 addition & 0 deletions cypress/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ declare namespace Cypress {
visitWorksheetTellingTime(): Chainable<AUTWindow>;
visitWorksheetNumberGrid(): Chainable<AUTWindow>;
visitWorksheetSkipCounting(): Chainable<AUTWindow>;
visitWorksheetCompareNumbers(): Chainable<AUTWindow>;
}

interface Chainable<Subject> {
Expand Down
1 change: 1 addition & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const paths = {
worksheetTellingTime: '/worksheet-telling-time',
worksheetNumberGrid: '/worksheet-number-grid',
worksheetSkipCounting: '/worksheet-skip-counting',
worksheetCompareNumbers: 'worksheet-compare-numbers',
};

const pathNames = Object.keys(paths);
Expand Down
4 changes: 2 additions & 2 deletions src/lib/RandomNumberGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import Range from './Range';

export type MathRandom = () => number;

type ScalingMap<T> = Map<T, number>;
export type ScalingMap<T> = Map<T, number>;

function scaledRoulette<T>(scales: ScalingMap<T>): T {
export function scaledRoulette<T>(scales: ScalingMap<T>): T {
const r = Math.random();
const total = Array.from(scales.values())
.reduce<number>((sum, n) => sum + n, 0);
Expand Down
5 changes: 5 additions & 0 deletions src/lib/linkMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const NumbersToWordsPage = lazy(() => import('../pages/numbersToWords/NumbersToW
const TellingTimePage = lazy(() => import('../pages/tellingTime/TellingTimePage'));
const NumberGridPage = lazy(() => import('../pages/numberGrid/NumberGridPage'));
const SkipCountingPage = lazy(() => import('../pages/skipCounting/SkipCountingPage'));
const CompareNumbersPage = lazy(() => import('../pages/compareNumbers/CompareNumbersPage'));
const ExperimentsPage = lazy(() => import('../pages/experiments/ExperimentsPage'));
const SettingsPage = lazy(() => import('../pages/settings/SettingsPage'));

Expand Down Expand Up @@ -43,6 +44,10 @@ if (!isProduction) {
}

export const mathLinks: SectionLinks = new Map([
['/worksheet-compare-numbers', {
text: 'Compare Numbers',
loader: CompareNumbersPage,
}],
['/addition-fill-the-blanks', {
text: 'Addition: Fill in the Blanks',
loader: AdditionFillTheBlanksPage,
Expand Down
14 changes: 14 additions & 0 deletions src/pages/compareNumbers/CompareNumbersData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Magnitude } from '../../lib/math/magnitude';

export type NumberComparison = '>' | '<' | '=';
export const numberComparisons: NumberComparison[] = [
'>',
'<',
'=',
];

export default interface CompareNumbersData {
count: number;
magnitude: Magnitude;
columns: number;
}
35 changes: 35 additions & 0 deletions src/pages/compareNumbers/CompareNumbersPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PrintableUI from '../../components/PrintableUI';
import usePageState from '../usePageState';
import CustomizeCompareNumbersForm from './CustomizeCompareNumbersForm';
import CompareNumbersData from './CompareNumbersData';
import PreviewCompareNumbers from './PreviewCompareNumbers';

const defaultData: CompareNumbersData = {
count: 10,
magnitude: 'tens',
columns: 1,
};
const key = 'compareNumbers';

function CompareNumbersPage(): JSX.Element {
const { data, onChange } = usePageState<CompareNumbersData>({
key, defaultData,
});
return (
<PrintableUI
title="Compare Numbers"
optionsKey={key}
customizeForm={(
<CustomizeCompareNumbersForm
onChange={onChange}
data={data}
/>
)}
>
<PreviewCompareNumbers data={data} />
</PrintableUI>
);
}

export default CompareNumbersPage;
26 changes: 26 additions & 0 deletions src/pages/compareNumbers/CompareNumbersProblem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NumberComparison } from './CompareNumbersData';

class CompareNumbersProblem {
left: number;

right: number;

constructor(left: number, right: number) {
this.left = left;
this.right = right;
}

symbol(): NumberComparison {
if (this.left === this.right) {
return '=';
}
return this.left > this.right ? '>' : '<';
}

toString() {
const symbol = this.symbol() as string;
return `${this.left} ${symbol} ${this.right}`;
}
}

export default CompareNumbersProblem;
47 changes: 47 additions & 0 deletions src/pages/compareNumbers/CustomizeCompareNumbersForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { Divider } from '@material-ui/core';
import CustomizeForm from '../../components/forms/CustomizeForm';
import CompareNumbersData from './CompareNumbersData';
import NumberField from '../../components/forms/NumberField';
import { Magnitude, magnitudes } from '../../lib/math/magnitude';
import SelectField from '../../components/forms/SelectField';
import arrayToOptions from '../../components/forms/arrayToOptions';

interface CustomizeCompareNumbersFormProps {
onChange: (data: CompareNumbersData) => void;
data: CompareNumbersData;
}

function CustomizeCompareNumbersForm({
data, onChange,
}: CustomizeCompareNumbersFormProps): JSX.Element {
return (
<CustomizeForm name="Worksheet">
<NumberField
name="count"
label="Count"
value={data.count}
onChange={(count) => onChange({ ...data, count })}
/>
<SelectField<Magnitude>
name="magnitude"
value={data.magnitude}
onChange={(magnitude) => onChange({ ...data, magnitude })}
>
{arrayToOptions(magnitudes, true)}
</SelectField>

<Divider variant="middle" />
<NumberField
name="columns"
value={data.columns}
onChange={(columns) => onChange({ ...data, columns })}
min={1}
max={10}
/>

</CustomizeForm>
);
}

export default CustomizeCompareNumbersForm;
78 changes: 78 additions & 0 deletions src/pages/compareNumbers/PreviewCompareNumbers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';
import MultiPaperPage from '../../components/MultiPaperPage';
import PageTitle from '../../elements/PageTitle';
import ProblemList from '../../components/ProblemList';
import ProblemListItem from '../../components/ProblemListItem';
import WorksheetFooter from '../../components/printElements/WorksheetFooter';
import WorksheetHeader from '../../components/printElements/WorksheetHeader';
import CompareNumbersData from './CompareNumbersData';
import generateProblems from './generateProblems';
import CompareNumbersProblem from './CompareNumbersProblem';
import Blank from '../../components/Blank';

function itemBuilder(
showAnswer: boolean,
) {
function fn(problem: CompareNumbersProblem, indexNumber: number) {
return (
<ProblemListItem
key={`problem-${indexNumber}`}
className="compare-numbers-problem-item"
label={`Compare Numbers ${showAnswer ? 'Answer' : 'Problem'}`}
>
{problem.left}
{' '}
<Blank showAnswer={showAnswer} answer={problem.symbol().toString()} />
{' '}
{problem.right}
</ProblemListItem>
);
}
return fn;
}

interface PreviewCompareNumbersProps {
data: CompareNumbersData;
}

function PreviewCompareNumbers({ data }: PreviewCompareNumbersProps): JSX.Element {
const problems = generateProblems(data);
const instructions = 'Write <, >, = if the number on the left is less than, greater than, or equal to the number on the right.';

return (
<>
<MultiPaperPage
header={(
<WorksheetHeader>
<p>{instructions}</p>
</WorksheetHeader>
)}
wrapper={ProblemList}
footer={(<WorksheetFooter itemCount={problems.length} />)}
wrapperProps={{
className: 'problems',
columns: data.columns,
}}
data={problems}
itemSelector=".compare-numbers-problem-item"
renderItems={itemBuilder(false)}
/>
<MultiPaperPage
header={(
<PageTitle>Answer Key</PageTitle>
)}
wrapper={ProblemList}
wrapperProps={{
className: 'answers',
label: 'Answers',
columns: data.columns,
}}
data={problems}
itemSelector=".compare-numbers-problem-item"
renderItems={itemBuilder(true)}
/>
</>
);
}

export default PreviewCompareNumbers;
35 changes: 35 additions & 0 deletions src/pages/compareNumbers/generateProblems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { maxFromMagnitude } from '../../lib/math/magnitude';
import { randomGenerator, scaledRoulette, ScalingMap } from '../../lib/RandomNumberGenerator';
import CompareNumbersData, { NumberComparison } from './CompareNumbersData';
import CompareNumbersProblem from './CompareNumbersProblem';

const comparisonWeights: ScalingMap<NumberComparison> = new Map([
['<', 2],
['>', 2],
['=', 1],
]);

export default function generateProblems({
magnitude, count,
}: CompareNumbersData): CompareNumbersProblem[] {
const problems: CompareNumbersProblem[] = [];
const max = maxFromMagnitude(magnitude);
for (let i = 0; i < count; i++) {
const comparison = scaledRoulette(comparisonWeights);
let left: number;
let right: number;
if (comparison === '>') {
left = randomGenerator.integer(max, 1);
right = randomGenerator.integer(left - 1);
} else if (comparison === '<') {
left = randomGenerator.integer(max - 1);
right = randomGenerator.integer(max, left + 1);
} else {
left = randomGenerator.integer(max);
right = left;
}
problems.push(new CompareNumbersProblem(left, right));
}

return problems;
}

0 comments on commit b74a840

Please sign in to comment.