support underscores in function application, add sign entity
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Elizabeth Hunt 2024-03-11 16:22:06 -06:00
parent 4da17f6ded
commit 32879581e5
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
12 changed files with 93 additions and 15 deletions

BIN
public/assets/sign.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

View File

@ -11,7 +11,7 @@ export interface GameCanvasProps {
export const GameCanvas = ({ width, height }: GameCanvasProps) => { export const GameCanvas = ({ width, height }: GameCanvasProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
const [game, setGame] = useState<TheAbstractionEngine>(); const [game, setGame] = useState<TheAbstractionEngine>();
const [ready, setReady] = useState(false); const [ready, setReady] = useState(true); // false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {

View File

@ -33,7 +33,7 @@ export class TheAbstractionEngine {
const facingDirectionSystem = new FacingDirection(inputSystem); const facingDirectionSystem = new FacingDirection(inputSystem);
[ [
new Level(LevelNames.LevelSelection), new Level(LevelNames.Tutorial),
inputSystem, inputSystem,
facingDirectionSystem, facingDirectionSystem,
new Grid( new Grid(

View File

@ -11,6 +11,7 @@ export enum Sprites {
BUBBLE, BUBBLE,
PORTAL, PORTAL,
GRASS, GRASS,
SIGN,
} }
export interface SpriteSpec { export interface SpriteSpec {
@ -126,3 +127,12 @@ const grassSpriteSpec = {
sheet: "/assets/grass.png", sheet: "/assets/grass.png",
}; };
SPRITE_SPECS.set(Sprites.GRASS, grassSpriteSpec); 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);

View File

@ -10,4 +10,5 @@ export namespace EntityNames {
export const Particles = "Particles"; export const Particles = "Particles";
export const Portal = "Portal"; export const Portal = "Portal";
export const Grass = "Grass"; export const Grass = "Grass";
export const Sign = "Sign";
} }

View File

@ -34,6 +34,10 @@ import {
interpret, interpret,
} from "../../interpreter"; } from "../../interpreter";
const APPLICATION_RESULTS: Record<string, (gridPosition: Coord2D) => Entity> = {
_KEY: (gridPosition: Coord2D) => new Key(gridPosition),
};
export class FunctionApplication extends Entity { export class FunctionApplication extends Entity {
private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec; private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec;
@ -43,7 +47,9 @@ export class FunctionApplication extends Entity {
super(EntityNames.FunctionApplication); super(EntityNames.FunctionApplication);
this.symbolTable = new SymbolTable(); this.symbolTable = new SymbolTable();
this.symbolTable.add("key"); Object.keys(APPLICATION_RESULTS).forEach((key) => {
this.symbolTable.add(key);
});
const dimension = { const dimension = {
width: FunctionApplication.spriteSpec.width, width: FunctionApplication.spriteSpec.width,
@ -109,9 +115,10 @@ export class FunctionApplication extends Entity {
ComponentNames.LambdaTerm ComponentNames.LambdaTerm
); );
const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code); const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code);
let result: DebrujinifiedLambdaTerm | null = null; let result: DebrujinifiedLambdaTerm | null = null;
try { try {
result = interpret(newCode, this.symbolTable); result = interpret(newCode, this.symbolTable, true);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
fail(); fail();
@ -131,8 +138,9 @@ export class FunctionApplication extends Entity {
applicationResultingEntity = new FunctionBox(grid.gridPosition, code); applicationResultingEntity = new FunctionBox(grid.gridPosition, code);
} else if ("name" in result) { } else if ("name" in result) {
const { name } = result; const { name } = result;
if (name === "key") { const entityFactory = APPLICATION_RESULTS[name];
applicationResultingEntity = new Key(grid.gridPosition); if (entityFactory) {
game.addEntity(entityFactory(nextPosition));
} }
} else { } else {
fail(); fail();

View File

@ -67,7 +67,10 @@ export class FunctionBox extends Entity {
} }
} }
export const makeLambdaTermHighlightComponent = (entity: Entity) => { export const makeLambdaTermHighlightComponent = (
entity: Entity,
text?: string
) => {
const onUnhighlight = () => { const onUnhighlight = () => {
closeModal(); closeModal();
entity.removeComponent(ComponentNames.Interactable); entity.removeComponent(ComponentNames.Interactable);
@ -87,9 +90,9 @@ export const makeLambdaTermHighlightComponent = (entity: Entity) => {
return; return;
} }
const code = entity.getComponent<LambdaTerm>( const code =
ComponentNames.LambdaTerm text ??
)!.code; entity.getComponent<LambdaTerm>(ComponentNames.LambdaTerm)!.code;
openModal( openModal(
`<div style="text-align:center"><p>${code}</p> <br> <button id="close">Close</button></div>` `<div style="text-align:center"><p>${code}</p> <br> <button id="close">Close</button></div>`
); );

View File

@ -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));
}
}

View File

@ -11,3 +11,4 @@ export * from "./FunctionApplication";
export * from "./Particles"; export * from "./Particles";
export * from "./Portal"; export * from "./Portal";
export * from "./Grass"; export * from "./Grass";
export * from "./Sign";

View File

@ -6,6 +6,7 @@ import {
LambdaFactory, LambdaFactory,
LockedDoor, LockedDoor,
Player, Player,
Sign,
Wall, Wall,
} from "../entities"; } from "../entities";
@ -16,14 +17,15 @@ export class Tutorial extends Level {
public init(game: Game): void { public init(game: Game): void {
const entities = [ 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: 9 }),
new Wall({ x: 10, y: 11 }), new Wall({ x: 10, y: 11 }),
new Wall({ x: 11, y: 10 }), new Wall({ x: 11, y: 10 }),
new Curry({ x: 10, y: 10 }), new Curry({ x: 10, y: 10 }),
new LockedDoor({ x: 9, y: 10 }), new LockedDoor({ x: 9, y: 10 }),
new LambdaFactory({ x: 6, y: 3 }, "// TODO: Remove line\n(λ (x) . x)", 3), 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)); entities.forEach((entity) => game.addEntity(entity));

View File

@ -215,7 +215,7 @@ export default (function () {
var peg$c2 = "."; var peg$c2 = ".";
var peg$c3 = "\r\n"; 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$r1 = /^[\\\u03BB]/;
var peg$r2 = /^[\t-\n ]/; var peg$r2 = /^[\t-\n ]/;

View File

@ -30,6 +30,10 @@ export const isVariable = (term: LambdaTerm): term is Variable => {
return typeof term === "string"; return typeof term === "string";
}; };
export const parse = (term: string, library = false) => { export const parse = (
return peggyParser.parse(term, { peg$library: library }); term: string,
allowUnderscores = false,
library = false
) => {
return peggyParser.parse(term, { peg$library: library, allowUnderscores });
}; };