FrogReaver
As long as i get to be the frog
I don’t recall for sure, but don’t you need to seed the Randomizer in C with something (perhaps current time?). Nevermind, found it in main, which is where it should beOK, fine. How about this:
I made a simulation that takes two fighters, both level 20. They are fighting an enemy. We assume the fighters have a 65% chance to hit the enemy. One fighter deals 2d6 + 6 damage to represent the fighter with GWF and the other does 2d6+5 as a defense-fighter. The enemy has a 65% chance to hit the first fighter while they have a 60% chance to hit the second fighter.
The fighters are purely going to attack 4 times each before the enemy gets a chance to attack and deal anywhere from 30 - 70 damage. This approximates the damage that each fighter could be expected to take at level 20 in a single turn, its somewhat low because of situations where the enemy decides to do less damage but AoE, the enemy attacks somewhat else, the enemy is stunned, the fighter gets healed, etc.
The fighter's hp is set to 224. The enemy's HP is randomly chosen between 1 and 169 to represent uncertainty of their health from mooks to bosses (169 is the tarrasque's health divided by 4, to represent each other player pulling their weight).
The simulation outputs the number of times the fighter dies and the average number of turns each fighter needs to defeat the enemy per combat when they don't die.
I iterated this simulation 10,000 times. The output I got was:
Number of deaths for Fighter 1 (2d6+6 damage, 65% hit probability): 5616
Number of deaths for Fighter 2 (2d6+5 damage, 60% hit probability): 5475
Average turns for Fighter 1 (2d6+6 damage, 65% hit probability): 4.76
Average turns for Fighter 2 (2d6+5 damage, 60% hit probability): 5.15
The difference between the fighter's death are 141 deaths. Out of the 10,000 enemies, the +1 AC bonus mattered for 1.41% of them. In contrast, the +1 damage reduces the average turns needed to kill by 0.39, meaning that after 3 combats, you killed an enemy quicker than you would have without GWF.
I don't know about you, but I don't think I'll make it to 10,000 enemies in a campaign, and if I do, I don't think it wise to take the extra 1% extra death insurance rather than saving 333 rounds against an enemy. If not for survival purposes, it end the combat quicker.
If you have a problem with my assumptions and think that your assumptions would be more realistic, be my guest.
C:#include <stdio.h> #include <stdlib.h> #include <time.h> #define NUM_SIMULATIONS 10000 #define HP 224 // Function to simulate rolling two dice and adding the damage with a bonus int roll_damage(int bonus) { int roll1 = rand() % 6 + 1; int roll2 = rand() % 6 + 1; return roll1 + roll2 + bonus; } // Function to simulate the probability of getting hit int is_hit(double probability) { return (rand() % 100) < (probability * 100); } // Function to simulate the number of attacks before getting hit int attacks_before_hit(double attack_probability) { int attacks = 0; while (attacks < 4 && is_hit(attack_probability)) { attacks++; } return attacks; } // Function to simulate a single fighter's attempt to reach the target damage threshold int simulate_fighter(int target_damage, int damage_bonus, double hit_probability) { int current_damage = 0; int turns = 0; int hp = HP; while (current_damage < target_damage && hp > 0) { // Determine the number of attacks before the fighter is hit int num_attacks = attacks_before_hit(0.65); // Both fighters attack with 65% probability // Apply the attacks for (int i = 0; i < num_attacks; i++) { // Roll damage int damage = roll_damage(damage_bonus); current_damage += damage; turns++; // Check if the fighter gets hit after each attack if (is_hit(hit_probability)) { int attack_damage = rand() % 41 + 30; // Attack damage from 30 to 70 hp -= attack_damage; if (hp <= 0) { return -1; // Fighter lost all HP before reaching the target } } } } if (hp > 0) { return turns; // Return the number of turns required if the fighter survived } else { return -1; // Return -1 if the fighter died } } int main() { srand(time(NULL)); // Seed the random number generator int deaths_fighter1 = 0; int deaths_fighter2 = 0; double total_turns_fighter1 = 0; double total_turns_fighter2 = 0; int survivals_fighter1 = 0; int survivals_fighter2 = 0; for (int i = 0; i < NUM_SIMULATIONS; i++) { int target_damage = rand() % 169 + 1; // Random target damage between 1 and 169 // Simulate Fighter 1 int result1 = simulate_fighter(target_damage, 6, 0.65); if (result1 == -1) { deaths_fighter1++; } else { total_turns_fighter1 += result1; survivals_fighter1++; } // Simulate Fighter 2 int result2 = simulate_fighter(target_damage, 5, 0.60); // Updated hit probability to 60% if (result2 == -1) { deaths_fighter2++; } else { total_turns_fighter2 += result2; survivals_fighter2++; } } // Calculate average turns for each fighter double avg_turns_fighter1 = survivals_fighter1 > 0 ? total_turns_fighter1 / survivals_fighter1 : 0; double avg_turns_fighter2 = survivals_fighter2 > 0 ? total_turns_fighter2 / survivals_fighter2 : 0; // Print the results printf("Number of deaths for Fighter 1 (2d6+6 damage, 65%% hit probability): %d\n", deaths_fighter1); printf("Number of deaths for Fighter 2 (2d6+5 damage, 60%% hit probability): %d\n", deaths_fighter2); printf("Average turns for Fighter 1 (2d6+6 damage, 65%% hit probability): %.2f\n", avg_turns_fighter1); printf("Average turns for Fighter 2 (2d6+5 damage, 60%% hit probability): %.2f\n", avg_turns_fighter2); return 0; }
And if my code looks kinda like spaghetti, it is. I wanted to write in python, but it would take far too long for the code to run, so its in C which I barely know how to code. I got assistance from ChatGPT, so also feel free to scrutinize the code itself, but it seems passable from my review.
And yeah, I know, whiteboard analysis, but I think the results are dramatic enough and the simulation takes enough cases into account that we can at least use it as a rough guide to our thinking.
Edit: 1.41% not .014% and 10,000 instead of 1,000
Doesn’t your attacks before hit function always return 4 attacks?
Last edited: