Code Review Asked by Redwolf Programs on February 20, 2021
I wrote this a few months ago as my first "serious" C program (I’ve used JS for a few years). It’s a simple resource collecting and trading game (based off one I made in HTML/JS), that takes input in the form of some simple commands.
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
struct trade_like {
int8_t buy_item;
int8_t sell_item;
uint64_t buy_amount;
uint64_t sell_amount;
int16_t timer;
};
struct upgrade {
int8_t thread;
int8_t id;
};
void shorten_number(char *dest, uint64_t number) {
if (number >= 1000000000000) {
sprintf(dest, "%.2fT", fmin((double) number / 1000000000000.0, 999.99));
} else if (number >= 1000000000) {
sprintf(dest, "%.2fB", fmin((double) number / 1000000000.0, 999.99));
} else if (number >= 1000000) {
sprintf(dest, "%.2fM", fmin((double) number / 1000000.0, 999.99));
} else if (number >= 1000) {
sprintf(dest, "%.2fK", fmin((double) number / 1000.0, 999.99));
} else {
sprintf(dest, "%d", number);
}
return;
}
void print_resources(uint64_t resources[], struct trade_like trades[], struct trade_like deals[], struct upgrade upgrades[]) {
char amounts[9][10];
char trade_list[5][48];
char deal_list[3][48];
char upgrade_list[9][36];
char names[9][8] = {"Wood", "Stone", "Coal", "Iron", "Copper", "Silver", "Gold", "Diamond", "Emerald"};
char upper_names[9][8] = {"WOOD", "STONE", "COAL", "IRON", "COPPER", "SILVER", "GOLD", "DIAMOND", "EMERALD"};
char unlock_costs[8][2][16] = {
{"Wood (200)", "Coal (40)"},
{"Stone (400)", "Coal (80)"},
{"Stone (200)", "Iron (100)"},
{"Iron (300)", "Copper (50)"},
{"Stone (1.00K)", "Iron (400)"},
{"Copper (500)", "Coal (300)"},
{"Iron (1.00K)", "Silver (400)"},
{"Diamond (200)", "Silver (100)"}
};
char multiplier_levels[7][8] = {"+10%", "+25%", "+75%", "DOUBLE", "LOTS OF", "TONS OF"};
int16_t base_cost[7] = {200, 500, 1500, 4000, 10000, 20000};
memset(trade_list, '', sizeof(trade_list[0][0]) * 240);
memset(deal_list, '', sizeof(deal_list[0][0]) * 144);
memset(upgrade_list, '', sizeof(upgrade_list[0][0]) * 324);
printf("33[F33[A33[A33[A33[A33[A33[A33[A33[A33[A33[A33[A");
for (int8_t i = 0; i < 9; i++) {
shorten_number(amounts[i], resources[i]);
}
for (int8_t i = 0; i < 5; i++) {
if (trades[i].timer >= 0) {
char sell_string[10];
char buy_string[10];
shorten_number(sell_string, trades[i].sell_amount);
shorten_number(buy_string, trades[i].buy_amount);
sprintf(trade_list[i], "[%d] %s (%s) -> %s (%s)", i + 1, names[trades[i].sell_item], sell_string, names[trades[i].buy_item], buy_string);
}
}
for (int8_t i = 0; i < 3; i++) {
if (deals[i].timer >= 0) {
char sell_string[10];
char buy_string[10];
shorten_number(sell_string, deals[i].sell_amount);
shorten_number(buy_string, deals[i].buy_amount);
sprintf(deal_list[i], "[%d] %s (%s) -> %s (%s)", i + 1, names[deals[i].sell_item], sell_string, names[deals[i].buy_item], buy_string);
}
}
if (upgrades[0].thread != -1) {
sprintf(upgrade_list[0], "MINE %s", upper_names[upgrades[0].id + 1]);
sprintf(upgrade_list[1], " %s", unlock_costs[upgrades[0].id][0]);
sprintf(upgrade_list[2], " %s", unlock_costs[upgrades[0].id][1]);
}
if (upgrades[1].thread != -1) {
sprintf(upgrade_list[4], "%s %s", multiplier_levels[(int8_t) ((double) upgrades[1].id / 9.0)], upper_names[upgrades[1].id % 9]);
char cost_string[10];
shorten_number(cost_string, (double) base_cost[(int8_t) upgrades[1].id / 9] * (1.0 - 0.1 * (upgrades[1].id % 9)));
sprintf(upgrade_list[5], " %s (%s)", names[upgrades[1].id % 9], cost_string);
}
if (upgrades[2].thread == 2) {
sprintf(upgrade_list[7], "AUTO-%s", upper_names[upgrades[2].id]);
if (upgrades[2].id == 4) {
strcpy(upgrade_list[8], " Gold (200)");
}
sprintf(upgrade_list[8], " %s (200)", names[upgrades[2].id + 2]);
} else if (upgrades[2].thread == 3) {
sprintf(upgrade_list[7], "%s/%s DEALS", upper_names[upgrades[2].id * 2], upper_names[upgrades[2].id * 2 + 1]);
char cost_string[10];
shorten_number(cost_string, 1750 - 375 * upgrades[2].id);
sprintf(upgrade_list[8], " %s (%s)", names[upgrades[2].id * 2 + 1], cost_string);
}
printf(
" Wood: %-9s%-44s%-36sn Stone: %-9s%-44s%-36sn Coal: %-9s%-44s%-36sn Iron: %-9s%-44s%-36sn Copper: %-9s%-44s%-36sn Silver: %-9s%-44s%-36sn Gold: %-9s%-44s%-36sn Diamond: %-9s%-44s%-36sn Emerald: %-9s%-44s%-36snnnn >> bbbbbbbbbbbbbbbbbbbbbbbb",
amounts[0], trade_list[0], upgrade_list[0], amounts[1], trade_list[1], upgrade_list[1], amounts[2], trade_list[2], upgrade_list[2],
amounts[3], trade_list[3], upgrade_list[3], amounts[4], trade_list[4], upgrade_list[4], amounts[5], " ", upgrade_list[5],
amounts[6], deal_list[0], upgrade_list[6], amounts[7], deal_list[1], upgrade_list[7], amounts[8], deal_list[2], upgrade_list[8]
);
return;
}
int main(int argc, char** argv) {
int8_t unlocked = 0;
uint64_t resources[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
double multipliers[9] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
int8_t auto_level = 0;
int16_t item_costs[9] = {1, 2, 5, 10, 25, 40, 80, 200, 875};
char names[9][8] = {"Wood", "Stone", "Coal", "Iron", "Copper", "Silver", "Gold", "Diamond", "Emerald"};
struct trade_like trades[5];
struct trade_like deals[3];
int8_t trade_tick = 0;
int8_t deal_tick = 0;
int8_t unlocked_deals = 0;
for (int8_t i = 0; i < 5; i++) {
trades[i].timer = -1;
if (i < 3) {
deals[i].timer = -1;
}
}
struct upgrade upgrades[3];
upgrades[0].thread = 0;
upgrades[0].id = 0;
upgrades[0].thread = -1;
upgrades[1].thread = -1;
upgrades[2].thread = -1;
int64_t turn_count = 0;
char words_redo[4][24];
srand(time(NULL));
strcpy(words_redo[0], "collect");
strcpy(words_redo[1], "wood");
memset(words_redo[2], '', sizeof(words_redo[2][0]) * 48);
printf("MERCHANT 2.0.0 [TERMINAL EDITION]nnnnnnnnnnnn Enter 'collect wood' to begin playing!nnn33[A");
char input[24];
while (strncmp(input, "quitn", 5) != 0 && strncmp(input, "exitn", 5) != 0 && strncmp(input, "qn", 2) != 0 && strncmp(input, "xn", 2) != 0) {
print_resources(resources, trades, deals, upgrades);
fgets(input, 24, stdin);
printf("33[F33[A33[A bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
char words[4][24];
int8_t word_count = 0;
int8_t within_word = 0;
memset(words[0], '', sizeof(words[0][0]) * 96);
for (int8_t i = 0; i < 24; i++) {
if (input[i] == 'n' || input[i] == '') {
break;
} else if (input[i] >= 'a' && input[i] <= 'z' || input[i] >= 'A' && input[i] <= 'Z' || input[i] >= '0' && input[i] <= '9' || input[i] == '-' || input[i] == '_') {
words[word_count][within_word++] = input[i];
} else {
if (within_word != 0) {
word_count++;
within_word = 0;
if (word_count == 4) {
break;
}
}
}
}
if (strncmp(words[0], "redo", 5) == 0 || strncmp(words[0], "r", 2) == 0 || words[0][0] == '') {
strcpy(words[0], words_redo[0]);
strcpy(words[1], words_redo[1]);
strcpy(words[2], words_redo[2]);
strcpy(words[3], words_redo[3]);
}
if (strncmp(words[0], "collect", 8) == 0 || strncmp(words[0], "col", 4) == 0 || strncmp(words[0], "c", 2) == 0) {
int16_t collect_amount;
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (resource name)nn");
continue;
}
if (strncmp(words[1], "wood", 5) == 0 || strncmp(words[1], "w", 2) == 0) {
if (unlocked < 0) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[0]) + (rand() < RAND_MAX * (multipliers[0] - floorf(multipliers[0]))));
resources[0] += collect_amount;
printf("Collected %d wood", collect_amount);
} else if (strncmp(words[1], "stone", 6) == 0 || strncmp(words[1], "s", 2) == 0) {
if (unlocked < 1) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[1]) + (rand() < RAND_MAX * (multipliers[1] - floorf(multipliers[1]))));
resources[1] += collect_amount;
printf("Collected %d stone", collect_amount);
} else if (strncmp(words[1], "coal", 5) == 0 || strncmp(words[1], "c", 2) == 0) {
if (unlocked < 2) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[2]) + (rand() < RAND_MAX * (multipliers[2] - floorf(multipliers[2]))));
resources[2] += collect_amount;
printf("Collected %d coal", collect_amount);
} else if (strncmp(words[1], "iron", 5) == 0 || strncmp(words[1], "i", 2) == 0) {
if (unlocked < 3) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[3]) + (rand() < RAND_MAX * (multipliers[3] - floorf(multipliers[3]))));
resources[3] += collect_amount;
printf("Collected %d iron", collect_amount);
} else if (strncmp(words[1], "copper", 7) == 0 || strncmp(words[1], "cp", 3) == 0 || strncmp(words[1], "cr", 3) == 0) {
if (unlocked < 4) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[4]) + (rand() < RAND_MAX * (multipliers[4] - floorf(multipliers[4]))));
resources[4] += collect_amount;
printf("Collected %d copper", collect_amount);
} else if (strncmp(words[1], "silver", 7) == 0 || strncmp(words[1], "si", 3) == 0 || strncmp(words[1], "sv", 3) == 0) {
if (unlocked < 5) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[5]) + (rand() < RAND_MAX * (multipliers[5] - floorf(multipliers[5]))));
resources[5] += collect_amount;
printf("Collected %d silver", collect_amount);
} else if (strncmp(words[1], "gold", 5) == 0 || strncmp(words[1], "g", 2) == 0) {
if (unlocked < 6) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[6]) + (rand() < RAND_MAX * (multipliers[6] - floorf(multipliers[6]))));
resources[6] += collect_amount;
printf("Collected %d gold", collect_amount);
} else if (strncmp(words[1], "diamond", 8) == 0 || strncmp(words[1], "d", 2) == 0) {
if (unlocked < 7) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[7]) + (rand() < RAND_MAX * (multipliers[7] - floorf(multipliers[7]))));
resources[7] += collect_amount;
printf("Collected %d diamond", collect_amount);
} else if (strncmp(words[1], "emerald", 8) == 0 || strncmp(words[1], "e", 2) == 0 || strncmp(words[1], "m", 2) == 0) {
if (unlocked < 8) {
printf("ERR: You haven't unlocked this resourcenn");
continue;
}
collect_amount = (int16_t) (floorf(multipliers[8]) + (rand() < RAND_MAX * (multipliers[8] - floorf(multipliers[8]))));
resources[8] += collect_amount;
printf("Collected %d emerald", collect_amount);
} else {
printf("ERR: Unknown resourcenn");
continue;
}
} else if (strncmp(words[0], "trade", 6) == 0 || strncmp(words[0], "tr", 3) == 0 || strncmp(words[0], "t", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (trade id)nn");
continue;
}
if (words[1][1] != '' || words[1][0] < '1' || words[1][0] > '5') {
printf("ERR: Invalid trade idnn");
continue;
}
int8_t trade = words[1][0] - 49;
if (trades[trade].timer == -1) {
printf("ERR: There is no trade with that idnn");
continue;
} else if (resources[trades[trade].sell_item] < trades[trade].sell_amount) {
printf("ERR: You can't afford that tradenn");
continue;
} else {
resources[trades[trade].buy_item] += trades[trade].buy_amount;
resources[trades[trade].sell_item] -= trades[trade].sell_amount;
trades[trade].timer = fmax(trades[trade].timer - (int16_t) ((trades[trade].buy_amount / resources[trades[trade].buy_item]) * 4), -1);
printf("Trade #1: %s (%d) -> %s (%d)", names[trades[trade].sell_item], trades[trade].sell_amount, names[trades[trade].buy_item], trades[trade].buy_amount);
}
} else if (strncmp(words[0], "deal", 5) == 0 || strncmp(words[0], "d", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (deal id)nn");
continue;
}
if (words[1][1] != '' || words[1][0] < '1' || words[1][0] > '3') {
printf("ERR: Invalid deal idnn");
continue;
}
int8_t deal = words[1][0] - 49;
if (deals[deal].timer == -1) {
printf("ERR: There is no deal with that idnn");
continue;
} else if (resources[deals[deal].sell_item] < deals[deal].sell_amount) {
printf("ERR: You can't afford that dealnn");
continue;
} else {
resources[deals[deal].buy_item] += deals[deal].buy_amount;
resources[deals[deal].sell_item] -= deals[deal].sell_amount;
deals[deal].timer = -1;
printf("Deal #1: %s (%d) -> %s (%d)", names[deals[deal].sell_item], deals[deal].sell_amount, names[deals[deal].buy_item], deals[deal].buy_amount);
}
} else if (strncmp(words[0], "unlock", 7) == 0 || strncmp(words[0], "unl", 4) == 0 || strncmp(words[0], "u", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (resource id)nn");
continue;
}
if (strncmp(words[1], "wood", 5) == 0 || strncmp(words[1], "w", 2) == 0) {
printf("ERR: You have already unlocked this resourcenn");
continue;
} else if (strncmp(words[1], "stone", 6) == 0 || strncmp(words[1], "s", 2) == 0) {
if (unlocked >= 1) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (resources[0] < 200 || resources[2] < 40) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[0] -= 200;
resources[2] -= 40;
unlocked++;
printf("Unlocked stone");
} else if (strncmp(words[1], "coal", 5) == 0 || strncmp(words[1], "c", 2) == 0) {
if (unlocked >= 2) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 1) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[1] < 400 || resources[2] < 80) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[1] -= 400;
resources[2] -= 80;
unlocked++;
printf("Unlocked coal");
} else if (strncmp(words[1], "iron", 5) == 0 || strncmp(words[1], "i", 2) == 0) {
if (unlocked >= 3) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 2) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[1] < 200 || resources[3] < 100) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[1] -= 200;
resources[3] -= 100;
unlocked++;
printf("Unlocked iron");
} else if (strncmp(words[1], "copper", 7) == 0 || strncmp(words[1], "cp", 3) == 0 || strncmp(words[1], "cr", 3) == 0) {
if (unlocked >= 4) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 3) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[3] < 300 || resources[4] < 50) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[3] -= 300;
resources[4] -= 50;
unlocked++;
printf("Unlocked copper");
} else if (strncmp(words[1], "silver", 7) == 0 || strncmp(words[1], "si", 3) == 0 || strncmp(words[1], "sv", 3) == 0) {
if (unlocked >= 5) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 4) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[1] < 1000 || resources[3] < 400) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[1] -= 1000;
resources[3] -= 400;
unlocked++;
printf("Unlocked silver");
} else if (strncmp(words[1], "gold", 5) == 0 || strncmp(words[1], "g", 2) == 0) {
if (unlocked >= 6) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 5) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[4] < 500 || resources[2] < 300) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[4] -= 500;
resources[2] -= 300;
unlocked++;
printf("Unlocked gold");
} else if (strncmp(words[1], "diamond", 8) == 0 || strncmp(words[1], "d", 2) == 0) {
if (unlocked >= 7) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 6) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[3] < 1000 || resources[5] < 400) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[3] -= 1000;
resources[5] -= 400;
unlocked++;
printf("Unlocked diamond");
} else if (strncmp(words[1], "emerald", 8) == 0 || strncmp(words[1], "e", 2) == 0 || strncmp(words[1], "m", 2) == 0) {
if (unlocked == 8) {
printf("ERR: You have already unlocked this resourcenn");
continue;
}
if (unlocked < 7) {
printf("ERR: You cannot unlock this resource yetnn");
continue;
}
if (resources[7] < 200 || resources[5] < 100) {
printf("ERR: You cannot afford to unlock this resourcenn");
continue;
}
resources[7] -= 200;
resources[5] -= 100;
unlocked++;
printf("Unlocked emerald");
} else {
printf("ERR: Unknown resourcenn");
continue;
}
upgrades[0].thread = -1;
} else if (strncmp(words[0], "multiplier", 11) == 0 || strncmp(words[0], "multiply", 9) == 0 || strncmp(words[0], "multi", 6) == 0 || strncmp(words[0], "mul", 4) == 0 || strncmp(words[0], "m", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (resource name)nn");
continue;
}
int8_t resource;
if (strncmp(words[1], "wood", 5) == 0 || strncmp(words[1], "w", 2) == 0) {
resource = 0;
} else if (strncmp(words[1], "stone", 6) == 0 || strncmp(words[1], "s", 2) == 0) {
resource = 1;
} else if (strncmp(words[1], "coal", 5) == 0 || strncmp(words[1], "c", 2) == 0) {
resource = 2;
} else if (strncmp(words[1], "iron", 5) == 0 || strncmp(words[1], "i", 2) == 0) {
resource = 3;
} else if (strncmp(words[1], "copper", 7) == 0 || strncmp(words[1], "cp", 3) == 0 || strncmp(words[1], "cr", 3) == 0) {
resource = 4;
} else if (strncmp(words[1], "silver", 7) == 0 || strncmp(words[1], "si", 3) == 0 || strncmp(words[1], "sv", 3) == 0) {
resource = 5;
} else if (strncmp(words[1], "gold", 5) == 0 || strncmp(words[1], "g", 2) == 0) {
resource = 6;
} else if (strncmp(words[1], "diamond", 8) == 0 || strncmp(words[1], "d", 2) == 0) {
resource = 7;
} else if (strncmp(words[1], "emerald", 8) == 0 || strncmp(words[1], "e", 2) == 0 || strncmp(words[1], "m", 2) == 0) {
resource = 8;
} else {
printf("ERR: Unknown resourcenn");
continue;
}
if (multipliers[resource] == 1.0) {
if (resources[resource] < 200 - 20 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 200 - 20 * resource;
multipliers[resource] = 1.1;
} else if (multipliers[resource] == 1.1) {
if (resources[resource] < 500 - 50 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 500 - 50 * resource;
multipliers[resource] = 1.25;
} else if (multipliers[resource] == 1.25) {
if (resources[resource] < 1500 - 150 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 1500 - 150 * resource;
multipliers[resource] = 1.75;
} else if (multipliers[resource] == 1.75) {
if (resources[resource] < 4000 - 40 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 4000 - 400 * resource;
multipliers[resource] = 2.0;
} else if (multipliers[resource] == 2.0) {
if (resources[resource] < 10000 - 1000 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 10000 - 1000 * resource;
multipliers[resource] = 5.0;
} else if (multipliers[resource] == 5.0) {
if (resources[resource] < 20000 - 2000 * resource) {
printf("ERR: You cannot afford this upgradenn");
continue;
}
resources[resource] -= 20000 - 2000 * resource;
multipliers[resource] = 10.0;
} else {
printf("ERR: This resource is already at max multipliernn");
continue;
}
upgrades[1].thread = -1;
} else if (strncmp(words[0], "autocollect", 12) == 0 || strncmp(words[0], "autocol", 8) == 0 || strncmp(words[0], "auto", 5) == 0 || strncmp(words[0], "a", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (resource)nn");
continue;
}
int8_t level;
if (strncmp(words[1], "wood", 5) == 0 || strncmp(words[1], "w", 2) == 0) {
level = 1;
} else if (strncmp(words[1], "stone", 6) == 0 || strncmp(words[1], "s", 2) == 0) {
level = 2;
} else if (strncmp(words[1], "coal", 5) == 0 || strncmp(words[1], "c", 2) == 0) {
level = 3;
} else if (strncmp(words[1], "iron", 5) == 0 || strncmp(words[1], "i", 2) == 0) {
level = 4;
} else if (strncmp(words[1], "metal", 6) == 0 || strncmp(words[1], "m", 2) == 0) {
level = 5;
} else {
printf("ERR: Unknown or non-automatable resourcenn");
continue;
}
if (auto_level > level) {
printf("ERR: You have already automated this resourcenn");
continue;
}
if (auto_level < level - 1) {
printf("ERR: You cannot automate this resource yetnn");
continue;
}
if (resources[level + 1] < 200) {
printf("ERR: You cannot afford to automate this resourcenn");
continue;
}
auto_level = level;
resources[level + 1] -= 200;
upgrades[2].thread = -1;
} else if (strncmp(words[0], "unlock-deal", 12) == 0 || strncmp(words[0], "unlock_deal", 12) == 0 || strncmp(words[0], "unl-d", 6) == 0 || strncmp(words[0], "unl_d", 6) == 0 || strncmp(words[0], "ud", 3) == 0 || strncmp(words[0], "l", 2) == 0) {
if (words[1][0] == '' || words[2][0] != '') {
printf("ERR: Expected one argument (resource)nn");
continue;
}
int8_t deal;
if (strncmp(words[1], "wood", 5) == 0 || strncmp(words[1], "w", 2) == 0) {
deal = 2;
} else if (strncmp(words[1], "stone", 6) == 0 || strncmp(words[1], "s", 2) == 0) {
deal = 2;
} else if (strncmp(words[1], "coal", 5) == 0 || strncmp(words[1], "c", 2) == 0) {
deal = 4;
} else if (strncmp(words[1], "iron", 5) == 0 || strncmp(words[1], "i", 2) == 0) {
deal = 4;
} else if (strncmp(words[1], "copper", 7) == 0 || strncmp(words[1], "cp", 3) == 0 || strncmp(words[1], "cr", 3) == 0) {
deal = 6;
} else if (strncmp(words[1], "silver", 7) == 0 || strncmp(words[1], "si", 3) == 0 || strncmp(words[1], "sv", 3) == 0) {
deal = 6;
} else if (strncmp(words[1], "gold", 5) == 0 || strncmp(words[1], "g", 2) == 0) {
deal = 8;
} else if (strncmp(words[1], "diamond", 8) == 0 || strncmp(words[1], "d", 2) == 0) {
deal = 8;
} else {
printf("ERR: Unknown resourcenn");
continue;
}
if (deal < unlocked_deals) {
printf("You have already unlocked these dealsnn");
continue;
}
if (unlocked_deals < deal - 2) {
printf("You cannot unlock these deals yetnn");
continue;
}
if (resources[deal - 1] < 2125 - (deal / 2) * 375) {
printf("You cannot afford to unlock these dealsnn");
continue;
}
resources[deal - 1] -= 2125 - (deal / 2) * 375;
unlocked_deals = deal;
upgrades[2].thread = -1;
} else {
printf("ERR: Unknown commandnn");
continue;
}
strcpy(words_redo[0], words[0]);
strcpy(words_redo[1], words[1]);
strcpy(words_redo[2], words[2]);
strcpy(words_redo[3], words[3]);
printf("nn");
if (auto_level == 1) {
if (rand() < (double) RAND_MAX * 0.1) {
resources[0]++;
}
} else if (auto_level == 2) {
if (rand() < (double) RAND_MAX * 0.2) {
resources[0]++;
}
if (rand() < (double) RAND_MAX * 0.1) {
resources[1]++;
}
} else if (auto_level == 3) {
if (rand() < (double) RAND_MAX * 0.35) {
resources[0]++;
}
if (rand() < (double) RAND_MAX * 0.2) {
resources[1]++;
}
if (rand() < (double) RAND_MAX * 0.1) {
resources[2]++;
}
} else if (auto_level == 4) {
if (rand() < (double) RAND_MAX * 0.5) {
resources[0]++;
}
if (rand() < (double) RAND_MAX * 0.35) {
resources[1]++;
}
if (rand() < (double) RAND_MAX * 0.2) {
resources[2]++;
}
if (rand() < (double) RAND_MAX * 0.1) {
resources[3]++;
}
} else if (auto_level == 5) {
if (rand() < (double) RAND_MAX * 0.75) {
resources[0]++;
}
if (rand() < (double) RAND_MAX * 0.5) {
resources[1]++;
}
if (rand() < (double) RAND_MAX * 0.35) {
resources[2]++;
}
if (rand() < (double) RAND_MAX * 0.2) {
resources[3]++;
}
if (rand() < (double) RAND_MAX * 0.1) {
resources[4]++;
}
if (rand() < (double) RAND_MAX * 0.05) {
resources[5]++;
}
if (rand() < (double) RAND_MAX * 0.01) {
resources[6]++;
}
}
if (trade_tick-- < 0) {
for (int8_t i = 0; i < 5; i++) {
if (trades[i].timer >= 0)
trades[i].timer--;
}
if (rand() < RAND_MAX * 0.15) {
int8_t trade = -1;
for (int8_t i = 0; i < 5; i++) {
if (trades[i].timer == -1) {
trade = i;
break;
}
}
if (trade != -1) {
trades[trade].sell_item = (int8_t) ((rand() / (double) RAND_MAX) * (unlocked + 1));
trades[trade].sell_amount = (uint64_t) (resources[trades[trade].sell_item] * ((rand() / (double) RAND_MAX) + 0.25) + (uint64_t) (rand() / (double) RAND_MAX) * 40 * multipliers[trades[trade].sell_item]);
do {
trades[trade].buy_item = (int8_t) ((rand() / (double) RAND_MAX) * (fmin(unlocked, 8) + 1));
double random = rand() / (double) RAND_MAX;
if (random < 0.02 && unlocked <= 5) {
trades[trade].buy_item += 3;
} else if (random < 0.2 && unlocked <= 6) {
trades[trade].buy_item += 2;
} else if (random < 0.6 && unlocked <= 7) {
trades[trade].buy_item += 1;
}
} while (trades[trade].buy_item == trades[trade].sell_item);
trades[trade].buy_amount = (uint64_t) (((trades[trade].sell_amount * item_costs[trades[trade].sell_item]) * ((rand() / (double) RAND_MAX) * 0.6 + 0.75)) / item_costs[trades[trade].buy_item]);
trades[trade].timer = (int16_t) ((rand() / (double) RAND_MAX) * 8 + 16);
}
}
trade_tick = (int8_t) ((rand() / (double) RAND_MAX) * 5) + 4;
}
if (unlocked_deals != 0 && deal_tick-- < 0) {
for (int8_t i = 0; i < 3; i++) {
if (deals[i].timer >= 0)
deals[i].timer--;
}
if (rand() < RAND_MAX * 0.35) {
int8_t deal = -1;
for (int8_t i = 0; i < 3; i++) {
if (deals[i].timer == -1) {
deal = i;
break;
}
}
if (deal != -1) {
deals[deal].sell_item = (int8_t) ((rand() / (double) RAND_MAX) * unlocked_deals);
deals[deal].sell_amount = (uint64_t) (resources[deals[deal].sell_item] * ((rand() / (double) RAND_MAX) * 0.5 + 0.1) + (rand() / (double) RAND_MAX) * 20 * multipliers[deals[deal].sell_item]);
do {
deals[deal].buy_item = (int8_t) ((rand() / (double) RAND_MAX) * unlocked_deals);
} while (deals[deal].buy_item == deals[deal].sell_item);
deals[deal].buy_amount = (uint64_t) (((deals[deal].sell_amount * item_costs[deals[deal].sell_item]) * ((rand() / (double) RAND_MAX) + 0.6)) / item_costs[deals[deal].buy_item]);
deals[deal].timer = (int16_t) ((rand() / (double) RAND_MAX) * 3 + 8);
}
}
deal_tick = (int8_t) ((rand() / (double) RAND_MAX) * 2) + 2;
}
if (upgrades[0].thread == -1) {
if (unlocked == 0) {
upgrades[0].thread = 0;
upgrades[0].id = 0;
} else if (unlocked == 1 && resources[2]) {
upgrades[0].thread = 0;
upgrades[0].id = 1;
} else if (unlocked == 2 && resources[3]) {
upgrades[0].thread = 0;
upgrades[0].id = 2;
} else if (unlocked == 3 && resources[4]) {
upgrades[0].thread = 0;
upgrades[0].id = 3;
} else if (unlocked == 4 && resources[5]) {
upgrades[0].thread = 0;
upgrades[0].id = 4;
} else if (unlocked == 5 && resources[6]) {
upgrades[0].thread = 0;
upgrades[0].id = 5;
} else if (unlocked == 6 && resources[7]) {
upgrades[0].thread = 0;
upgrades[0].id = 6;
} else if (unlocked == 7 && resources[8]) {
upgrades[0].thread = 0;
upgrades[0].id = 7;
}
}
if (upgrades[1].thread == -1) {
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 5.0 && resources[i] > 2000) {
upgrades[1].thread = 1;
upgrades[1].id = i + 45;
break;
}
}
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 2.0 && resources[i] > 1000) {
upgrades[1].thread = 1;
upgrades[1].id = i + 36;
break;
}
}
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 1.75 && resources[i] > 400) {
upgrades[1].thread = 1;
upgrades[1].id = i + 27;
break;
}
}
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 1.25 && resources[i] > 150) {
upgrades[1].thread = 1;
upgrades[1].id = i + 18;
break;
}
}
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 1.1 && resources[i] > 50) {
upgrades[1].thread = 1;
upgrades[1].id = i + 9;
break;
}
}
for (int8_t i = 0; i < 9; i++) {
if (multipliers[i] == 1.0 && resources[i] > 20) {
upgrades[1].thread = 1;
upgrades[1].id = i;
break;
}
}
}
if (upgrades[2].thread == -1) {
if (auto_level == 0 && unlocked >= 1 && resources[2]) {
upgrades[2].thread = 2;
upgrades[2].id = 0;
} else if (auto_level == 1 && unlocked >= 2 && resources[3]) {
upgrades[2].thread = 2;
upgrades[2].id = 1;
} else if (auto_level == 2 && unlocked >= 3 && resources[4]) {
upgrades[2].thread = 2;
upgrades[2].id = 2;
} else if (auto_level == 3 && unlocked >= 4 && resources[5]) {
upgrades[2].thread = 2;
upgrades[2].id = 3;
} else if (auto_level == 4 && unlocked >= 6) {
upgrades[2].thread = 2;
upgrades[2].id = 4;
} else if (unlocked_deals == 0 && unlocked >= 1) {
upgrades[2].thread = 3;
upgrades[2].id = 0;
} else if (unlocked_deals == 2 && unlocked >= 3) {
upgrades[2].thread = 3;
upgrades[2].id = 1;
} else if (unlocked_deals == 4 && unlocked >= 5) {
upgrades[2].thread = 3;
upgrades[2].id = 2;
} else if (unlocked_deals == 6 && unlocked >= 7) {
upgrades[2].thread = 3;
upgrades[2].id = 3;
}
}
turn_count++;
}
printf("33[F33[A Finished game after %d turn(s)nn", turn_count);
return 0;
}
(Compiled on my machine (Bash, Linux VM) with gcc -g -lm -o merchant merchant.c
)
Some things I was wondering about:
else if
s? Maybe a switch
statement or for
loop?First post on code review, if there’s something I forgot to include let me know!
Is there a way to get rid of all those else ifs? Maybe a switch statement or for loop?
Certainly.
With if (strncmp(words[0], "redo ", ....
consider a table of pairs of string and function.
// Something like
for (i=0; i<table_size; i++) {
if (my_compare(words[0], table[i].s)) {
table[i].f(state_data, words, ....); // do whatever per helper function
break;
}
}
if (i == table_size) my_handle_no_match();
With shorten_number()
:
To get a correct answer is tricky mixing 64-bit integer math with double
.
Example: (Note original code provides errant results with large values and near 999.995+*10^3x)
// Reduce to "1.00x" to "999.99x"
void shorten_number(char *dest, uint64_t number) {
if (number < 1000) {
sprintf(dest, "%d", (int) number);
return;
}
static const char suffix[] = " KMBTqQ"; // or maybe metric " kMGTPEZY"
int suffix_index = 0;
double scale = 1.0;
while (number/scale >= 999.995) {
scale *= 1000.0;
suffix_index++;
}
sprintf(dest, "%.2f%c", number / scale, suffix[suffix_index]);
}
Is there a better way to overwrite all of the program's previous output than just moving the cursor to overwrite it?
C has no standard way to overwrite previous output. Any solution is specific to the terminal type.
Rather than printf("