Skip to content

Commit f62a76a

Browse files
committed
feat(knuth-morris-pratt): implement info
1 parent cee147c commit f62a76a

File tree

12 files changed

+359
-10
lines changed

12 files changed

+359
-10
lines changed

.eslintrc.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ module.exports = {
44
parser: '@typescript-eslint/parser',
55
plugins: ['@typescript-eslint'],
66
root: true,
7+
rules: {
8+
'@typescript-eslint/no-unused-vars': 0,
9+
},
710
};

algorithms/string/knuth-morris-pratt/animation/enums/events.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* @since 2024-02-04
33
* @author vivaxy
44
*/
5+
export const INIT_INFO = 'INIT_INFO';
56
export const STAGE = 'STAGE';
67
export const SET_VALUE = 'SET_VALUE';
78
export const COMPARE = 'COMPARE';

algorithms/string/knuth-morris-pratt/animation/index.css

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,57 @@
22
* @since 2024-02-04
33
* @author vivaxy
44
*/
5+
.char {
6+
font-family: monospace;
7+
border: 1px solid rgba(0, 0, 0, 0.3);
8+
padding: 2px;
9+
margin: 2px;
10+
}
11+
12+
.char.hidden {
13+
opacity: 0;
14+
}
15+
16+
label {
17+
display: inline-block;
18+
width: 90px;
19+
}
20+
21+
#info {
22+
.text,
23+
.target {
24+
margin: 30px 4px 0 4px;
25+
}
26+
27+
.text-index,
28+
.target-index {
29+
margin: 0 4px;
30+
}
31+
32+
.text-index,
33+
.target-index {
34+
.char {
35+
border-color: transparent;
36+
}
37+
}
38+
39+
.target.highlight .char {
40+
background: #ff9292;
41+
}
42+
}
43+
44+
#pattern-table {
45+
.pattern-table {
46+
margin: 30px 4px 0 4px;
47+
}
48+
49+
.table-index {
50+
margin: 0 4px;
51+
}
52+
53+
.table-index {
54+
.char {
55+
border-color: transparent;
56+
}
57+
}
58+
}

algorithms/string/knuth-morris-pratt/animation/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
</head>
1919
<body>
2020
<div id="root">
21-
<div id="info"></div>
2221
<div id="stage"></div>
22+
<div id="info"></div>
2323
<div id="pattern-table"></div>
2424
<div id="search"></div>
2525
</div>

algorithms/string/knuth-morris-pratt/animation/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,23 @@ import { events } from './utils/events.js';
66
import { initKMP } from './services/kmp.js';
77
import { initStage } from './services/stage.js';
88
import { initPatternTable } from './services/pattern-table.js';
9+
import { initSearch } from './services/search.js';
10+
import { initInfo } from './services/info.js';
11+
import { sleep } from './utils/sleep.js';
912

1013
const kmp = initKMP(events);
1114
initStage(events);
1215
initPatternTable(events);
16+
initSearch(events);
17+
initInfo(events);
1318

