 
 }
 
+let backgroundQueue = DispatchQueue.global(qos: .background)
+let breedSemaphore = DispatchSemaphore(value: 0)
+var breedQueues = [DispatchQueue]()
+for i in 0..<5 {
+    breedQueues.append(DispatchQueue(label: "Breed Queue \(i)"))
+}
 
 struct Genetic {
     let mutationRate = 0.015
     let tournamentSize = 5
     let elitism = true
 
+    // this should only be called in one place to reduce race condition-related bugs
     func evolve(population: Population) -> Population {
         var newPop = Population(size: population.size, initialize: false)
 

                }
            }
        }
        //        print("end crossover")
        return child
    }


            offset = 1
        }

        // BREED
        let breedGroup = DispatchGroup()
        for i in offset..<population.size {
            breedQueues[i % breedQueues.count].async(group: breedGroup, execute: {
                let parent1 = self.select(from: population)
                let parent2 = self.select(from: population)
                let child = self.crossover(parent1: parent1, parent2: parent2)
                newPop[i] = child
            })
        }

        breedGroup.notify(queue: DispatchQueue(label: "Breed Completion"), execute: {
            breedSemaphore.signal()
        })

        breedSemaphore.wait()
        // MUTATE
        for i in offset..<population.size {
            newPop[i] = mutate(tour: newPop[i])
        }
