Files
tps/src/modules/heijkunka/heijunka-store.ts

179 lines
4.5 KiB
TypeScript

import {
NUMBER_OF_DAYS,
NUMBER_OF_HOURS_PER_DAY
} from '@/modules/heijkunka/heijunka-config'
import { ProductType } from '@/modules/heijkunka/types/product-type'
import { getMean, pickRandomElement } from '@/utils'
import { defineStore } from 'pinia'
type Order = {
status: 'requested' | 'received'
leadTime: number
product: ProductType
}
type Inventory = {
shirt: number
jeans: number
shoes: number
hat: number
}
type HeijunkaState = {
money: number
inventory: Inventory
orders: Order[]
planning: ProductType[]
meta: {
currentHour: number
}
}
const getInventoryByProduct = (
product: ProductType,
planning: ProductType[],
currentDay: number
): number => {
const inventory = planning.filter(
(p, index) =>
index >= (currentDay % NUMBER_OF_DAYS) * NUMBER_OF_HOURS_PER_DAY &&
index < ((currentDay % NUMBER_OF_DAYS) + 1) * NUMBER_OF_HOURS_PER_DAY &&
p === product
).length
return inventory
}
const initialInventory: Inventory = {
shirt: 0,
jeans: 0,
shoes: 0,
hat: 0
}
export const useHeijunkaStore = defineStore('heijunka', {
state: (): HeijunkaState => ({
money: 100,
inventory: { ...initialInventory },
orders: [],
planning: [],
meta: {
currentHour: 0
}
}),
actions: {
newHour() {
// End of the production
if (this.gameEnded) {
return
}
this.meta.currentHour++
// Add to inventory every day
if (this.meta.currentHour % NUMBER_OF_HOURS_PER_DAY === 0) {
this.inventory = {
shirt:
this.inventory.shirt +
getInventoryByProduct('shirt', this.planning, this.currentDay),
jeans:
this.inventory.jeans +
getInventoryByProduct('jeans', this.planning, this.currentDay),
shoes:
this.inventory.shoes +
getInventoryByProduct('shoes', this.planning, this.currentDay),
hat:
this.inventory.hat +
getInventoryByProduct('hat', this.planning, this.currentDay)
}
}
// Each non received demand gains one hour of lead time
this.orders = this.orders.map((order): Order => {
return {
...order,
leadTime:
order.status === 'received' ? order.leadTime : order.leadTime + 1
}
})
// New demand
const newDemand: Order = {
status: 'requested',
leadTime: 0,
product: pickRandomElement(
[
Array.from({ length: 5 }, (): ProductType => 'shirt'),
Array.from({ length: 3 }, (): ProductType => 'jeans'),
Array.from({ length: 2 }, (): ProductType => 'shoes'),
Array.from({ length: 2 }, (): ProductType => 'hat')
].flat()
)
}
this.orders.push(newDemand)
// Use the inventory to deliver orders
this.orders = this.orders.map((order, index): Order => {
const productInventory = this.inventory[order.product]
if (productInventory === 0) {
return order
}
const offset = this.orders.filter(
(o, i) => i < index && o.product !== order.product
).length
const newStatus =
index - offset < productInventory ? 'received' : 'requested'
return {
...order,
status: newStatus
}
})
},
reset() {
this.meta.currentHour = 0
this.planning = []
this.orders = []
this.inventory = { ...initialInventory }
},
simulateMonth() {
for (let index = 0; index < 80; index++) {
this.newHour()
}
}
},
getters: {
currentDay: (state) =>
Math.ceil(state.meta.currentHour / NUMBER_OF_HOURS_PER_DAY),
remainingInventory: (state): Inventory => ({
shirt: Math.max(
state.inventory.shirt -
state.orders.filter((o) => o.product === 'shirt').length,
0
),
jeans: Math.max(
state.inventory.jeans -
state.orders.filter((o) => o.product === 'jeans').length,
0
),
shoes: Math.max(
state.inventory.shoes -
state.orders.filter((o) => o.product === 'shoes').length,
0
),
hat: Math.max(
state.inventory.hat -
state.orders.filter((o) => o.product === 'hat').length,
0
)
}),
gameEnded: () => false,
// state.meta.currentHour >= NUMBER_OF_DAYS * NUMBER_OF_HOURS_PER_DAY,
meanLeadTime: (state) => getMean(state.orders.map((o) => o.leadTime))
}
})