import type { Get, Obj, Num, List, Union } from "./TypeUtils"; declare type PlayerState = { health: number; position: MapLevel | MapElement; inventory: GameItems[]; }; declare type GameItems = "Small Key" | "Spider Mask" | "Green Gem"; declare type GameState = [string, PlayerState]; declare type MapElementAction = [GameItems | undefined, keyof Actions]; declare type Wall = { type: "wall"; description: "It's a wall"; actions: {}; }; declare type Corridor = { type: "corridor"; target: TTarget; description: TDescription; actions: {}; }; declare type Room = { type: "room"; description: TDescription; insideDescription: TInsideDescription; actions: TActions; }; declare type Item = { type: "item"; description: TDescription; actions: TActions; }; declare type MapElement = Wall | Corridor | Room | Item; declare type InteractiveMapElement = Room | Item; declare type _MapLevel = [/* Left: */ MapElement, /* Forward: */ MapElement, /* Right: */ MapElement]; declare type MapLevel = { level: TLevel; actions: { left: [undefined, 0]; forward: [undefined, 1]; right: [undefined, 2]; }; }; declare type Actions = { "keyRoom.key": "Small Key" extends TPlayerState["inventory"][number] ? [ "You see nothing inside the drawer. You get back and exit the room, leaving the door open, as you found it.", Obj.Update ] : [ "You find a small key! You put it in your pocket and exit the room, leaving the door open, as you found it.", Obj.Update ]; "keyRoom.exit": [ `You leave the room.`, Obj.Update ]; "spidersRoomSouthDoor.runForDoor": [ "You make a run for the other door, only to find it locked. You get back and, as you leave the room, you are bitten and lose one hit point.", Obj.Update; position: GameMap[1]; }> ]; "spidersRoomSouthDoor.exit": [ "You go back to where you came from and avoid getting hurt.", Obj.Update ]; "spidersRoomEastDoor.runForDoor": [ "You make a run for the other door, and as you cross it you are bitten and lose one hit point.", Obj.Update; }> ]; "spidersRoom.putMask": [ "As soon as you put on the mask, the spiders gather around you. As you move, they spread out, making way for you. You focus your efforts on investigating the room and find a hidden passage that leads you to… the lost treasure of Anders Hejlsberg! You did it, adventurer! Now, go check the code.", never ]; "chest.unlock": "Spider Mask" extends TPlayerState["inventory"][number] ? [ "You grab the small key from your pocket; it fits in the chest lock. *click* Inside the chest you see nothing. You close the chest.", Obj.Update ] : [ "You grab the small key from your pocket; it fits in the chest lock. *click* Inside the chest you find a hairy mask with multiple eyes. You put it in your bag and close the chest.", Obj.Update ]; "chest.force": [ "As you rattle the chest's lock, a spider comes out of nowhere and bites you.", Obj.Update; }> ]; "chest.leave": [ "", Obj.Update ]; }; declare type GameMap = [ MapLevel<[ Room<"a half-opened door", "Opening the door, you find yourself in a room with a small desk. The desk has one drawer.", { "Open the drawer": [undefined, "keyRoom.key"]; "Exit the room": [undefined, "keyRoom.exit"]; }>, Corridor<"a dark and humid corridor.", GameMap[1]>, Wall ]>, MapLevel<[ Wall, Room<"a door - and you can feel a current of air coming through it", "You open the door to a room full of venomous spiders. There's another door on the right wall.", { "Reach for the other door": [undefined, "spidersRoomSouthDoor.runForDoor"]; "Exit from where you came": [undefined, "spidersRoomSouthDoor.exit"]; "Put on the mask": ["Spider Mask", "spidersRoom.putMask"]; }>, Corridor<"a tunnel that bifurcates", GameMap[2]> ]>, MapLevel<[ Corridor<"that the tunnel you're in continues", GameMap[3]>, Wall, Item<"Locked Chest", { "Use the Small key": ["Small Key", "chest.unlock"]; "Force it open": [undefined, "chest.force"]; "Leave it": [undefined, "chest.leave"]; }> ]>, MapLevel<[Corridor<"that to keep following the tunnel seems to be your only option", GameMap[4]>, Wall, Wall]>, MapLevel<[ Wall, Room<"a door - and you can feel a current of air current coming from below it", "You open the door to a completely dark room. As the door slams shut behind you, you notice another door on the left wall and… lots of venomous spiders", { "Exit through the other door": [undefined, "spidersRoomEastDoor.runForDoor"]; "Put on the mask": ["Spider Mask", "spidersRoom.putMask"]; }>, Wall ]> ]; declare type Directions = ["On your left you notice", "In front of you there's", "On your right you see"]; declare type DescribeMapLevel = TMapLevel["level"] extends infer TLevel ? List.Join<{ [Index in keyof TLevel]: TLevel[Index] extends Wall ? "" : TLevel[Index] extends MapElement ? `${Get} ${TLevel[Index]["description"]}.` : TLevel[Index]; }, " "> : never; declare type ListActions = Obj.KeyWithValue; declare type Move = Get extends infer TDirection ? Get extends infer TTargetElement ? TTargetElement extends Wall ? [`You can't go this way. ${DescribeMapLevel}`, TGameState[1]] : TTargetElement extends Corridor ? [DescribeMapLevel, Obj.Update] : TTargetElement extends Room ? [ `${TTargetElement["insideDescription"]}. Your available actions are: ${List.Join>, ", ">}`, Obj.Update ] : TTargetElement extends Item ? [ `You reach for the ${TTargetElement["description"]}. Your available actions are: ${List.Join>, ", ">}`, Obj.Update ] : TTargetElement : never : never; declare type CheckActionResult = TGameState[1] extends never ? TGameState : TGameState[1]["health"] extends 0 ? [`${TGameState[0]} You are dead - Game Over!`, null] : TGameState[1]["position"] extends MapLevel ? [`${TGameState[0]} ${DescribeMapLevel}`, TGameState[1]] : TGameState; export declare type Act, TPlayerState extends PlayerState = TGameState[1]> = TPlayerState["position"] extends infer TCurrentPosition ? TCurrentPosition extends MapLevel ? Move : TCurrentPosition extends InteractiveMapElement ? Actions[TCurrentPosition["actions"][TAction][1]] extends infer TSelectedAction ? TSelectedAction extends GameState ? CheckActionResult : never : never : never : never; declare type NewState = { health: 2; inventory: []; position: GameMap[0]; }; export declare type NewGame = [ `Welcome Adventurer. You locked yourself in this dungeon and you can't get out. ${DescribeMapLevel} Use the type Act.`, NewState ]; export {};