14-
const fn = kmp('abcd', 'c');
19+
const fn = kmp('abcdef', 'cd');
1520
/**
1621
* @type {{value: *, done?: boolean}}
1722
*/
1823
let result = { value: undefined, done: false };
1924
while (!result.done) {
2025
result = fn.next();
26+
await sleep(1e3);
2127
}
2228
console.log('result', result);
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* @since 2024-02-16
3+
* @author vivaxy
4+
*/
5+
import {
6+
createElement,
7+
createText,
8+
render,
9+
// @ts-expect-error remote js
10+
} from 'https://unpkg.com/@vivaxy/framework/ui/render-app.js';
11+
12+
import * as EVENTS from '../enums/events.js';
13+
14+
/**
15+
* @typedef {import('../utils/types.js').EventEmitter} EventEmitter
16+
*/
17+
18+
/**
19+
* @param {{ text: string, target: string, textIndex: number, targetIndex: number, highlightTarget: boolean }} props
20+
* @returns {*}
21+
*/
22+
function createApp(props) {
23+
return createElement('div', {}, [
24+
createElement('div', { class: 'text' }, [
25+
createElement('label', {}, [createText('Text: ')]),
26+
...props.text.split('').map(function (char) {
27+
return createElement('span', { class: 'char' }, [createText(char)]);
28+
}),
29+
]),
30+
createElement('div', { class: 'text-index' }, [
31+
createElement('label', {}, [createText('Text index: ')]),
32+
33+
...props.text.split('').map(function (_, i) {
34+
return createElement(
35+
'span',
36+
{ class: `char ${i === props.textIndex ? '' : 'hidden'}` },
37+
[createText('↑')],
38+
);
39+
}),
40+
]),
41+
createElement(
42+
'div',
43+
{ class: `target ${props.highlightTarget ? 'highlight' : ''}` },
44+
[
45+
createElement('label', {}, [createText('Target: ')]),
46+
...props.target.split('').map(function (char) {
47+
return createElement('span', { class: 'char' }, [createText(char)]);
48+
}),
49+
],
50+
),
51+
createElement('div', { class: 'target-index' }, [
52+
createElement('label', {}, [createText('Target index: ')]),
53+
...props.target.split('').map(function (_, i) {
54+
return createElement(
55+
'span',
56+
{ class: `char ${i === props.targetIndex ? '' : 'hidden'}` },
57+
[createText('↑')],
58+
);
59+
}),
60+
]),
61+
]);
62+
}
63+
64+
/**
65+
* @param {EventEmitter} events
66+
*/
67+
export function initInfo(events) {
68+
let props = {
69+
root: document.getElementById('info'),
70+
text: '',
71+
target: '',
72+
textIndex: -1,
73+
targetIndex: -1,
74+
highlightTarget: false,
75+
};
76+
77+
events.on(EVENTS.INIT_INFO, function ({ text, target }) {
78+
props = {
79+
...props,
80+
text,
81+
target,
82+
highlightTarget: false,
83+
};
84+
render(createApp, props, props.root);
85+
});
86+
87+
events.on(EVENTS.SET_VALUE, function ({ key, value }) {
88+
props = {
89+
...props,
90+
[key]: value,
91+
highlightTarget: false,
92+
};
93+
render(createApp, props, props.root);
94+
});
95+
96+
events.on(EVENTS.COMPARE, function ({ from }) {
97+
if (from === 'target[length]') {
98+
props = {
99+
...props,
100+
highlightTarget: true,
101+
};
102+
render(createApp, props, props.root);
103+
}
104+
});
105+
106+
events.on(EVENTS.STAGE, function () {
107+
props = {
108+
...props,
109+
highlightTarget: false,
110+
};
111+
render(createApp, props, props.root);
112+
});
113+
114+
events.on(EVENTS.RESULT, function () {
115+
props = {
116+
...props,
117+
highlightTarget: false,
118+
};
119+
render(createApp, props, props.root);
120+
});
121+
}

algorithms/string/knuth-morris-pratt/animation/services/kmp.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,27 @@
44
*/
55
import * as EVENTS from '../enums/events.js';
66

