Commit 26f59e22 authored by Brady James Garvin's avatar Brady James Garvin
Browse files

Added starter code for the homework on trees.

parent 0f90e119
......@@ -2,6 +2,12 @@
exports[`the ScoreSheet component correctly positions and numbers moves in a tree beginning from a nonzero ply 1`] = `
<div>
<div
id="portrait"
>
<div
id="app"
>
<div
class="score"
>
......@@ -143,11 +149,19 @@ exports[`the ScoreSheet component correctly positions and numbers moves in a tre
</span>
</div>
</div>
</div>
</div>
</div>
`;
exports[`the ScoreSheet component disables all of its buttons when it itself is disabled 1`] = `
<div>
<div
id="portrait"
>
<div
id="app"
>
<div
class="score"
>
......@@ -186,11 +200,19 @@ exports[`the ScoreSheet component disables all of its buttons when it itself is
</span>
</div>
</div>
</div>
</div>
</div>
`;
exports[`the ScoreSheet component organizes branchings into indented variations with ellipses to align moves 1`] = `
<div>
<div
id="portrait"
>
<div
id="app"
>
<div
class="score"
>
......@@ -341,5 +363,7 @@ exports[`the ScoreSheet component organizes branchings into indented variations
</span>
</div>
</div>
</div>
</div>
</div>
`;
......@@ -414,6 +414,24 @@ const gameTreesSlice = createSlice({
tree.modificationTime = impure.createTimestamp();
}
},
makeMainLine: (gameTrees, action) => {
const {
treeName,
positionIdentity,
} = action.payload;
console.log('makeMainLine reducer called with:');
console.log(` tree: ${treeName}`);
console.log(` position: ${positionIdentity}`);
},
deleteLine: (gameTrees, action) => {
const {
treeName,
positionIdentity,
} = action.payload;
console.log('deleteLine reducer called with:');
console.log(` tree: ${treeName}`);
console.log(` position: ${positionIdentity}`);
},
jumpToFirst: (gameTrees, action) => {
const {
treeName,
......@@ -471,6 +489,8 @@ export const {
rerootWithTeleportation,
setAnalysis,
makeMove,
makeMainLine,
deleteLine,
jumpToFirst,
jumpToPrevious,
jumpToNext,
......
......@@ -23,6 +23,8 @@ import gameTreesSlice, {
rerootWithTeleportation,
setAnalysis,
makeMove,
makeMainLine,
deleteLine,
jumpToFirst,
jumpToPrevious,
jumpToNext,
......@@ -2484,6 +2486,454 @@ describe('makeMove', () => {
});
});
describe('makeMainLine', () => {
test('has no effect when re-marking the current main line', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
root.mainLineMove = 'a';
child.mainLineMove = 'c';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, makeMainLine({
treeName: 'def',
positionIdentity: 3,
}));
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('changes only recent main-line moves when marking a recent deviation as the main line', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
root.mainLineMove = 'a';
child.mainLineMove = 'c';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, makeMainLine({
treeName: 'def',
positionIdentity: 2,
}));
child.mainLineMove = 'b';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('changes older main-line moves when marking a early deviation as the main line', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
const thirdGrandchild = dummyEncoding(5, secondChild, 'e');
root.mainLineMove = 'a';
child.mainLineMove = 'c';
secondChild.mainLineMove = 'e';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild, thirdGrandchild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, makeMainLine({
treeName: 'def',
positionIdentity: 5,
}));
root.mainLineMove = 'd';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild, thirdGrandchild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('does not unecessarily change main-line moves when marking a early deviation as the main line', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
root.mainLineMove = 'd';
child.mainLineMove = 'c';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, makeMainLine({
treeName: 'def',
positionIdentity: 1,
}));
root.mainLineMove = 'a';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
});
describe('deleteLine', () => {
describe('sets the current position to the parent of the deleted vertex', () => {
test('when the deleted vertex is a childless child', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 5,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 4,
}));
expect(state['def'].currentPositionIdentity).toBe(0);
});
test('when the deleted vertex is a child with children', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 5,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 1,
}));
expect(state['def'].currentPositionIdentity).toBe(0);
});
test('when the deleted vertex is a grandchild', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 5,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 3,
}));
expect(state['def'].currentPositionIdentity).toBe(1);
});
});
test('properly deletes a single position', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
root.mainLineMove = 'd';
child.mainLineMove = 'c';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 4,
}));
root.children['d'] = null;
root.mainLineMove = 'a';
root.mostRecentMove = 'a';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild),
rootIdentity: 0,
currentPositionIdentity: 0,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('properly deletes a two-position line', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
const thirdGrandchild = dummyEncoding(5, secondChild, 'e');
root.mainLineMove = 'a';
child.mainLineMove = 'c';
secondChild.mainLineMove = 'e';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
secondChild.mostRecentMove = 'e';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild, thirdGrandchild),
rootIdentity: 0,
currentPositionIdentity: 5,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 4,
}));
root.children['d'] = null;
root.mainLineMove = 'a';
root.mostRecentMove = 'a';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild),
rootIdentity: 0,
currentPositionIdentity: 0,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('properly deletes a line that splits', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const grandchild = dummyEncoding(2, child, 'b');
const secondGrandchild = dummyEncoding(3, child, 'c');
const secondChild = dummyEncoding(4, root, 'd');
root.mainLineMove = 'a';
child.mainLineMove = 'c';
secondChild.mainLineMove = 'e';
root.mostRecentMove = 'd';
child.mostRecentMove = 'b';
secondChild.mostRecentMove = 'e';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, grandchild, secondGrandchild, secondChild),
rootIdentity: 0,
currentPositionIdentity: 4,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 1,
}));
root.children['a'] = null;
root.mainLineMove = 'd';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, secondChild),
rootIdentity: 0,
currentPositionIdentity: 0,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
test('properly replaces moves to moribund positions', () => {
const root = dummyEncoding(0);
const child = dummyEncoding(1, root, 'a');
const secondChild = dummyEncoding(2, root, 'b');
const thirdChild = dummyEncoding(3, root, 'c');
root.mainLineMove = 'a';
root.mostRecentMove = 'a';
mockGame(new TestGame(undefined, undefined));
const state = gameTreesSlice.reducer({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, child, secondChild, thirdChild),
rootIdentity: 0,
currentPositionIdentity: 1,
modificationTime: EARLY_TIMESTAMP,
rotated: false,
},
}, deleteLine({
treeName: 'def',
positionIdentity: 1,
}));
root.children['a'] = null;
root.mainLineMove = 'c';
root.mostRecentMove = 'c';
expect(state).toEqual({
'def': {
title: undefined,
players: ['jkl', 'mno'],
game: 'ghi',
eternal: false,
complete: false,
positions: groupPositionEncodings(root, secondChild, thirdChild),
rootIdentity: 0,
currentPositionIdentity: 0,
modificationTime: LATE_TIMESTAMP,
rotated: false,
},
});
});
});
describe('the jump methods', () => {
test('can trace a path back to the root position', () => {
const root = dummyEncoding(0);
......
/* eslint-disable import/first, no-magic-numbers, quote-props */
import { render, screen } from '@testing-library/react';
import { MemoryRouter as Router, Route } from 'react-router-dom';
import userEvent from '@testing-library/user-event';
import '../../testing/mockRedux.js';
......@@ -46,6 +47,20 @@ function mockSituation(tree, current) {
Element.prototype.scrollIntoView = jest.fn().mockName('scrollIntoView');
}
function renderInContext(component) {
return render(
<div id="portrait">
<div id="app">
<Router initialEntries={['/score']}>
<Route path={'/score'}>
{component}