Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="app">
  <h3>Axis & Allies Combat Simulator</h3>
  
  <p>Run a Monte Carlo simulation of a single <em>Axis & Allies</em> combat
     to evaluate your chances of winning.</p>
  
  <p><strong>Instructions:</strong> Enter the number of times you'd lke to
    run the simulation. 10,000 iterations or less is recommended, unless you
    have some time on your hands.</p>
  
  <p>Then, enter a string of letters corresponding to the units that will
     participate in the combat.</p>
  
  <p>
    <strong>Key</strong><br>
    <code>I</code> = "Infantry"<br>
    <code>T</code> = "Tank"<br>
    <code>F</code> = "Fighter"<br>
  </p>
  
  <h4>Run the sim</h4>
  <p>An interesting case to try is <code>IIITF</code> vs. <code>IIIII</code>,
     which seems to lead to a bimodal distribution of outcomes.<p>
  <form @submit.prevent="run">
    <div>
      <label>Simulation Count</label>
      <input type="number" v-model="simCount" />
    </div>
    <div>
      <label>Attacker Units</label>
      <input type="text" v-model="attackerListStr" />
    </div>
    <div>
      <label for="DefenderUnits">Defender Units</label>
      <input type="text" v-model="defenderListStr" />
    </div>
    <button type="submit">Run Sim</button>
  </form>
  
  <div v-if="results !== null">
    <hr>
    
    <h3>Sim Results</h3>
    <p>
      <strong>Sim Duration:</strong> {{ results.simDuration }}<br />
      <strong>Attacker Wins:</strong> {{ results.attackerWins }}<br />
      <strong>Defender Wins:</strong> {{ results.defenderWins }}<br />
      <strong>Draws:</strong> {{ results.draws }}<br />
      <strong>Success Chance:</strong>
        {{ (results.attackerWins / results.simCount) * 100 }}
    </p>
    
    <h4>Histogram</h4>
    <p>Each combat, we get the difference of leftover attacker IPCs
       and remaining defender IPCs. Larger numbers correspond to a 
       more decisive victory.</p>
    <table>
      <thead>
        <tr>
          <th>IPC Diff</th>
          <th>Frequency</th>
        </tr>
      </thead>
      
      <tbody>
        <tr v-for="(list, index) in Array.from(results.ipcDiffs)">
          <td>{{ list[0] }}</td>
          <td>{{ list[1] }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
              
            
!

CSS

              
                code {
  background-color: orange;
  padding: 0 0.25rem;
}

th, td {
  text-align: right;
  padding: 0 0.5rem;
}
              
            
!

JS

              
                const randBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)

const rollD6 = () => randBetween(1, 6)

class Unit {
  constructor(type, ipc, attack, defend) {
    this.type = type;
    this.ipc = ipc;
    this.attack = attack;
    this.defend = defend;
  }
}

const types = {
  I: new Unit("Infantry", 3, 1, 2),
  T: new Unit("Tank", 6, 3, 3),
  F: new Unit("Fighter", 10, 3, 4)
};

var app = new Vue({
  el: '#app',
  data() {
    return {
      simCount: 1000,
      attackerListStr: "IT",
      defenderListStr: "I",
      results: null
    };
  },
  methods: {
    buildUnitList(str) {
      const result = [];
      for (let i = 0; i < str.length; i++) {
        const unit = types[str[i]]
        if (unit) {
          result.push(unit);
        }
      }
      return result;
    },
    run() {
      this.results = null;
      const attackerList = this.buildUnitList(this.attackerListStr);
      const defenderList = this.buildUnitList(this.defenderListStr);

      // Run the simulation the number of times indicated by
      // `simCount` and keep track of attacker and defender wins.
      const timeStart = Date.now();
      let attackerWins = 0;
      let defenderWins = 0;
      let draws = 0;
      let ipcDiffs = new Map();
      for (let i = 0; i < this.simCount; i++) {
        // Run one combat at a time, take casualties
        // in order of the attacker and defender lists.
        let done = false;
        let attackerCasualties = 0;
        let defenderCasualties = 0;
        while (!done) {
          // Roll for each attacking unit remaining, and
          // tally new defender casualties. These will
          // not be applied until the end of the round.
          let newDefenderCasualties = 0;
          for (let i = attackerCasualties; i < attackerList.length; i++) {
            const unit = attackerList[i];
            const roll = randBetween(1, 6);
            if (roll <= unit.attack) {
              newDefenderCasualties++;
            }
          }

          // Roll for each defending unit remaining, and
          // tally the new attacker casualties
          let newAttackerCasualties = 0;
          for (let i = defenderCasualties; i < defenderList.length; i++) {
            const unit = defenderList[i];
            const roll = randBetween(1, 6);
            if (roll <= unit.defend) {
              newAttackerCasualties++;
            }
          }

          // Don't take more casualties than the number of units
          attackerCasualties = Math.min(
            (attackerCasualties += newAttackerCasualties),
            attackerList.length
          );
          defenderCasualties = Math.min(
            (defenderCasualties += newDefenderCasualties),
            defenderList.length
          );
        
          // Check win state
          const attackerLost = attackerCasualties === attackerList.length
          const defenderLost = defenderCasualties === defenderList.length
          done = attackerLost || defenderLost

          // Summarize the combat
          draws += attackerLost && defenderLost ? 1 : 0
          attackerWins += !attackerLost && defenderLost ? 1 : 0
          defenderWins += !defenderLost && attackerLost ? 1 : 0
          
          // Compute IPC Difference and Store
          if (done) {
            let attackerIPCs = 0
            for (let i = attackerCasualties; i < attackerList.length; i++) {
              attackerIPCs += attackerList[i].ipc
            }
            let defenderIPCs = 0
            for (let i = defenderCasualties; i < defenderList.length; i++) {
              defenderIPCs += defenderList[i].ipc
            }
            
            // Compute diff
            let diff = attackerIPCs - defenderIPCs
            
            // Increment counter for this diff
            ipcDiffs.set(
              String(diff),
              ipcDiffs.get(String(diff))
                ? ipcDiffs.get(String(diff)) + 1
                : 1 
            )
          }
        }
      }

      // Sort the ipcDiffs by key
      ipcDiffs = new Map([...ipcDiffs].sort((a, b) => a[0] > b[0] ? 1 : -1))

      // Summarize stats across all simulated combats
      this.results = {
        attackerWins,
        defenderWins,
        draws,
        ipcDiffs,
        successChance: attackerWins / this.simCount,
        simCount: this.simCount,
        simDuration: String(Date.now() - timeStart) + "ms",
      };
    }
  }
})
              
            
!
999px

Console