JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/worker" id="worker1">

var wrap = f => function(x) {
	if (typeof x !== "function") throw new Error("Parameter passed not a function");
  var ret = f(x);
  if (ret !== 'C' && ret !== 'D') throw new Error("Return value not 'C' or 'D'");
  return ret;
};

var compete = function(f1, f2) {
  var f1 = wrap(f1);
  var f2 = wrap(f2);
  var r1, r2;
  if (Math.random() < 0.5) {
    try {
      r1 = f1(f2);
    } catch (err) {
    	self.postMessage(['C', 'D']);
      return;
    }
    try {
   		r2 = f2(f1);
    } catch(err) {
    	self.postMessage(['D', 'C']);
      return;
    }
  } else {
  	try {
  		r2 = f2(f1);
    } catch (err) {
    	self.postMessage(['D', 'C']);
      return;
    }
    try {
    	r1 = f1(f2);
    } catch (err) {
    	self.postMessage(['C', 'D']);
      return;
    }
  }
  self.postMessage([r1, r2]);
};

var createFn = s => eval('(' + s + ')');
self.onmessage = function(e) {
	compete(createFn(e.data.f1), createFn(e.data.f2));
};

</script>

<div id="competitors">
</div>

JavaScript

var blobURL = window.URL.createObjectURL(new Blob([
  document.querySelector('#worker1').textContent
], {
  type: "text/javascript"
}));

var worker = new Worker(blobURL);

worker.onmessage = function(e) {
  console.log("Received: " + e.data);
};

var runCompetition = function(f1, f2) {
  return new Promise((resolve, reject) => {
    var resolved = false;
    worker.onmessage = function(e) {
      resolved = true;
      resolve(e.data);
    };
    worker.onerror = function(e) {
      resolved = true;
      reject(e);
    };
    setTimeout(function() {
      if (resolved) return;
      worker.terminate();
      reject("Took too long");
    }, 1000);
    worker.postMessage({
      f1: f1.toString(),
      f2: f2.toString()
    });
  });
};

var sleep = function(t) {
  return new Promise((resolve) => setTimeout(resolve, t));
}

async function runAll(competitors) {
  var N = 1000;
  var scores = [];
  var payoff = [
    [
      [2, 2],
      [0, 3]
    ],
    [
      [3, 0],
      [1, 1]
    ]
  ];
  var d = {
    'C': 0,
    'D': 1
  };
  for (let i = 0; i < competitors.length; ++i) {
    scores[i] = 0;
    $("#competitors").append(competitors[i].name + '<div class="score"></div><br />');
  }
  for (let i = 0; i < competitors.length; ++i) {
    for (let j = i; j < competitors.length; ++j) {
      for (let n = 0; n < N; ++n) {
        let result = await runCompetition(competitors[i], competitors[j]);
        let r1 = d[result[0]],
          r2 = d[result[1]];
        scores[i] += payoff[r1][r2][0];
        scores[j] += payoff[r1][r2][1];
        // comment out to run faster
        //await sleep(20);
      }
      $(".score").eq(i).text(scores[i]);
      $(".score").eq(j).text(scores[j]);
    }
  }
  console.log(scores);
}

/*
Competitors
*/

function cooperate(them) {
    return 'C';
}

function defect(them) {
    return 'D';
}

function nice(them) {
    // Do whatever they would do when faced with a cooperator
    return them(wrap(_ => 'C'));
}

function...