I have an array of colors that will populate a pie chart to act as a game spinner. I don\'t want the same colors to appear next to each other, making one huge chunk in the c
Despite appearances, this is non-trivial. As the commentator @antonio081014 points out, it's actually an algorithmic question, and (as @MartinR points out) is addressed here. Here's a very simple heuristic that (unlike the solution from @appzYourLife) is not an algorithm, but will work in most cases, and is much faster (O(n^2) rather than O(n!)). For randomness, simply shuffle the input array first:
func unSort(_ a: [String]) -> [String] {
// construct a measure of "blockiness"
func blockiness(_ a: [String]) -> Int {
var bl = 0
for i in 0 ..< a.count {
// Wrap around, as OP wants this on a circle
if a[i] == a[(i + 1) % a.count] { bl += 1 }
}
return bl
}
var aCopy = a // Make it a mutable var
var giveUpAfter = aCopy.count // Frankly, arbitrary...
while (blockiness(aCopy) > 0) && (giveUpAfter > 0) {
// i.e. we give up if either blockiness has been removed ( == 0)
// OR if we have made too many changes without solving
// Look for adjacent pairs
for i in 0 ..< aCopy.count {
// Wrap around, as OP wants this on a circle
let prev = (i - 1 >= 0) ? i - 1 : i - 1 + aCopy.count
if aCopy[i] == aCopy[prev] { // two adjacent elements match
let next = (i + 1) % aCopy.count // again, circular
// move the known match away, swapping it with the "unknown" next element
(aCopy[i], aCopy[next]) = (aCopy[next], aCopy[i])
}
}
giveUpAfter -= 1
}
return aCopy
}
var colors = ["blue", "red", "green", "red", "blue", "blue", "blue", "green"]
unSort(colors) // ["blue", "green", "blue", "red", "blue", "green", "blue", "red"]
// Add an extra blue to make it impossible...
colors = ["blue", "blue", "green", "red", "blue", "blue", "blue", "green"]
unSort(colors) //["blue", "green", "blue", "red", "blue", "blue", "green", "blue"]