summaryrefslogtreecommitdiff
path: root/src/engine/entities/FunctionApplication.ts
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-07 20:45:47 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-07 20:45:47 -0700
commite6e29440563e33bb67e0ad51f9fb6c5c2c3fe809 (patch)
tree5deaee322ff1a039dc44a3cb52ecc48a671fda2a /src/engine/entities/FunctionApplication.ts
parent823620b2a6ebb7ece619991e47a37ad46542b69f (diff)
downloadthe-abstraction-engine-e6e29440563e33bb67e0ad51f9fb6c5c2c3fe809.tar.gz
the-abstraction-engine-e6e29440563e33bb67e0ad51f9fb6c5c2c3fe809.zip
level one (applications prototype finished!)
Diffstat (limited to 'src/engine/entities/FunctionApplication.ts')
-rw-r--r--src/engine/entities/FunctionApplication.ts180
1 files changed, 178 insertions, 2 deletions
diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts
index 31e3490..24e4eec 100644
--- a/src/engine/entities/FunctionApplication.ts
+++ b/src/engine/entities/FunctionApplication.ts
@@ -1,7 +1,183 @@
-import { Entity, EntityNames } from ".";
+import {
+ Entity,
+ EntityNames,
+ FunctionBox,
+ Key,
+ Particles,
+ makeLambdaTermHighlightComponent,
+} from ".";
+import {
+ BoundingBox,
+ Colliding,
+ ComponentNames,
+ Grid,
+ LambdaTerm,
+ Sprite,
+} from "../components";
+import {
+ Failure,
+ IMAGES,
+ LambdaTransformSound,
+ SOUNDS,
+ SPRITE_SPECS,
+ SpriteSpec,
+ Sprites,
+} from "../config";
+import { Coord2D, Direction } from "../interfaces";
+import { Game } from "..";
+import { Grid as GridSystem, SystemNames } from "../systems";
+import { colors } from "../utils";
+import {
+ DebrujinifiedLambdaTerm,
+ SymbolTable,
+ emitNamed,
+ interpret,
+} from "../../interpreter";
export class FunctionApplication extends Entity {
- constructor() {
+ private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec;
+
+ private symbolTable: SymbolTable;
+
+ constructor(gridPosition: Coord2D, lambdaTerm: string) {
super(EntityNames.FunctionApplication);
+
+ this.symbolTable = new SymbolTable();
+ this.symbolTable.add("key");
+
+ const dimension = {
+ width: FunctionApplication.spriteSpec.width,
+ height: FunctionApplication.spriteSpec.height,
+ };
+ this.addComponent(
+ new BoundingBox(
+ {
+ x: 0,
+ y: 0,
+ },
+ dimension,
+ 0,
+ ),
+ );
+
+ this.addComponent(new Grid(gridPosition));
+
+ this.addComponent(new LambdaTerm(lambdaTerm));
+
+ this.addComponent(
+ new Sprite(
+ IMAGES.get(FunctionApplication.spriteSpec.sheet)!,
+ { x: 0, y: 0 },
+ dimension,
+ FunctionApplication.spriteSpec.msPerFrame,
+ FunctionApplication.spriteSpec.frames,
+ ),
+ );
+
+ this.addComponent(new Colliding(this.handleCollision.bind(this)));
+
+ this.addComponent(makeLambdaTermHighlightComponent(this));
+ }
+
+ public handleCollision(game: Game, entity: Entity) {
+ if (entity.name !== EntityNames.FunctionBox) {
+ return;
+ }
+
+ const entityGrid = entity.getComponent<Grid>(ComponentNames.Grid);
+ if (entityGrid.movingDirection !== Direction.NONE) {
+ // prevent recursive functionBox -> application creation
+ return;
+ }
+
+ const grid = this.getComponent<Grid>(ComponentNames.Grid);
+ const gridSystem = game.getSystem<GridSystem>(SystemNames.Grid);
+ const fail = () => {
+ entityGrid.movingDirection = gridSystem.oppositeDirection(
+ entityGrid.previousDirection,
+ );
+ entity.addComponent(entityGrid);
+
+ const failureSound = SOUNDS.get(Failure.name)!;
+ failureSound.play();
+ };
+
+ const applicationTerm = this.getComponent<LambdaTerm>(
+ ComponentNames.LambdaTerm,
+ );
+ const functionTerm = entity.getComponent<LambdaTerm>(
+ ComponentNames.LambdaTerm,
+ );
+ const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code);
+ let result: DebrujinifiedLambdaTerm | null = null;
+ try {
+ result = interpret(newCode, this.symbolTable);
+ } catch (e) {
+ console.error(e);
+ fail();
+ return;
+ }
+
+ const { dimension } = gridSystem;
+ const nextPosition = gridSystem.getNewGridPosition(
+ grid.gridPosition,
+ entityGrid.previousDirection,
+ );
+
+ let applicationResultingEntity: Entity | null = null; // this should be its own function
+ if ("abstraction" in result) {
+ const code = emitNamed(result);
+
+ applicationResultingEntity = new FunctionBox(grid.gridPosition, code);
+ } else if ("name" in result) {
+ const { name } = result;
+ if (name === "key") {
+ applicationResultingEntity = new Key(grid.gridPosition);
+ }
+ } else {
+ fail();
+ return;
+ }
+
+ game.removeEntity(entity.id);
+ if (applicationResultingEntity) {
+ const grid = applicationResultingEntity.getComponent<Grid>(
+ ComponentNames.Grid,
+ );
+ grid.movingDirection = entityGrid.previousDirection;
+ applicationResultingEntity.addComponent(grid);
+
+ game.addEntity(applicationResultingEntity);
+ }
+
+ this.playTransformSound();
+ const particles = new Particles({
+ center: gridSystem.gridToScreenPosition(nextPosition),
+ spawnerDimensions: {
+ width: dimension.width / 2,
+ height: dimension.height / 2,
+ },
+ particleCount: 10,
+ spawnerShape: "circle",
+ particleShape: "circle",
+ particleMeanSpeed: 0.25,
+ particleSpeedVariance: 0.15,
+ particleMeanLife: 150,
+ particleMeanSize: 2,
+ particleSizeVariance: 1,
+ particleLifeVariance: 20,
+ particleColors: [
+ colors.lightAqua,
+ colors.blue,
+ colors.green,
+ colors.lightGreen,
+ ],
+ });
+ game.addEntity(particles);
+ }
+
+ private playTransformSound() {
+ const audio = SOUNDS.get(LambdaTransformSound.name)!;
+ audio.play();
}
}