git @ Cat's Eye Technologies Cosmos-Boulders / master src / utils.js
master

Tree @master (Download .tar.gz)

utils.js @masterraw · history · blame

// SPDX-FileCopyrightText: In 2019, Chris Pressey, the original author of this work, placed it into the public domain.
// SPDX-License-Identifier: Unlicense
// For more information, please refer to <https://unlicense.org/>


import { bless } from '../contrib/concoctor-0.2/concoctor.js';
import { concoctJaft as concoct } from '../contrib/jaft-0.2/jaftConcoctor.js';
import { get, setr, update } from './immutable.js';


/* --[ Constants ]---------------------------------------------------------------- */


const screenWidth = bless(() => 640);
const screenHeight = bless(() => 400);

/* --[ Utility functions ]-------------------------------------------------------- */


const isUndefined = bless((x) => typeof x === 'undefined');

// FIXME: obviously, this is not pure.  However,
// for our purposes it is an "acceptable effect".
// Our eventual solution will be to have concoctor track
// a set of effects (instead of just "was produced by
// concoctor"), and error out if the result has any
// effects that are deemed unacceptable.
const error = bless(function(msg, arg) {
    throw new Error(msg + ": " + arg);
});

const newNull = bless(() => null);

const not = bless((b) => !b);

const pi = bless((n) => Math.PI * n);
const abs = bless((n) => Math.abs(n));
const cos = bless((n) => Math.cos(n));
const sin = bless((n) => Math.sin(n));
const floor = bless((n) => Math.floor(n));

// FIXME: again, obviously not pure.  See above.
const random = bless(() => Math.random());

const decr = concoct({}, `(x) => x - 1`);
const incr = concoct({}, `(x) => x + 1`);


const degreesToRadians = concoct({ pi }, `(deg) =>
    (deg / 360) * pi(2)
`);


const sign = concoct({}, `(n) =>
    (n > 0) ? 1 : (0 > n) ? (0 - 1) : 0
`);


const cap = concoct({ abs, sign }, `(n, absMax) =>
    (abs(n) > absMax) ? absMax * sign(n) : n
`);


const limitWithin = concoct({}, `(low, high, v) =>
    const range = high - low;
    ((((v - low) % range) + range) % range) + low
`);


const updatePosition = concoct({ setr, get, limitWithin, screenWidth, screenHeight }, `(obj) =>
    const x = get(obj, "x"), y = get(obj, "y"), vx = get(obj, "vx"), vy = get(obj, "vy");
    setr("x", limitWithin(0, screenWidth(), x + vx),
      setr("y", limitWithin(0, screenHeight(), y + vy), obj))
`);


const countDown = concoct({ update, decr, get }, `(obj, callback) =>
    const obj2 = update(obj, "timer", decr);
    get(obj2, "timer") <= 0 ? callback(obj2) : obj2
`, { signature: ["object", "function"] });


// FIXME we could rewrite in terms of countDown, eventually
const countDownToMode = concoct({ update, decr, get, setr }, `(obj, toMode) =>
    const obj2 = update(obj, "timer", decr);
    (get(obj2, "timer") <= 0) ? setr("mode", toMode, obj2) : obj2
`);


const fireWentDown = concoct({ not }, `(action) =>
    not(action.prev.firePressed) && action.firePressed
`);


const fireWentUp = concoct({ not }, `(action) =>
    action.prev.firePressed && not(action.firePressed)
`);


const makeAction = bless((t) => ({ type: t }));

export {
    screenWidth, screenHeight,
    isUndefined, not, error, newNull,
    abs, cos, sin, degreesToRadians, floor, random, sign, cap, limitWithin,
    updatePosition,
    decr, incr, countDown, countDownToMode, fireWentDown, fireWentUp,
    makeAction
}