Files
vending-tycoon-cli/src/mockProcess.ts
2021-07-18 13:57:08 -06:00

318 lines
7.7 KiB
TypeScript

import mockData from './mockdata';
import * as cryptoRandomString from 'crypto-random-string';
import { uniqueNamesGenerator, Config, adjectives, names, colors } from 'unique-names-generator';
// function calculateBusinessDay(player: any) {
// let lineItems = [];
// for (let i in player.vendingMachines) {
// let machine = player.vendingMachines[i];
//
// }
// }
function handleEvent(eventLog: EventLog) {
if (eventLog.eventName === 'bought') {
let vendingMachine = findVendingMachine(eventLog.data.offer);
let selection = vendingMachine.selections.find((sel) => {
return sel.id === eventLog.data.selection;
});
selection.current = selection.current - 1;
}
}
function findVendingMachine(id: string) {
for (let i in mockData.players) {
let player = mockData.players[i];
for (let j in player.vendingMachines) {
if (player.vendingMachines[i].id === id) {
return player.vendingMachines[i];
}
}
}
}
function personPassesByVendingMachine(person: Person, machine): EventLog {
let isThursty: boolean = Math.random() < person.thirst;
let availableSelections = machine.selections.filter((selection) => {
return !!selection.current;
});
if (isThursty) {
if (!availableSelections.length) {
return wontBuy('NoneAvailable');
}
// pick a drink
let acceptableOptions = availableSelections.filter((option) => {
return person.preferences.indexOf(option.drink) !== -1;
});
if (!acceptableOptions.length) {
return wontBuy('NoPreferredDrinks');
}
let options = acceptableOptions.filter((selection) => {
return selection.price <= person.highestPrice;
});
if (!options.length) {
return wontBuy('HighPrice');
}
let picked = pick(acceptableOptions);
let selectionTypeData = getSelectionType(picked.type);
return {
eventName: 'bought',
data: {
reason: 'Thirsty',
amount: picked.price,
drink: picked.drink,
selection: picked.id,
selectionType: picked.type,
oz: selectionTypeData ? selectionTypeData.oz : 12,
person: person.id,
offer: machine.id,
}
};
} else {
return wontBuy('NotThirsty');
}
function wontBuy(reason): EventLog {
return {
eventName: 'wontBuy',
data: {
reason: reason,
amount: 0,
drink: 'none',
selection: 'none',
selectionType: 'none',
oz: 0,
person: person.id,
offer: machine.id,
}
};
}
}
function generatePerson(location: Location): Person {
let money = Math.random() * 100;
return {
id: genId('person'),
name: genPersonName(),
preferences: genPreferences(),
highestPrice: (money / 20),
money: money,
thirst: clamp(location.dailyTraffic.thirstBonus + (Math.random() / 10))
}
}
function genId(prefix: string): string {
return `${prefix}-${cryptoRandomString({length: 6, type: 'distinguishable'})}`;
}
function genPersonName(): string {
const config: Config = {
dictionaries: [names, names],
length: 2,
separator: ' '
};
return uniqueNamesGenerator(config);
}
function genDrinkName(): string {
const config: Config = {
dictionaries: [adjectives, colors],
length: 2,
separator: ' ',
style: 'capital'
};
return uniqueNamesGenerator(config);
}
function genStoreName(): string {
const stores: string[] = [
'shop',
'reseller',
'department Store',
'chain Store',
'emporium',
'supermarket',
'hypermarket',
'superstore',
'mart',
'shed',
'big Box',
'convenience Store',
'corner Store',
'food Store',
'market',
'food Mart',
'bodega',
];
const config: Config = {
dictionaries: [names, stores],
length: 2,
separator: '\'s ',
style: 'capital'
};
return uniqueNamesGenerator(config);
}
function genCityName(): string {
const places: string[] = [
'town',
'city',
'township',
'borough',
'seat',
'metropolis',
'burg',
'municipality',
'hamlet',
];
const config: Config = {
dictionaries: [Math.random() > 0.5 ? colors : names, places],
length: 2,
separator: ' ',
style: 'capital'
};
return uniqueNamesGenerator(config);
}
function clamp(value: number, max: number = 1, min: number = 0) {
if (value > max) {
return max;
}
if (value < min) {
return min;
}
return value;
}
function genPreferences(): string[] {
const availableDrinks: string[] = mockData.drinks;
let prefCount = Math.floor(Math.random() * availableDrinks.length);
prefCount = prefCount === 0 ? prefCount + 1 : prefCount; // have at least one preference
let preferences: string[] = [];
while (preferences.length < prefCount) {
let newPref: Drink = pick(availableDrinks);
if (preferences.indexOf(newPref.id) === -1) {
preferences.push(newPref.id);
}
}
return preferences;
}
function getSelectionType(typeName: string) {
return mockData.selectionTypes.find((type) => {
return type.type === typeName;
});
}
function randomNumber(min: number, max: number): number {
return Math.random() * (max - min) + min;
}
function pick(arr: any[]) {
return arr[Math.floor(Math.random() * arr.length)];
}
function getStatsFromEvents(events: EventLog[]) {
let purchaseCount: number = 0;
let offerEventCount: number = 0;
let amountEarned: number = 0;
let ozSold: number = 0;
let popularity: {[drink: string]: number} = {};
let eventReasons: {[reason: string]: number} = {};
for (let i in events) {
let eventLog: EventLog = events[i];
if (!eventReasons[eventLog.data.reason]) {
eventReasons[eventLog.data.reason] = 0;
}
eventReasons[eventLog.data.reason] = eventReasons[eventLog.data.reason] + 1;
if (eventLog.eventName === 'bought' || eventLog.eventName === 'wontBuy') {
offerEventCount = offerEventCount + 1;
if (eventLog.eventName === 'bought') {
purchaseCount = purchaseCount + 1;
if (!popularity[eventLog.data.drink]) {
popularity[eventLog.data.drink] = 0;
}
popularity[eventLog.data.drink] = popularity[eventLog.data.drink] + 1;
amountEarned = amountEarned + eventLog.data.amount;
ozSold = ozSold + eventLog.data.oz;
}
}
}
console.log({
purchaseCount,
purchaseRate: purchaseCount / offerEventCount,
offerEventCount,
amountEarned,
ozSold,
popularity,
eventReasons
});
}
interface Drink {
id: string;
name: string;
costPerOz: number;
}
interface DailyTraffic {
max: number;
min: number;
thirstBonus: number;
}
interface Placement {
id: string;
name: string;
traffic: number;
}
interface Location {
id: string;
name: string;
city: string;
dailyTraffic: DailyTraffic;
placements: Placement[];
}
interface Person {
id: string;
name: string;
preferences: string[];
highestPrice: number;
money: number;
thirst: number;
}
interface EventLog {
eventName: string;
data: any;
}
interface PersonEvent {
reason: string;
amount: number;
drink: string;
selection: string;
selectionType: string;
oz: number;
person: string; // person involved in the event
offer: string; // id of deal or vending machine
}
let events: EventLog[] = [];
let traffic: number = randomNumber(mockData.locations[0].dailyTraffic.min, mockData.locations[0].dailyTraffic.max)
for (let i = 0; i < traffic; i++) {
// console.log(generatePerson(mockData.locations[0]));
let curEvent: EventLog = personPassesByVendingMachine(generatePerson(mockData.locations[0]), mockData.players[0].vendingMachines[0])
// console.log(genDrinkName());
// console.log(genStoreName());
console.log(genCityName());
events.push(curEvent);
handleEvent(curEvent);
}
getStatsFromEvents(events);