Last active
July 20, 2017 18:04
-
-
Save Heimdell/fd1c63102b9d4c53a9843f43df10d14c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Utils { | |
static unsnoc(array) { | |
return { | |
init: array.slice(0, -1), | |
last: array[array.length - 1], | |
} | |
} | |
} | |
class Event { | |
static new() { | |
return new Event() | |
} | |
constructor() { | |
this.subscribers = [] | |
} | |
subscribe(callback) { | |
this.subscribers.push(callback) | |
} | |
feed(event) { | |
this.subscribers.forEach(sink => { | |
sink(event) | |
}) | |
} | |
transform(commutator) { | |
var result = Event.new() | |
this.subscribe(event => { | |
setTimeout(() => { | |
commutator(result.feed.bind(result), event) | |
}, 0) | |
}) | |
return result | |
} | |
map(mapper) { | |
return this.transform((feed, event) => { | |
feed(mapper(event)) | |
}) | |
} | |
filter(predicate) { | |
return this.transform((feed, event) => { | |
if (predicate(event)) { | |
feed(event) | |
} | |
}) | |
} | |
reduce(acc, add) { | |
return this.transform((feed, event) => { | |
feed(acc = add(acc, event)) | |
}) | |
} | |
delay(ms) { | |
return this.transform((feed, event) => { | |
setTimeout(() => feed(event), ms) | |
}) | |
} | |
throttle(ms) { | |
var comesThrough = true; | |
return this.transform((feed, event) => { | |
if (comesThrough) { | |
comesThrough = false | |
feed(event) | |
setTimeout(() => { | |
comesThrough = true | |
}, ms) | |
} | |
}) | |
} | |
mergeWith(event) { | |
var result = Event.new() | |
this .subscribe(event => result.feed(event)) | |
event.subscribe(event => result.feed(event)) | |
return result | |
} | |
static merge([event, ...events]) { | |
return events.reduce((a, b) => a.mergeWith(b), event) | |
} | |
static group(group) { | |
var keyed = | |
Object.keys(group).map(key => | |
group[key].map(x => | |
({[key]: x}) | |
) | |
) | |
return Event.merge(keyed) | |
} | |
behavior() { | |
return Behavior.of(this) | |
} | |
sample(...args) { | |
const {init: behaviors, last: f} = Utils.unsnoc(args) | |
return this.map(x => f(x, ...behaviours.map(it => it.now()))) | |
} | |
compact() { | |
return this.filter(x => undefined !== x) | |
} | |
split(tags) { | |
var tagged = | |
tags.map(tag => ({ | |
tag, | |
event: this.map(event => event[tag]).compact() | |
})) | |
return tagged.reduce( | |
(acc, {tag, event}) => | |
Object.assign(acc, {[tag]: event}), | |
{} | |
) | |
} | |
} | |
class Behavior { | |
static of(event) { | |
return new Behavior(event) | |
} | |
constructor(event) { | |
event.subscribe(value => { | |
this.value = value | |
}) | |
} | |
now() { | |
return this.value | |
} | |
sampleOn(event) { | |
return event.map(_ => this.now()) | |
} | |
applyTo(event, f) { | |
return event.map(x => f(this.now(), x)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var s = JSON.stringify | |
var parseLevel = (...lines) => { | |
var center | |
outer: for (var y = 0; y < lines.length; y++) { | |
var line = lines[y] | |
for (var x = 0; x < line.length; x++) { | |
if (line[x] === "@") { | |
center = {x, y} | |
break outer | |
} | |
} | |
} | |
var terrain = {doors: {}} | |
terrain.maxX = 0 | |
terrain.minX = 0 | |
terrain.maxY = 0 | |
terrain.minY = 0 | |
for (var y = 0; y < lines.length; y++) { | |
var line = lines[y] | |
for (var x = 0; x < line.length; x++) { | |
terrain.maxX = Math.max(center.x - x, terrain.maxX) | |
terrain.minX = Math.min(center.x - x, terrain.minX) | |
terrain.maxY = Math.max(center.y - y, terrain.maxY) | |
terrain.minY = Math.min(center.y - y, terrain.minY) | |
var set = (val) => terrain[s({x: center.x - x, y: center.y - y})] = val | |
let char = line[x] | |
switch (char) { | |
case ".": | |
case "@": | |
set({open: true}) | |
break; | |
case '#': | |
set({open: false}) | |
break; | |
case 'X': | |
set({open: true, onstep: level => level.next()}) | |
break; | |
default: | |
if ("abcdef".includes(char)) { | |
set({ | |
open: true, | |
keyName: char, | |
onstep: (level) => level.openDoor(char.toUpperCase()) | |
}) | |
break; | |
} | |
if ("ABCDEF".includes(char)) { | |
terrain.doors[char] = s({x: center.x - x, y: center.y - y}) | |
set({open: false, doorName: char}) | |
break; | |
} | |
} | |
} | |
} | |
terrain.openDoor = (name) => { | |
terrain[terrain.doors[name]].open = ~terrain[terrain.doors[name]].open | |
return terrain | |
} | |
terrain.player = {x: 0, y: 0} | |
return terrain | |
} | |
var move = (terrain, {dx, dy}) => { | |
let {x, y} = terrain.player | |
let x1 = x + dx | |
let y1 = y + dy | |
let place = terrain[s({x: x1, y: y1})] | |
if (place && place.open) { | |
terrain.player = {x: x1, y: y1} | |
if (terrain[s(terrain.player)].onstep) { | |
return terrain[s(terrain.player)].onstep(terrain) | |
} | |
} | |
return terrain | |
} | |
var show = terrain => { | |
var acc = [] | |
for (var y = terrain.maxY + 1; y >= terrain.minY - 1; y--) { | |
for (var x = terrain.maxX + 1; x >= terrain.minX - 1; x--) { | |
let index = s({x, y}) | |
let place = terrain[index] | |
var glyph = '#' | |
if (s(terrain.player) === index) { | |
glyph = '@' | |
} else | |
if (place) { | |
if (place.open) { | |
if (place.keyName) { | |
glyph = place.keyName | |
} else { | |
glyph = '.' | |
} | |
} else { | |
if (place.doorName) { | |
glyph = place.doorName | |
} else { | |
glyph = '#' | |
} | |
} | |
} | |
acc.push(glyph) | |
} | |
acc.push('\n') | |
} | |
return acc.join("") + "\n" + s(terrain.player) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var keyboard = Event.new() | |
var wasd = keyboard.filter(key => "wasd ".includes(key)) | |
var movements = wasd.map(key => ( | |
{ w: {dx: 0, dy: +1} | |
, s: {dx: 0, dy: -1} | |
, a: {dx: +1, dy: 0} | |
, d: {dx: -1, dy: 0} | |
, ' ': {dx: 0, dy: 0} | |
} [key])) | |
var level = parseLevel( | |
"#############", | |
"#.#b......#.#", | |
"#..#.....#..#", | |
"#...##A##...#", | |
"#...#...#...#", | |
"#[email protected]#", | |
"#...#a..#...#", | |
"#...##B##...#", | |
"#..#.....#..#", | |
"#.#.....c.#.#", | |
"#############", | |
) | |
var state = movements.reduce(level, move) | |
var view = state.map(show) | |
view.subscribe((key) => { | |
var canvas = document.getElementById('canvas') | |
canvas.innerText = key | |
}) | |
document.onkeypress = (event) => { | |
keyboard.feed(event.key) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<pre id="canvas"> | |
<font caption="inconsolata"> | |
Press 'space' to start. | |
'WASD' to move. | |
</font> | |
</pre> | |
<script type="text/javascript" src="./frp.js"></script> | |
<script type="text/javascript" src="./game.js"></script> | |
<script type="text/javascript" src="./logic.js"></script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment