From 82419840618418daa9020029a5347fc0f6e5edc5 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Mon, 25 Nov 2024 14:52:56 +0100 Subject: location score. close #1, close #7, close #6 --- README.md | 3 +++ src/include/world.h | 8 +++++-- src/scenes/place_detail.c | 31 +++++++++++++++++++++---- src/world.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4b3d1d4..f614691 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ Truck logistics management game written using C + OpenGL. Uses SDL2 SDL2_Mixer for audio. Video: https://www.youtube.com/watch?v=vd9a-LMGzrs&ab_channel=Aldrik + +Heuristics: +location score is based on: schedule efficiency 60%, employee happiness 10%, customer trust 30% \ No newline at end of file diff --git a/src/include/world.h b/src/include/world.h index 11ac92e..a719e57 100644 --- a/src/include/world.h +++ b/src/include/world.h @@ -29,6 +29,8 @@ typedef struct t_world_location world_location; typedef struct t_employee employee; + + #define WORK_HOUR_START 0 #define WORK_HOUR_END 24 #define TIME_SLOTS_PER_HOUR 4 @@ -39,7 +41,8 @@ typedef struct t_employee employee; #define MAX_EMPLOYEE_COUNT (TIME_SLOTS_PER_WEEK) #define MAX_TRUCK_COUNT (TIME_SLOTS_PER_WEEK) -#define MISSED_DELIVERY_TRUST_PENALTY (0.5f) +#define JOB_STARTING_TRUST 0.8f +#define MISSED_DELIVERY_TRUST_PENALTY (0.1f) #define MAX_EFFECTIVE_EXPERIENCE 25.0f // anything past 25 years of experience has no extra positives. #define SHIPTIME_DURATION_MULTIPLIER_MAX 1.0f #define SHIPTIME_DURATION_MULTIPLIER_MIN 1.15f @@ -145,7 +148,7 @@ typedef struct t_employee struct tm hire_date; u8 experience; float salary; - float happiness; + float happiness; // 0-1 s16 days_below_happiness_treshold; u32 current_location_id; u32 original_location_id; @@ -242,6 +245,7 @@ typedef struct t_world_location schedule schedule; u16 purchase_year; array insights; + float score; // 0-1 // Dynamic array connections; diff --git a/src/scenes/place_detail.c b/src/scenes/place_detail.c index 707ae0f..4519cfa 100644 --- a/src/scenes/place_detail.c +++ b/src/scenes/place_detail.c @@ -131,7 +131,7 @@ static scheduled_job create_empty_job_schedule(job_offer* job) scheduled_job new_job; new_job.location = _active_location; new_job.offer = *job; - new_job.trust = 1.0f; + new_job.trust = JOB_STARTING_TRUST; for (s32 i = 0; i < MAX_SHIPDAYS; i++) { new_job.timeslots[i] = (scheduled_job_time){-1, -1, 0, 0}; } @@ -1567,11 +1567,34 @@ static tab place_detail_draw_tabs(platform_window* window) return place_detail_draw_tab_bg(window); } +#define DRAW_STARS(_x, _y, _txt, _count){\ +s32 textw = renderer->render_text(fnt, _x, _y, _txt, COLOR_TEXT);\ +_x += (scale*5);\ +for (s32 i = 0; i < 5; i++)\ +{\ + if (i < _count) renderer->render_image(img_star, _x + textw + (i*(fnt->px_h+2)), _y, fnt->px_h, fnt->px_h);\ + else renderer->render_image_tint(img_star, _x + textw + (i*(fnt->px_h+2)), _y, fnt->px_h, fnt->px_h, rgba(255,255,255,30));\ +}} + +static void place_detail_draw_location_stats(platform_window* window) +{ + font* fnt = fnt_rd20; + float text_pad = scale * 40.0; + + //s32 w = (area.w * 0.9 - (offset*2)); + + s32 text_x = area.x + text_pad + (area.w*0.75); + s32 text_y = area.y + text_pad + (area.w*0.05); + + DRAW_STARS(text_x, text_y, "Score: ", 5); +} + static void place_detail_draw_title(platform_window* window) { char buf[200]; if (current_detail_state == PLACE_DETAIL_SHOW_MAIN) { strcpy(buf, _active_location->name); + place_detail_draw_location_stats(window); } else if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) { strcpy(buf, "Hire new employees"); @@ -1596,8 +1619,8 @@ static void place_detail_draw_title(platform_window* window) font* fnt = fnt_rd36; float text_pad = scale * 40.0; - s32 text_x = text_pad + area.x + (area.w*0.05); - s32 text_y = text_pad + area.y + (area.w*0.05); + s32 text_x = area.x + text_pad + (area.w*0.05); + s32 text_y = area.y + text_pad + (area.w*0.05); // Title { @@ -1739,7 +1762,7 @@ void place_detail_scene_render(platform_window* window) if (selected_tab_index == PLACE_DETAIL_SCHEDULE) { selected_tab_index = PLACE_DETAIL_SHOW_MAIN; current_detail_state = PLACE_DETAIL_SHOW_SCHEDULE; - } + } } if (current_detail_state == PLACE_DETAIL_SHOW_RESUMES) { place_detail_draw_resumes(window); diff --git a/src/world.c b/src/world.c index db8ce7d..3226937 100644 --- a/src/world.c +++ b/src/world.c @@ -692,7 +692,7 @@ static void world_assign_new_job_offers(world* world) total_dist += distance_between_location(source, dest); } new_offer.total_distance = total_dist; - new_offer.reward = (u32)(new_offer.total_distance * 2.1); // -1 because source is is connection list. + new_offer.reward = (u32)(new_offer.total_distance * 2.1); // lets assume most experienced drivers drive at 90km/h double min_duration_hours = (new_offer.total_distance/90.0); @@ -976,7 +976,12 @@ static void world_update_active_jobs(world* world) i--; } else { // Job is done, return to original location if not staying. - if (sc_job) sc_job->trust += (0.1f / sc_job->trust); // If job is still available, update trust. + if (sc_job) { // If job is still available, update trust. + sc_job->trust += (0.01f / sc_job->trust); + if (sc_job->trust > 1.0f) { + sc_job->trust = 1.0f; + } + } ADD_INCOME(world, endpoints.source, income_from_trips, job->offer.reward); float gasprice = ((job->offer.total_distance/100.0f) * job->assigned_truck.fuelusage) * DIESEL_PRICE_PER_LITER; @@ -1151,6 +1156,54 @@ static void end_contract_with_employee(world* world, employee* emp) if (curr_loc) array_remove_by(&curr_loc->employees, &emp); } +static void world_update_location_scores(world* world) +{ + for (s32 i = 0; i < world->locations.length; i++) + { + world_location* location = array_at(&world->locations, i); + if (!location->is_owned) continue; + + s32 total_scheduled_slots = 0; + for (int x = 0; x < location->schedule.jobs.length; x++) + { + scheduled_job* job = array_at(&location->schedule.jobs, x); + total_scheduled_slots += job->offer.shipday_count; + } + + float total_happiness = 0.0f; + int total_employees_counted = 0; + for (s32 x = 0; x < location->employees.length; x++) + { + employee* em = *(employee**)array_at(&location->employees, x); + if (em->original_location_id != location->id) continue; + + total_employees_counted++; + total_happiness += em->happiness; + } + if (total_employees_counted == 0) total_employees_counted = 1; + + float total_trust = 0.0f; + int total_trust_counted = 0; + for (s32 x = 0; x < location->schedule.jobs.length; x++) + { + scheduled_job* scheduled_job = array_at(&location->schedule.jobs, x); + total_trust += scheduled_job->trust; + total_trust_counted++; + } + if (total_trust_counted == 0) total_trust_counted = 1; + + float fill = total_scheduled_slots / ((float)TIME_SLOTS_PER_WEEK / 3); + if (fill > 1.0f) fill = 1.0f; + + float happiness = total_happiness / total_employees_counted; + float trust = total_trust / total_trust_counted; + location->score = ((fill*3.0f)+(happiness*0.5f)+(trust*1.5f)) / 5.0f; + + //printf("Score for location %s: (Schedule: %f Happiness: %f Trust: %f) = %f%% stars: %d\n", + // location->name, fill, happiness, trust, location->score*100.0f, (int)round(location->score * 5)); + } +} + static void world_run_simulation_tick(world* world) { s32 elapsed_sec = MINUTES(world->simulation_speed); @@ -1195,6 +1248,7 @@ static void world_run_simulation_tick(world* world) } world_update_active_jobs(world); + world_update_location_scores(world); } void world_update(platform_window* window, world* world) -- cgit v1.2.3-70-g09d2