-
Notifications
You must be signed in to change notification settings - Fork 2
/
reducers.ts
107 lines (97 loc) · 2.78 KB
/
reducers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import Stream from 'xstream';
import delay from 'xstream/extra/delay';
import { IIntent } from './intent';
import { IResult, IState } from './definitions';
import flattenConcurrently from 'xstream/extra/flattenConcurrently';
import dropRepeats from 'xstream/extra/dropRepeats';
function reduce<T>(reducer$: Stream<(prev: T) => T>, initial: T) {
const value$ = reducer$.fold((current, reducer) => reducer(current), initial);
return value$;
}
function reducers(actions: IIntent): IState {
// alias
const xs = Stream;
const puzzle$ =
actions.newGame$
.map(() => {
const puzzle: number[] = [];
const maxSize = 9;
for (var i = 0; i < maxSize; i++) {
var nextNumber = Math.floor(Math.random() * 25);
while (puzzle.indexOf(nextNumber) !== -1)
nextNumber = Math.floor(Math.random() * 25);
puzzle.push(nextNumber);
}
return puzzle;
}).remember();
const selectedCellsReducer$ =
xs.merge(
puzzle$
.mapTo(() => new Array<number>()),
actions.reset$
.mapTo(() => new Array<number>()),
actions.selectCell$
.map(clicked =>
(selectedCells: number[]) => {
var selected = selectedCells.indexOf(clicked) !== -1;
return selected
? selectedCells.filter(x => x != clicked)
: selectedCells.concat(clicked);
})
);
const selectedCells$ =
reduce(selectedCellsReducer$, new Array<number>())
.remember();
const allowed$ =
xs.merge(
puzzle$
.mapTo(false),
puzzle$
.compose(delay(4000))
.mapTo(true)
).remember();
const over$ =
selectedCells$
.map((selected) => selected.length === 9)
.compose(dropRepeats<boolean>((prev, next) => prev === next));
const result$ =
xs.merge(
puzzle$
.mapTo(null),
over$
.filter(Boolean)
.map(() =>
puzzle$.map(puzzle =>
selectedCells$.map(selected => {
const result: IResult = {
correct: selected.filter(s => puzzle.indexOf(s) !== -1),
wrong: selected.filter(s => puzzle.indexOf(s) === -1),
missed: puzzle.filter(p => selected.indexOf(p) === -1)
};
return result;
})
).flatten()
).flatten()
).startWith(null);
const scoreReducer$ =
result$
.filter(Boolean)
.map(result =>
(score: number) => {
const won = result.correct.length === 9;
score = score || 0;
return won ? score + 1 : score;
});
const score$ =
reduce(scoreReducer$, 0)
.remember();
return {
puzzle$,
allowed$,
selectedCells$,
over$,
score$,
result$
};
}
export default reducers;