More lib files, more functional
Still missing that 'attack' fn, though :(
This commit is contained in:
parent
42b8afdecf
commit
545f8b4366
21
lib/Tank.ts
21
lib/Tank.ts
@ -1,4 +1,6 @@
|
||||
import { setStats, isLive, isOther, critMultiplier } from "./helpers";
|
||||
import { doIf, tap } from "./combinators";
|
||||
import { isLive, setProp, dealDamageToRandom, isReadyToAttack } from "./helpers";
|
||||
import { mapR, pipe } from "./reducers";
|
||||
|
||||
export interface ITank {
|
||||
name: string;
|
||||
@ -13,16 +15,15 @@ export const buildTank: BuildTank = (name) => ({
|
||||
attackDelay: 0,
|
||||
} as ITank);
|
||||
|
||||
type Attack = (_: ITank[], tank: ITank, tIndex: number, tanks: ITank[]) => ITank[];
|
||||
type Attack = (_prevTanks: ITank[], tank: ITank, tIndex: number, tanks: ITank[]) => ITank[];
|
||||
const attack: Attack = (_acc, tank, _iTank, tanks) => {
|
||||
// [TODO]: Refactor this imperative block
|
||||
if (tank.attackDelay === 0) {
|
||||
const target = tanks.filter(isOther(tank.name))[Math.floor(Math.random() * tanks.length)];
|
||||
const attackDamage = critMultiplier(tank.health) * tank.health / 100;
|
||||
target.health -= attackDamage;
|
||||
};
|
||||
|
||||
return tanks.map(setStats);
|
||||
tap(
|
||||
doIf(
|
||||
isReadyToAttack,
|
||||
dealDamageToRandom(tanks)
|
||||
)
|
||||
)(tank);
|
||||
return mapR(setProp("attackDelay", tank))(tanks);
|
||||
};
|
||||
|
||||
type Attacks = (tanks: ITank[]) => ITank[];
|
||||
|
7
lib/combinators.ts
Normal file
7
lib/combinators.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const tap = (fn) => (input) => {
|
||||
fn(input);
|
||||
return input;
|
||||
};
|
||||
|
||||
export const doIf = (fn, pred) => (input) =>
|
||||
pred ? fn(input) : input;
|
@ -1,17 +1,27 @@
|
||||
import { ITank } from "./Tank";
|
||||
import { filterR, pipe } from "./reducers";
|
||||
|
||||
type CritMultiplier = (health: number) => number;
|
||||
export const critMultiplier: CritMultiplier = (health) =>
|
||||
Math.floor(Math.random() * 10) >= 10 - health / 10 ? 1 : 2;
|
||||
|
||||
type SetStats = (tank: ITank) => ITank;
|
||||
export const setStats: SetStats = (tank) => ({
|
||||
...tank,
|
||||
attackDelay: tank.attackDelay === 0 ? Math.floor(tank.health / 10) : tank.attackDelay - 1,
|
||||
} as ITank);
|
||||
type PickRandom = <T>(arr: T[]) => T;
|
||||
export const pickRandom: PickRandom = (arr) =>
|
||||
arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
export const setProp = (prop, val) => (obj) => obj[prop] = val;
|
||||
|
||||
type IsLive = (tank: ITank) => boolean;
|
||||
export const isLive: IsLive = (tank) => tank.health >= 0;
|
||||
|
||||
type IsOther = (name: string) => (tank: ITank) => boolean;
|
||||
export const isOther: IsOther = (name) => (tank) => tank.name !== name;
|
||||
|
||||
export const isReadyToAttack = (tank: ITank) => tank.attackDelay === 0;
|
||||
|
||||
type DealDamageToRandom = (tanks: ITank[]) => (tank: ITank) => void;
|
||||
export const dealDamageToRandom: DealDamageToRandom = (tanks) => (tank) => {
|
||||
const target = pipe(filterR(isOther(tank.name)), pickRandom)(tanks);
|
||||
const attackDamage = critMultiplier(tank.health) * tank.health / 100;
|
||||
setProp("health", target.health - attackDamage)(target);
|
||||
};
|
||||
|
10
lib/reducers.ts
Normal file
10
lib/reducers.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export const pipe = (...fns) => (input) =>
|
||||
fns.reduce((acc, fn) => fn(acc), input);
|
||||
|
||||
export const redFn = (acc, x) => [...acc, x];
|
||||
|
||||
export const mapR = (fn) => (input) =>
|
||||
input.reduce((acc, x) => [...acc, fn(x)], []);
|
||||
|
||||
export const filterR = (pred) => (input) =>
|
||||
input.reduce((acc, x) => pred(x) ? [...acc, x] : acc ,[]);
|
Loading…
Reference in New Issue
Block a user