diff --git a/package.json b/package.json index c13cfa4..6fb3679 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test:pyunit": "npm run extractcode && ./unittest_python.sh", "test": "npm run jest && npm run test:pyunit && npm run test:pystress", "build:ssr": "./ssr-all.sh", - "update:html": "mkdir -p build && (for i in {chapter1,chapter2,chapter3,chapter4}; do mustache src/mustache/$i.json src/page.html.template > src/autogenerated/$i.html; done)", + "update:html": "mkdir -p build && (for i in {chapter1,chapter2,chapter3,chapter4,new_demos}; do mustache src/mustache/$i.json src/page.html.template > src/autogenerated/$i.html; done)", "start": "webpack-dev-server --config webpack.dev.js --host 0.0.0.0", "serve": "http-server -p 9090 dist/", "build": "npm run build:ssr && webpack --config webpack.prod.js", diff --git a/src/autogenerated/new_demos.html b/src/autogenerated/new_demos.html new file mode 100644 index 0000000..1241b14 --- /dev/null +++ b/src/autogenerated/new_demos.html @@ -0,0 +1,18 @@ + + + + Inside python dict — an explorable explanation + + + + + + + + +
+ + + diff --git a/src/chapter1_simplified_hash.js b/src/chapter1_simplified_hash.js index f282b60..064d0cb 100644 --- a/src/chapter1_simplified_hash.js +++ b/src/chapter1_simplified_hash.js @@ -172,7 +172,7 @@ class SimplifiedInsertAll extends BreakpointFunction { this._overwritten = []; } - run(_originalList, isBroken = false) { + run(_originalList, isBroken = false, overrideSize = null) { this.fmtIsBroken = isBroken; this.originalList = new ImmutableList(_originalList); this.newList = new ImmutableList(); @@ -180,7 +180,13 @@ class SimplifiedInsertAll extends BreakpointFunction { this.fmtMissingNumbers = new ImmutableList(); this.newListWithReplacements = new ImmutableList(); } - const startSize = (isBroken ? 1 : 2) * this.originalList.size; + let startSize; + + if (!overrideSize) { + startSize = (isBroken ? 1 : 2) * this.originalList.size; + } else { + overrideSize = startSize; + } for (let i = 0; i < startSize; ++i) { this.newList = this.newList.push(null); if (isBroken) { @@ -245,21 +251,15 @@ let formatSimplifiedInsertAllDescription = function(bp, prevBp) { bp.number }`; case 'compute-idx': - return `Compute the slot index: ${bp.newListIdx} == ${bp.number} % ${ - bp.newList.size - }`; + return `Compute the slot index: ${bp.newListIdx} == ${bp.number} % ${bp.newList.size}`; case 'check-collision': return chapter1_2_FormatCheckCollision(bp.newList, bp.newListIdx, bp.fmtCollisionCount); case 'next-idx': - return `Keep probing, the next slot will be ${bp.newListIdx} == (${ - prevBp.newListIdx - } + 1) % ${bp.newList.size}`; + return `Keep probing, the next slot will be ${bp.newListIdx} == (${prevBp.newListIdx} + 1) % ${bp.newList.size}`; case 'assign-elem': { const prevNumber = prevBp.newList.get(bp.newListIdx); if (prevNumber != null) { - return `Collision of ${bp.number} with ${prevNumber} in slot ${ - bp.newListIdx - } - the number is overwritten`; + return `Collision of ${bp.number} with ${prevNumber} in slot ${bp.newListIdx} - the number is overwritten`; } else { return `Put ${bp.number} in slot ${bp.newListIdx}`; } @@ -351,9 +351,7 @@ class SimplifiedSearch extends BreakpointFunction { let formatSimplifiedSearchDescription = function(bp) { switch (bp.point) { case 'compute-idx': - return `Compute the slot index: ${bp.newListIdx} == ${bp.number} % ${ - bp.newList.size - }`; + return `Compute the slot index: ${bp.newListIdx} == ${bp.number} % ${bp.newList.size}`; case 'check-not-found': return commonFormatCheckNotFound(bp.newList, bp.newListIdx, bp.fmtCollisionCount); case 'check-found': @@ -618,8 +616,8 @@ export class Chapter1_SimplifiedHash extends ChapterComponent {

Accessing a single element by index is very fast. Accessing only a few elements would be fast - too. We don't want to be doing a linear scan over the whole list every time we look up a number, so - we need to organize our data in a clever way. + too. We don't want to be doing a linear scan over the whole list every time we look up a number, + so we need to organize our data in a clever way.

Here's how.

diff --git a/src/code_blocks.js b/src/code_blocks.js index 5e7e539..af3e851 100644 --- a/src/code_blocks.js +++ b/src/code_blocks.js @@ -1310,6 +1310,55 @@ export class Tetris extends React.PureComponent { } } +export function formatBp(bp, prevBp, formatBpDesc) { + let desc = null; + if (typeof formatBpDesc === 'function') { + desc = formatBpDesc(bp, prevBp); + } else { + for (const formatFunc of formatBpDesc) { + desc = formatFunc(bp, prevBp); + if (desc != null) break; + } + } + return desc; +} + +export function getVisibleBreakpoints(code, breakpoints, time) { + let visibleBreakpoints = {}; + let pointToLevel = {}; + for (let [line, bpPoint, level] of code) { + if (line === '' || bpPoint === '') { + continue; + } + if (level === undefined) { + pointToLevel = null; + break; + } + pointToLevel[bpPoint] = level; + } + + let prevBp = null; + for (let [t, bp] of breakpoints.entries()) { + if (t > time) { + break; + } + + if (bp.point in visibleBreakpoints) { + let level = pointToLevel[bp.point]; + for (let visibleBpPoint in visibleBreakpoints) { + if (pointToLevel[visibleBpPoint] >= level) { + delete visibleBreakpoints[visibleBpPoint]; + } + } + } + + visibleBreakpoints[bp.point] = {bp, prevBp}; + prevBp = bp; + } + + return visibleBreakpoints; +} + class CodeBlockWithActiveLineAndAnnotations extends React.Component { constructor() { super(); @@ -1330,7 +1379,6 @@ class CodeBlockWithActiveLineAndAnnotations extends React.Component { }); getCodeWithExplanationHtmlLines(visibleBreakpoints, activeBp) { - const t1 = performance.now(); const code = this.props.code; const hlLines = this._highlightLines(code); let lines = []; @@ -1345,15 +1393,7 @@ class CodeBlockWithActiveLineAndAnnotations extends React.Component { if (bpPoint in visibleBreakpoints) { const {bp, prevBp} = visibleBreakpoints[bpPoint]; - let desc = null; - if (typeof this.props.formatBpDesc === 'function') { - desc = this.props.formatBpDesc(bp, prevBp); - } else { - for (const formatBpDesc of this.props.formatBpDesc) { - desc = formatBpDesc(bp, prevBp); - if (desc != null) break; - } - } + const desc = formatBp(bp, prevBp, this.props.formatBpDesc); if (desc == null) { throw new Error('Unknown bp type: ' + bpPoint); @@ -1399,47 +1439,10 @@ class CodeBlockWithActiveLineAndAnnotations extends React.Component { return lines; } - getVisibleBreakpoints(activeBp) { - const t1 = performance.now(); - let visibleBreakpoints = {}; - let pointToLevel = {}; - for (let [line, bpPoint, level] of this.props.code) { - if (line === '' || bpPoint === '') { - continue; - } - if (level === undefined) { - pointToLevel = null; - break; - } - pointToLevel[bpPoint] = level; - } - - let prevBp = null; - for (let [time, bp] of this.props.breakpoints.entries()) { - if (time > this.props.time) { - break; - } - - if (bp.point in visibleBreakpoints) { - let level = pointToLevel[bp.point]; - for (let visibleBpPoint in visibleBreakpoints) { - if (pointToLevel[visibleBpPoint] >= level) { - delete visibleBreakpoints[visibleBpPoint]; - } - } - } - - visibleBreakpoints[bp.point] = {bp, prevBp}; - prevBp = bp; - } - - return visibleBreakpoints; - } - render() { let activeBp = this.props.breakpoints[this.props.time]; - const visibleBreakpoints = this.getVisibleBreakpoints(activeBp); + const visibleBreakpoints = getVisibleBreakpoints(this.props.code, this.props.breakpoints, this.props.time); const lines = this.getCodeWithExplanationHtmlLines(visibleBreakpoints, activeBp); return ( @@ -1792,6 +1795,18 @@ export class VisualizedCode extends React.Component { } } + getLastDesc() { + const currentBp = this.props.breakpoints[this.state.time]; + // Pretty hacky as an experiment + const visibleBreakpoints = getVisibleBreakpoints(this.props.code, this.props.breakpoints, this.state.time); + if (visibleBreakpoints.length === 0) { + return null; + } + console.log('VB', visibleBreakpoints, currentBp.point); + const {bp, prevBp} = visibleBreakpoints[currentBp.point]; + return formatBp(bp, prevBp, this.props.formatBpDesc); + } + render() { const windowWidth = this.props.windowWidth; const windowHeight = this.props.windowHeight; @@ -1801,6 +1816,9 @@ export class VisualizedCode extends React.Component { const smallerFont = tallScreen || serverSide; let bp = this.props.breakpoints[this.state.time]; + + const lastDesc = this.getLastDesc(); + const StateVisualization = this.props.stateVisualization; let codeHeight; @@ -1835,6 +1853,14 @@ export class VisualizedCode extends React.Component { maxTime={this.props.breakpoints.length - 1} autoplayByDefault={this.props.autoplayByDefault} /> +

+ +
+

Demos

+ +

Hello, world!

+

Hello, world!

+
+ + ); + } +} diff --git a/src/styles.css b/src/styles.css index 835a7e5..cd10b90 100644 --- a/src/styles.css +++ b/src/styles.css @@ -448,3 +448,8 @@ blockquote.blockquote { transition-duration: 750ms; transition-function: ease; } + +.last-desc { + font-size: 18px; + margin-top: 10px; +} diff --git a/webpack.dev.js b/webpack.dev.js index ca295d9..777008d 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -22,6 +22,10 @@ module.exports = merge(common, { template: 'src/autogenerated/chapter4.html', filename: 'chapter4.html', }), + new HtmlWebpackPlugin({ + template: 'src/autogenerated/new_demos.html', + filename: 'new_demos.html', + }), ], devServer: { contentBase: './dist', diff --git a/webpack.prod.js b/webpack.prod.js index b240c77..870d87a 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -28,6 +28,10 @@ module.exports = merge(common, { template: 'build/chapter4.html', filename: 'chapter4.html', }), + new HtmlWebpackPlugin({ + template: 'build/new_demos.html', + filename: 'new_demos.html', + }), new BundleAnalyzerPlugin(), ], });