7+
/**
8+
* @typedef {import('../utils/types.js').EventEmitter} EventEmitter
9+
*/
10+
11+
/**
12+
* @param {EventEmitter} events
13+
*/
714
export function initKMP(events) {
815
/**
916
* @param {string} text
1017
* @param {string} target
11-
* @returns {Generator<number>}
18+
* @returns {Generator<*>}
1219
*/
1320
return function* knuthMorrisPratt(text, target) {
21+
yield events.emit(EVENTS.INIT_INFO, { text, target });
22+
23+
yield events.emit(EVENTS.STAGE, { value: 0 });
24+
yield events.emit(EVENTS.COMPARE, {
25+
from: 'target[length]',
26+
to: '0',
27+
});
1428
if (target.length === 0) {
1529
yield events.emit(EVENTS.RESULT, { value: 0 });
1630
return 0;
@@ -29,7 +43,6 @@ export function initKMP(events) {
2943
let patternTableGeneratorResult = { value: [], done: false };
3044
while (!patternTableGeneratorResult.done) {
3145
patternTableGeneratorResult = patternTableGenerator.next();
32-
// @ts-expect-error value maybe events or patternTable
3346
yield patternTableGeneratorResult.value;
3447
}
3548
const patternTable = patternTableGeneratorResult.value;
@@ -78,10 +91,15 @@ export function initKMP(events) {
7891

7992
/**
8093
* @param {string} target
81-
* @returns {Generator<number[]>}
94+
* @returns {Generator<*>}
8295
*/
8396
function* buildPatternTable(target) {
8497
let patternTable = [0];
98+
yield events.emit(EVENTS.SET_VALUE, { key: 'tableIndex', value: 0 });
99+
yield events.emit(EVENTS.SET_VALUE, {
100+
key: 'patternTable[tableIndex]',
101+
value: 0,
102+
});
85103
let tableIndex = 1;
86104
yield events.emit(EVENTS.SET_VALUE, { key: 'tableIndex', value: 1 });
87105
let currentTargetIndex = 0;

algorithms/string/knuth-morris-pratt/animation/services/pattern-table.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,76 @@
22
* @since 2024-02-04
33
* @author vivaxy
44
*/
5-
export function initPatternTable() {}
5+
import {
6+
createElement,
7+
createText,
8+
render,
9+
// @ts-expect-error remote js
10+
} from 'https://unpkg.com/@vivaxy/framework/ui/render-app.js';
11+
import * as EVENTS from '../enums/events.js';
12+
13+
/**
14+
* @typedef {import('../utils/types.js').EventEmitter} EventEmitter
15+
*/
16+
17+
/**
18+
* @param {{ tableIndex: number, patternTable: number[] }} props
19+
*/
20+
function createApp(props) {
21+
return createElement('div', {}, [
22+
createElement('div', { class: 'pattern-table' }, [
23+
createElement('label', {}, [createText('Pattern table: ')]),
24+
...props.patternTable.map(function (number) {
25+
return createElement('span', {}, [createText(number)]);
26+
}),
27+
]),
28+
createElement('div', { class: 'table-index' }, [
29+
createElement('label', {}, [createText('tableIndex: ')]),
30+
...Array.from(
31+
{ length: Math.max(props.patternTable.length, props.tableIndex + 1) },
32+
function (_, i) {
33+
return createElement(
34+
'span',
35+
{ class: `char ${i === props.tableIndex ? '' : 'hidden'}` },
36+
[createText('↑')],
37+
);
38+
},
39+
),
40+
]),
41+
]);
42+
}
43+
44+
/**
45+
* @param {EventEmitter} events
46+
*/
47+
export function initPatternTable(events) {
48+
let stage = 1;
49+
let props = {
50+
root: document.getElementById('pattern-table'),
51+
patternTable: [],
52+
tableIndex: -1,
53+
};
54+
55+
events.on(EVENTS.STAGE, function ({ value }) {
56+
stage = value;
57+
if (stage === 1) {
58+
render(createApp, props, props.root);
59+
}
60+
});
61+
events.on(EVENTS.SET_VALUE, function ({ key, value }) {
62+
if (stage === 1) {
63+
if (key === 'tableIndex') {
64+
props = {
65+
...props,
66+
tableIndex: value,
67+
};
68+
render(createApp, props, props.root);
69+
}
70+
}
71+
});
72+
events.on(EVENTS.COMPARE, function ({ from, to }) {
73+
if (stage === 1) {
74+
console.log('COMPARE', from, to);
75+
}
76+
});
77+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @since 2024-02-16
3+
* @author vivaxy
4+
*/
5+
import * as EVENTS from '../enums/events.js';
6+
7+
/**
8+
* @typedef {import('../utils/types.js').EventEmitter} EventEmitter
9+
*/
10+
11+
/**
12+
* @param {EventEmitter} events
13+
*/
14+
export function initSearch(events) {
15+
let stage = 0;
16+
events.on(EVENTS.STAGE, function ({ value }) {
17+
stage = value;
18+
});
19+
events.on(EVENTS.SET_VALUE, function (...args) {
20+
if (stage !== 1) {
21+
console.log('SET_VALUE', ...args);
22+
}
23+
});
24+
events.on(EVENTS.COMPARE, function (...args) {
25+
if (stage !== 1) {
26+
console.log('COMPARE', ...args);
27+
}
28+
});
29+
events.on(EVENTS.RESULT, function (...args) {
30+
if (stage !== 1) {
31+
console.log('RESULT', ...args);
32+
}
33+
});
34+
}

0 commit comments

Comments
 (0)