From 32879581e53fae5e684c24b44433172d8375d69e Mon Sep 17 00:00:00 2001 From: Lizzy Hunt Date: Mon, 11 Mar 2024 16:22:06 -0600 Subject: [PATCH] support underscores in function application, add sign entity --- public/assets/sign.png | Bin 0 -> 996 bytes src/components/GameCanvas.tsx | 2 +- src/engine/TheAbstractionEngine.ts | 2 +- src/engine/config/sprites.ts | 10 +++++ src/engine/entities/EntityNames.ts | 1 + src/engine/entities/FunctionApplication.ts | 16 +++++-- src/engine/entities/FunctionBox.ts | 11 +++-- src/engine/entities/Sign.ts | 49 +++++++++++++++++++++ src/engine/entities/index.ts | 1 + src/engine/levels/Tutorial.ts | 6 ++- src/interpreter/PeggyParser.js | 2 +- src/interpreter/parser.ts | 8 +++- 12 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 public/assets/sign.png create mode 100644 src/engine/entities/Sign.ts diff --git a/public/assets/sign.png b/public/assets/sign.png new file mode 100644 index 0000000000000000000000000000000000000000..a778b3bc151924c9579e6d867f4b6ded03764720 GIT binary patch literal 996 zcmVPx#1am@3R0s$N2z&@+hyVZsjY&j7RCr$Po!NEkFbqWPUQ@y=BPFEQ|+zXN}@pXUEx1t0)w2EZ2ZRsFwg z3AA^pmI?NOVC_F@#svRkLX-Rn0T$f@KmaEJw9TI+k)vly4VN|Zga5choZbIVdjJU# z0kCEOR8IhA0!X#)sGFxfku@dI+QENpf!X~J0e<`n0b=L>+NQ^Q4t+KQ zf`6=AM$Y;l0yq@_0u(2}Y&EZRvsblKAnn$O)k`1=zgqzyz?>F<0LS+R-8I9^>F(!M zYqkG2!dp|$Vju7yU+9AXKaYSyfNu*_O91W?$hrxXYV7Qcsol&MZI|{E5+3kBK2vUu zo3ruZ^)CcSIt79NixR-f(9v$6)=oLJb}Md8DXuCpG<;h7s`%XsU^N5;80+}~Ex@&Q ztKVl!0BHp98Z5iN=3uQodwtpSYxuPG?Db{OFX4j#&OJc3qq64L0$gj)T34@m%M!rq zSZlvt4r}#4R$SJ8t=83R9u3#>3ZNNaU$b7dNzDof@c;d!oA_Fk%^|Y}MDz-GbX-;d zN9T>=h>nY{Gi#g`2L#x8z-qWG$F-U_iX%F%)w)~FW5pr90eZA!Ovx}=>&%+Bm4ma7 z8>`@l0767o34q>-WwZp~{sus=z>xk&GGMR03i$h6;Opgo2;fXf5TG~#yprjRuix&y zGJ14<`*GfkrTs7X`+T9utpE_<*a8rs?X$wY59Z;GzhC0I`?xwssc;Xl+sBd=LNv@IB)HWML1~=d?%4ODKRb zW4G>x0-yjW019xq0-^w|Q@e3K6aWQ40Z;%GfKA}Fn?R#rHSacx0(LKfMgiX3qs9rr zKSt@ZxeEdq1GiN-2mk@7{i*#gul-SgRw>;%4+?++pa3WU3c%?Pr$0{dOzGZz6P$vA zNwGlC0uUf*IEJlZ0SK^$A3+hc00amcj$vz900OMxM^FSU00DxAW7rxN_yEmJXng_u S@Lm7_002ovPDHLkV1fWwV6P { const canvasRef = useRef(null); const [game, setGame] = useState(); - const [ready, setReady] = useState(false); + const [ready, setReady] = useState(true); // false); const [loading, setLoading] = useState(true); useEffect(() => { diff --git a/src/engine/TheAbstractionEngine.ts b/src/engine/TheAbstractionEngine.ts index 2c29406..4a0effa 100644 --- a/src/engine/TheAbstractionEngine.ts +++ b/src/engine/TheAbstractionEngine.ts @@ -33,7 +33,7 @@ export class TheAbstractionEngine { const facingDirectionSystem = new FacingDirection(inputSystem); [ - new Level(LevelNames.LevelSelection), + new Level(LevelNames.Tutorial), inputSystem, facingDirectionSystem, new Grid( diff --git a/src/engine/config/sprites.ts b/src/engine/config/sprites.ts index f8912d5..481dbb9 100644 --- a/src/engine/config/sprites.ts +++ b/src/engine/config/sprites.ts @@ -11,6 +11,7 @@ export enum Sprites { BUBBLE, PORTAL, GRASS, + SIGN, } export interface SpriteSpec { @@ -126,3 +127,12 @@ const grassSpriteSpec = { sheet: "/assets/grass.png", }; SPRITE_SPECS.set(Sprites.GRASS, grassSpriteSpec); + +const signSpriteSpec = { + msPerFrame: 200, + width: 64, + height: 64, + frames: 3, + sheet: "/assets/sign.png", +}; +SPRITE_SPECS.set(Sprites.SIGN, signSpriteSpec); diff --git a/src/engine/entities/EntityNames.ts b/src/engine/entities/EntityNames.ts index b4fbbb2..17b5519 100644 --- a/src/engine/entities/EntityNames.ts +++ b/src/engine/entities/EntityNames.ts @@ -10,4 +10,5 @@ export namespace EntityNames { export const Particles = "Particles"; export const Portal = "Portal"; export const Grass = "Grass"; + export const Sign = "Sign"; } diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts index d907eca..175534c 100644 --- a/src/engine/entities/FunctionApplication.ts +++ b/src/engine/entities/FunctionApplication.ts @@ -34,6 +34,10 @@ import { interpret, } from "../../interpreter"; +const APPLICATION_RESULTS: Record Entity> = { + _KEY: (gridPosition: Coord2D) => new Key(gridPosition), +}; + export class FunctionApplication extends Entity { private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec; @@ -43,7 +47,9 @@ export class FunctionApplication extends Entity { super(EntityNames.FunctionApplication); this.symbolTable = new SymbolTable(); - this.symbolTable.add("key"); + Object.keys(APPLICATION_RESULTS).forEach((key) => { + this.symbolTable.add(key); + }); const dimension = { width: FunctionApplication.spriteSpec.width, @@ -109,9 +115,10 @@ export class FunctionApplication extends Entity { ComponentNames.LambdaTerm ); const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code); + let result: DebrujinifiedLambdaTerm | null = null; try { - result = interpret(newCode, this.symbolTable); + result = interpret(newCode, this.symbolTable, true); } catch (e) { console.error(e); fail(); @@ -131,8 +138,9 @@ export class FunctionApplication extends Entity { applicationResultingEntity = new FunctionBox(grid.gridPosition, code); } else if ("name" in result) { const { name } = result; - if (name === "key") { - applicationResultingEntity = new Key(grid.gridPosition); + const entityFactory = APPLICATION_RESULTS[name]; + if (entityFactory) { + game.addEntity(entityFactory(nextPosition)); } } else { fail(); diff --git a/src/engine/entities/FunctionBox.ts b/src/engine/entities/FunctionBox.ts index dac2174..7b70567 100644 --- a/src/engine/entities/FunctionBox.ts +++ b/src/engine/entities/FunctionBox.ts @@ -67,7 +67,10 @@ export class FunctionBox extends Entity { } } -export const makeLambdaTermHighlightComponent = (entity: Entity) => { +export const makeLambdaTermHighlightComponent = ( + entity: Entity, + text?: string +) => { const onUnhighlight = () => { closeModal(); entity.removeComponent(ComponentNames.Interactable); @@ -87,9 +90,9 @@ export const makeLambdaTermHighlightComponent = (entity: Entity) => { return; } - const code = entity.getComponent( - ComponentNames.LambdaTerm - )!.code; + const code = + text ?? + entity.getComponent(ComponentNames.LambdaTerm)!.code; openModal( `

