function generateFixtureList(numberTeams, numberLoops) {
  
  // adapted from bluebones.net fixture algorithm

  // default league: 10 teams, double round-robin for testing
  let numberOfTeams = 3;
  let numberOfLoops = 3;

  if (numberLoops === undefined) {
    numberLoops = numberOfLoops;
  }

  if (numberTeams === undefined) {
    numberTeams = numberOfTeams;
  }

  // if odd number of players add a "ghost"
  let ghost = false
  if (numberTeams % 2 == 1) {
    numberTeams++;
    ghost = true;
  }

  // generate the fixtures using the cyclic algorithm
  let totalRounds = numberTeams - 1;
  let matchesPerRound = numberTeams / 2;
  let rounds = {};

  for (let round = 0; round < totalRounds; round++) {
    for (let match = 0; match < matchesPerRound; match++) {
      let home = (round + match) % (numberTeams - 1);
      let away = (numberTeams - 1 - match + round) % (numberTeams - 1);
      // last team stays in the same place while the others rotate around it.
      if (match == 0) {
        away = numberTeams - 1;
      }
      // add one so teams are numbered 1 to numberOfTeams
      if (!rounds[round]) rounds[round] = {}
      rounds[round][match] = (home + 1) + " v " + (away + 1);
    }
  }

  // alternate so that home and away games are fairly evenly dispersed.
  let alternated = {};

  let evn = 0;
  let odd = Math.round(numberTeams / 2);
  for (let i = 0; i < totalRounds; i++) {
    if (i % 2 == 0) {
      alternated[i] = rounds[evn++];
    } else {
      alternated[i] = rounds[odd++];
    }
  }

  rounds = alternated;

  // last team can't be away for every game so flip them to home on odd rounds.
  for (let round = 0; round < totalRounds; round++) {
    if (round % 2 == 1) {
      rounds[round][0] = flip(rounds[round][0]);
    }
  }

  // check the array here
  //console.log('initial fixture list: ', rounds)

  // split the generated fixtures by " v " into two "columns" and return that array
  var rounds2 = [];
  for(i = 0; i < totalRounds; i++) {
    for(j = 0; j < matchesPerRound; j++) {
      //let fixture = (i + 1) + " v " + rounds[i][j]; // this version includes matchday number
      let fixture = rounds[i][j];
      rounds2.push(fixture.split(" v "))
    }
  }

  let baseLoopOdd = rounds2;
  let baseLoopEven = [];
  for(i = 0; i < rounds2.length; i++) {
    //baseLoopEven.push( [ rounds2[i][0], rounds2[i][2], rounds2[i][1] ] )    // includes MD num
    baseLoopEven.push( [ rounds2[i][1], rounds2[i][0] ] );
  }

  // invert fixtures for subsequent loops and push to rounds2
  for(i = 2; i <= numberLoops; i++) {
    if(i % 2 == 0) {
      rounds2 = rounds2.concat(baseLoopEven);
    }
    if(i % 2 == 1) {
      rounds2 = rounds2.concat(baseLoopOdd);
    }
  }

  return rounds2;

}

function flip(match) {
  let components = match.split(" v ");
  return components[1] + " v " + components[0];
}