Skip to main content

The Narrow Trail

A Learning TypeScript > Unions and Literals 🍲 entree project.

Greetings, wilderness pioneers. You've come to most traitorous part of your journey west: the Narrow Trail. This legendary path winds takes a week to cross but is notoriously difficult to bring supplies on. Choose your actions on the trail wisely -- or perish.

...or at least, that's the marketing material for our in-development video game. This project will have you implementing a game function in TypeScript to help us get to our first demo. We'd do it ourselves, except we need someone who's learned about how unions, literals, and type narrowing work in TypeScript. That's you!

Oh, and one more catch: don't use the string primitive type. Use string literals instead wherever reasonable. We want our types to be exact. You can still use number if you want for numeric values.

Setup

If you haven't yet, set up the github.com/LearningTypeScript/projects repository locally.

shell
git clone https://github.com/LearningTypeScript/projects learning-typescript-projects
cd learning-typescript-projects
npm i
shell
git clone https://github.com/LearningTypeScript/projects learning-typescript-projects
cd learning-typescript-projects
npm i

Open your editor in this project's directory:

shell
code projects/unions-and-literals/the-narrow-trail
shell
code projects/unions-and-literals/the-narrow-trail

In one terminal, run the TypeScript compiler via the tsc script. For example, to start the TypeScript compiler in watch mode:

shell
npm run tsc -- --watch
shell
npm run tsc -- --watch

In another terminal, run Jest via the test script. For example, to start tests in watch mode:

shell
npm run test -- --watch
shell
npm run test -- --watch

Specification

Take a look at ./src/index.ts. It contains a runCommands() function you'll be working within.

Don't worry if you haven't covered functions in TypeScript yet. This project doesn't require knowing about how TypeScript works with them.

The game logic you're to write will keep track of four pieces of state:

  • Available Resource: Which of Food or Water will be available to resupply (see later), initially without a value
  • Day: What day of travel it is, initially 1
  • Food: A numeric value for how much food the player has left, initially 5
  • Water: A numeric value for how much water the player has left, initially 5

The goal of the game is for the player to still have both Food and Water after Day passes 7.

Your logic will continuously generate a random number between 1 and 6 to simulate a dice roll for a new day. Each day, one of the following commands will happen based on that rolled number:

  • 1, Food: Subsequent Resupply rolls will increase the player's Food supplies
  • 2, Water: Subsequent Resupply rolls will increase the player's Water supplies
  • 3-6, Resupply:
    • If no Available Resource value is set: set Available Resource to Food if the rolled number is even or Water if the rolled number is odd
    • If an Available Resource value is set: increase the corresponding resource by the rolled number, then unset the Available Resource value.

After the dice roll actions are completed, decrease both food and water by 1. If either is 0 then return false.

Once the Day state passes 7 (the player has lasted 7 days with sufficient supplies), return true.

Examples

Here's a step-by-step example of a player losing the game:

DayRollChangeNew Food StateNew Water State
13Available Resource is now Water44
24Increase Water by 437
34Available Resource is now Food26
41Available Resource is (still) Food15
52Available Resource is now Water0 💀4

Here's a step-by-step example of a player winning the game:

DayRollChangeNew Food StateNew Water State
11Available Resource is now Food44
23Increase Food by 363
35Available Resource is now Water52
42Available Resource is (still) Water41
54Increase Water by 434
66Available Resource is now Food23
71Available Resource is (still) Food12

Notes

Note: your terminal should be in the the-narrow-trail directory, not the root repository's directory.

  • Everything you write should be within the runCommands function.
  • You don't need to create any new arrays, functions or objects.