Skip to content

Latest commit

 

History

History
158 lines (111 loc) · 5.76 KB

README.md

File metadata and controls

158 lines (111 loc) · 5.76 KB

Farm the Gap: A strategy game and learning platform to feed the future.

Developed with the software and tools below

Svelte Badge Typescript Badge Sass Badge

Promotional image of the game

📍 Overview

Farm The Gap, a new digital puzzle game from The Plotline, gives you the keys to a virtual global farm. Modeled on real-world data, the game’s objective is to close a 50% “food gap” by simply changing what we grow and eat.

This repository contains all the source code and data for the game.

👾 Development

System requirements

  • Node v20+
  • npm/pnpm

Steps

  1. Clone the repo and run npm install to install dependencies
  2. Start a development server: npm run dev
  3. Build a production version: npm run build
  4. Preview the production build: npm run preview.

Global state

The brains of the game are defined in src/lib/stores/state.ts.

In this file are five writable Svelte stores:

  1. $farm: The foods on the farm and the respective production outputs
  2. $gameState: Food inventory, current year, remaining undos
  3. $gameSettings: High-level global settings
  4. $userState: User preferences and interaction states
  5. $gameHistory: History of moves (foods added/removed and where)

The first three stores feed into a derived Svelte store called $successMetrics. This store monitors the overall game status (win/loss) and the warning or fail states of each individual game metric (protein supply, emissions, etc). Any changes in the dependant stores triggers a recalculation of the derived store.

Data types

Global types and class declarations can be found in src/ambient.d.ts. Some important data structures:

Farm

class Farm {
  constructor(settings: GameSettings | null)

  // properties
  initialState: FarmState
  grid: FarmGrid
  items: string[]
  rows: number
  cols: number

  // methods
  getInitialState(): FarmState
  getFarmMetric(fn: (item: Food) => number): FarmMetric
  plantCrop(x: number, y: number, foodItem: Food): void
  getTotalSum(fn: (item: Food) => number): number
  getSumByFoodType(fn: (item: Food) => number): FarmGridFoodList[]

  // getters
  readonly yield: FarmMetric
  readonly landUse: FarmMetric
  readonly waterUse: FarmMetric
  readonly emissions: FarmMetric
  readonly eutrophy: FarmMetric
  readonly protein: FarmMetric
  readonly calories: FarmMetric
  readonly foodChanges: Count[]
}

Failure metrics

interface FailureMetric {
  value: number
  key: FailureMetricKey
  label: string
  suffix: string
  limit: number
  objective: string
  warn: boolean
  fail: boolean
  history: number[]
  farmMetricKey: FarmMetricKey
  foodMetricKey: keyof Food
  chartSettings: LineChartSettings
}

High-level game status

interface SuccessMetrics {
  hectaresPerPerson: number
  peopleAdequateCalories: number
  calorieProductionChange: number
  caloriesPerPersonPerDayValue: number
  proteinPerPersonPerDay: FailureMetric
  emissionsChange: FailureMetric
  waterUseChange: FailureMetric
  eutrophyChange: FailureMetric
  hasSucceeded: boolean
  hasFailed: boolean
}

Source data

Foods

I had to whittle down the hundreds of foods eaten globally into a sensible list of groups for easy gameplay. That involved making decisions about how to group and categorize foods, and finding the optimal trade-off between simplicity and accuracy. I arrived at the 13 foods and food groups in the stats table below.

Find these defined in src/lib/data/foods.json.

Food globalLand (%) kgYieldPerHa caloriesPerKg proteinPerKg emissionsPerKg waterUsePerKg eutrophyPerKg landPerKg
🐄 Beef 53 50 2,430 175 95 2494 428.7 295.3
🐑 Lamb 9 27 2,550 171 39.7 1803 97.1 369.8
🥛 Dairy 6 2,458 610 32.7 3.7 310 11.5 4.1
🌾 Rice 6 4,740 3,590 70.4 3.9 1,586 26.5 2.9
🍞 Wheat 6 3,483 3,700 151 1.6 648 7.2 3.9
🐖 Pork 4 737 2,280 178 9.8 1292 60.9 13.6
🥜 Nuts* 2 1,600 5,930 206.7 1.8 2993 16.6 11
🫘 Legumes* 3 1,896 3093 192 1.4 52 11.7 16.4
🐓 Poultry 3 1,200 1,330 179 8.2 483 34.3 8.3
🌽 Corn 2 5,847 3,640 62 1.7 216 4 2.9
🥦 Vegetables* 2 19,862 663 16.7 0.5 48 1.9 0.4
🍊 Fruit* 2 13,655 418 6.8 1.1 186 3.5 1
🥚 Eggs 2 1,465 1,430 124 4.4 830 20 6.8

Nuts impact data is the average of Nuts and Groundnuts (commodity data); nutrition data is the average of raw peanuts, almonds, and cashews.

Legumes data is a weighted average of Beans (75%), Chickpeas (10%), Lentils (5%), Garden Peas (10%)

Vegetables impact data is the weighted average of Root Vegetables (75%), Other Vegetables (20%), and Brassicas (5%). Nutrition data is the weighted average of gold potatoes, mature carrots and raw broccoli.

Fruit impact data is weighted average of Apples (11%), Bananas (14%), Berries (1%), Citrus Fruit (18%), Tomatoes (21%), and Other Fruit (35%) (commodity data). Nutritional data is weighted average of red delicious apples, bananas, strawberries, navel oranges, roma tomatoes and bartlett pears.