Last updated
Last updated
// RxJS v6+
import { fromEvent, of, interval, combineLatest } from 'rxjs';
import {
finalize,
map,
pluck,
scan,
startWith,
takeWhile,
tap
} from 'rxjs/operators';
import { score, randomBrick, clearGame, initialState } from './game';
import { render, renderGameOver } from './html-renderer';
import { handleKeyPress, resetKey } from './keyboard';
import { collide } from './collision';
import { rotate } from './rotation';
import { BRICK } from './constants';
import { State, Brick, Key } from './interfaces';
const player$ = combineLatest(
of(randomBrick()),
of({ code: '' }),
fromEvent(document, 'keyup').pipe(
startWith({ code: undefined }),
pluck('code')
)
).pipe(
map(
([brick, key, keyCode]: [Brick, Key, string]) => (
(key.code = keyCode), [brick, key]
)
)
);
const state$ = interval(1000).pipe(
scan < number,
State > ((state, _) => (state.x++, state), initialState)
);
const game$ = combineLatest(state$, player$).pipe(
scan < [State, [Brick, Key]],
[State, [Brick, Key]] >
(([state, [brick, key]]) => (
(state = handleKeyPress(state, brick, key)),
(([newState, rotatedBrick]: [State, Brick]) => (
(state = newState), (brick = rotatedBrick)
))(rotate(state, brick, key)),
(([newState, collidedBrick]: [State, Brick]) => (
(state = newState), (brick = collidedBrick)
))(collide(state, brick)),
(state = score(state)),
resetKey(key),
[state, [brick, key]]
)),
tap(([state, [brick, key]]) => render(state, brick)),
takeWhile(([state, [brick, key]]) => !state.game[1].some(c => c === BRICK)),
finalize(renderGameOver)
);
game$.subscribe();
import { GAME_SIZE, EMPTY, BRICK } from './constants';
import { State } from './interfaces';
const bricks = [
[
[0, 0, 0],
[1, 1, 1],
[0, 0, 0]
],
[
[1, 1, 1],
[0, 1, 0],
[0, 1, 0]
],
[
[0, 1, 1],
[0, 1, 0],
[0, 1, 0]
],
[
[1, 1, 0],
[0, 1, 0],
[0, 1, 0]
],
[
[1, 1, 0],
[1, 1, 0],
[0, 0, 0]
]
];
export const clearGame = () =>
Array(GAME_SIZE)
.fill(EMPTY)
.map(e => Array(GAME_SIZE).fill(EMPTY));
export const updatePosition = (position: number, column: number) =>
position === 0 ? column : position;
export const validGame = (game: number[][]) =>
game.map(r => r.filter((_, i) => i < GAME_SIZE));
export const validBrick = (brick: number[][]) =>
brick.filter(e => e.some(b => b === BRICK));
export const randomBrick = () =>
bricks[Math.floor(Math.random() * bricks.length)];
export const score = (state: State): State =>
(scoreIndex =>
scoreIndex > -1
? ((state.score += 1),
state.game.splice(scoreIndex, 1),
(state.game = [Array(GAME_SIZE).fill(EMPTY), ...state.game]),
state)
: state)(state.game.findIndex(e => e.every(e => e === BRICK)));
export const initialState = {
game: clearGame(),
x: 0,
y: 0,
score: 0