The demo for what I have is located here: http://jsfiddle.net/maniator/ueceeq7k/27/
const logger = ((logArea, logDelay = 0) => {
const playArea = document.getElementById(logArea);
return {
delay: logDelay,
log(...args) {
let div = document.createElement('div');
// Can see the result in the console
console.log(...args);
setTimeout(() => {
// append to the top of the log
playArea.insertBefore(div, playArea.firstChild);
div.textContent = args.join(', ')
}, this.delay);
this.delay += logDelay;
},
logPad(...args) {
this.log();
this.log(...args);
}
};
})('playArea', 120);
const Team = (() => {
const numberOfPlayers = 9;
return class Team {
constructor(name) {
this.name = name;
this.players = [];
this.listeners = [];
this.playerIndex = 0;
this.score = 0;
this.generatePlayers();
}
toString() {
return this.name;
}
gainRun() {
this.score++;
logger.log(`${this} now have ${this.score} runs`);
}
generatePlayers() {
for (let i = 0; i < numberOfPlayers; ++i) {
this.players.push(new Player(`${this} Player ${i + 1}`, this));
}
this.pitcher = new Pitcher(`${this} Pitcher`, this);
}
nextPlayer() {
this.playerIndex %= numberOfPlayers;
let nextPlayer = this.players[this.playerIndex++];
logger.log(`${nextPlayer} is up to bat`);
return nextPlayer;
}
pitchTo(otherTeam) {
let outs = 0;
while (outs < 3) {
let nextPlayer = otherTeam.nextPlayer();
let strikes = 0;
let balls = 0;
while (strikes < 3 && balls < 4) {
let pitch = this.pitcher.pitch();
let hit = nextPlayer.acceptPitch(strikes, balls);
if (hit.out) {
outs++;
logger.log(`${nextPlayer} hit the ball!`);
logger.log(`${nextPlayer} hit a ${hit.name}`);
break;
}
if (hit.bases === 0) {
if (hit.strike) {
strikes++;
logger.log(`${nextPlayer} swung and missed`);
} else {
if (pitch.strike) {
strikes++;
} else {
balls++;
}
logger.log(`${nextPlayer} waited and got a ${pitch.name}`);
}
} else {
logger.log(`${nextPlayer} hit the ball!`);
this.trigger('Hit', nextPlayer, hit);
logger.log(`${nextPlayer} got a ${hit.name}`);
break;
}
}
if (strikes >= 3) {
outs++;
logger.log(`${nextPlayer} struck out`);
} else if (balls >= 4) {
logger.log(`${nextPlayer} walked`);
this.trigger('Hit', nextPlayer, {
bases: 1,
});
}
}
}
addListener(object) {
if (!!object.trigger) {
this.listeners.push(object);
}
}
trigger() {
this.listeners.forEach((listener) => listener.trigger(...arguments))
}
};
})();
class Player {
constructor(name, team) {
this.name = name;
this.team = team;
}
toString() {
return this.name;
}
acceptPitch(strikes = 0, balls = 0) {
const random = Math.floor(Math.random() * 1000);
const swingRate = 500 - (75 * strikes) + (30 * balls);
if (random < swingRate) {
return {
name: 'swing and a miss',
bases: 0,
out: false,
strike: true,
};
} else if (random < 880) { // wait for the pitch or hit into an out
if (random > 830) {
return {
name: 'fly out',
bases: 0,
out: true,
};
} else if (random > 810) {
return {
name: 'ground out',
bases: 0,
out: true,
};
}
return {
name: 'wait',
bases: 0,
out: false,
};
} else if (random <= 1000) { // hit the ball
if (random > 940 && random < 970) {
return {
name: 'double',
bases: 2,
out: false,
};
}
else if (random >= 970 && random < 995) {
return {
name: 'triple',
bases: 3,
out: false,
};
}
else if (random >= 995) {
return {
name: 'homerun',
bases: 4,
out: false,
};
} else {
return {
name: 'single',
bases: 1,
out: false,
};
}
}
}
}
;
class Pitcher extends Player {
static get pitchTypes() {
// @todo math this SH*T up
return [{
name: 'strike',
strike: true,
}, {
name: 'ball',
strike: false,
}, {
name: 'strike',
strike: true,
},];
}
pitch() {
const types = Pitcher.pitchTypes;
const random = Math.floor(Math.random() * (types).length);
logger.log(`${this} threw the ball`);
return types[random];
}
}
;
const Stadium = ((diamondArea) => {
const diamondDiv = document.getElementById(diamondArea);
let firstBase = false,
secondBase = false,
thirdBase = false,
home = false;
return class Stadium {
constructor(a, b) {
// @todo checks that a and b are team objects
this.teams = [a, b];
}
set firstBase(player) {
if (firstBase && player) {
logger.log(`${firstBase} ran to second`);
this.secondBase = firstBase;
}
firstBase = player;
}
set secondBase(player) {
if (secondBase && player) {
logger.log(`${secondBase} ran to third`);
this.thirdBase = secondBase;
}
secondBase = player;
}
set thirdBase(player) {
if (thirdBase && player) {
logger.log(`${thirdBase} ran home`);
this.home = thirdBase;
}
thirdBase = player;
}
set home(player) {
player.team.gainRun();
}
single(player) {
this.firstBase = player;
logger.log(`${player} ran to first base`);
}
double(player) {
this.single(player);
this.secondBase = player;
this.firstBase = false;
logger.log(`${player} ran to second base`);
}
triple(player) {
this.double(player);
this.thirdBase = player;
this.secondBase = false;
logger.log(`${player} ran to third base`);
}
homerun(player) {
this.triple(player);
this.home = player;
this.thirdBase = false;
logger.log(`${player} ran to home base`);
}
get baseTypes() {
return [this.homerun, this.single, this.double, this.triple];
}
clear() {
firstBase = secondBase = thirdBase = false;
return this;
}
playGame(innings) {
let extraInnings = 0;
let [teamA, teamB] = this.teams;
logger.log(`${innings} inning game!`);
this.listenToTeamActions();
for (let i = 1; i <= innings; ++i) {
logger.logPad(`Playing inning ${i} of ${innings}`);
this.playInning(i);
}
while (teamA.score === teamB.score) {
extraInnings++;
logger.logPad(`EXTRA INNINGS!`);
logger.logPad(`Score: ${teamA}: ${teamA.score} to ${teamB}: ${teamB.score}`);
this.playInning(`EXTRA ${extraInnings}`);
}
logger.logPad(`GAME OVER${extraInnings ? ` WITH ${extraInnings} EXTRA INNINGS!` : '!'}`);
logger.logPad(`Score: ${teamA}: ${teamA.score} to ${teamB}: ${teamB.score}`);
}
playInning(index) {
let [teamA, teamB] = this.teams;
logger.logPad(`${teamB} are up to bat in inning ${index}`);
teamA.pitchTo(teamB);
this.clear();
logger.logPad(`${teamA} are up to bat in inning ${index}`);
teamB.pitchTo(teamA);
this.clear();
}
listenToTeamActions() {
let [teamA, teamB] = this.teams;
teamA.addListener(this);
teamB.addListener(this);
}
trigger(event, ...args) {
// @todo make first letter of event uppercase
if (!!this[`on${event}`]) {
this[`on${event}`](...args);
}
}
onHit(player, type) {
const baseTypes = this.baseTypes;
const numberOfBases = type.bases % 4;
baseTypes[numberOfBases].bind(this)(player);
}
};
})('diamond');
const mets = new Team('Mets');
const yankees = new Team('Yankees');
const citiField = new Stadium(mets, yankees);
console.log(mets, yankees);
citiField.playGame(9);