${code}


` ); diff --git a/src/engine/entities/Sign.ts b/src/engine/entities/Sign.ts new file mode 100644 index 0000000..a11fba6 --- /dev/null +++ b/src/engine/entities/Sign.ts @@ -0,0 +1,49 @@ +import { Entity, EntityNames, makeLambdaTermHighlightComponent } from "."; +import { BoundingBox, Colliding, Grid, Sprite } from "../components"; +import { IMAGES, SPRITE_SPECS, SpriteSpec, Sprites } from "../config"; +import { Coord2D } from "../interfaces"; + +export class Sign extends Entity { + private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( + Sprites.SIGN + ) as SpriteSpec; + + private text: string; + + constructor(text: string, gridPosition: Coord2D) { + super(EntityNames.Sign); + this.text = text; + + const dimension = { + width: Sign.spriteSpec.width, + height: Sign.spriteSpec.height, + }; + + this.addComponent( + new Sprite( + IMAGES.get(Sign.spriteSpec.sheet)!, + { x: 0, y: 0 }, + dimension, + Sign.spriteSpec.msPerFrame, + Sign.spriteSpec.frames + ) + ); + + this.addComponent( + new BoundingBox( + { + x: 0, + y: 0, + }, + dimension, + 0 + ) + ); + + this.addComponent(new Grid(gridPosition)); + + this.addComponent(new Colliding()); + + this.addComponent(makeLambdaTermHighlightComponent(this, this.text)); + } +} diff --git a/src/engine/entities/index.ts b/src/engine/entities/index.ts index 260db5b..284a2bd 100644 --- a/src/engine/entities/index.ts +++ b/src/engine/entities/index.ts @@ -11,3 +11,4 @@ export * from "./FunctionApplication"; export * from "./Particles"; export * from "./Portal"; export * from "./Grass"; +export * from "./Sign"; diff --git a/src/engine/levels/Tutorial.ts b/src/engine/levels/Tutorial.ts index 694c8ff..b720346 100644 --- a/src/engine/levels/Tutorial.ts +++ b/src/engine/levels/Tutorial.ts @@ -6,6 +6,7 @@ import { LambdaFactory, LockedDoor, Player, + Sign, Wall, } from "../entities"; @@ -16,14 +17,15 @@ export class Tutorial extends Level { public init(game: Game): void { const entities = [ - new Player({ x: 2, y: 2 }), + new Sign("TODO: Explain entities", { x: 4, y: 3 }), new Wall({ x: 10, y: 9 }), new Wall({ x: 10, y: 11 }), new Wall({ x: 11, y: 10 }), new Curry({ x: 10, y: 10 }), new LockedDoor({ x: 9, y: 10 }), new LambdaFactory({ x: 6, y: 3 }, "// TODO: Remove line\n(λ (x) . x)", 3), - new FunctionApplication({ x: 6, y: 6 }, "(_INPUT key)"), + new FunctionApplication({ x: 6, y: 6 }, "(_INPUT _KEY)"), + new Player({ x: 2, y: 2 }), ]; entities.forEach((entity) => game.addEntity(entity)); diff --git a/src/interpreter/PeggyParser.js b/src/interpreter/PeggyParser.js index 121cf9d..f5376b3 100644 --- a/src/interpreter/PeggyParser.js +++ b/src/interpreter/PeggyParser.js @@ -215,7 +215,7 @@ export default (function () { var peg$c2 = "."; var peg$c3 = "\r\n"; - var peg$r0 = /^[a-zA-Z0-9]/; + var peg$r0 = options.allowUnderscores ? /^[a-zA-Z0-9_]/ : /^[a-zA-Z0-9]/; var peg$r1 = /^[\\\u03BB]/; var peg$r2 = /^[\t-\n ]/; diff --git a/src/interpreter/parser.ts b/src/interpreter/parser.ts index 5e3be0f..930b953 100644 --- a/src/interpreter/parser.ts +++ b/src/interpreter/parser.ts @@ -30,6 +30,10 @@ export const isVariable = (term: LambdaTerm): term is Variable => { return typeof term === "string"; }; -export const parse = (term: string, library = false) => { - return peggyParser.parse(term, { peg$library: library }); +export const parse = ( + term: string, + allowUnderscores = false, + library = false +) => { + return peggyParser.parse(term, { peg$library: library, allowUnderscores }); };