Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Implementation of Secret Santa sort
/*
Small program written to automate the sorting of Secret Santas as initially brought to my attention by Brent Simmons (http://inessential.com/2015/09/25/a_secret_santa_solution).
*/
import Foundation
let DEBUG = false
class Person: Equatable {
var first: String
var last: String
var email: String
var match: Person?
var matched = false
init(first: String, last: String, email: String, match: Person?) {
self.first = first
self.last = last
self.email = email
self.match = match
}
func canBeSantaOf(p: Person) -> Bool {
return self.match == nil && self.last != p.last && !p.matched
}
}
func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.first == rhs.first && lhs.last == rhs.last
}
var people = [Person]()
let standardInput = NSFileHandle.fileHandleWithStandardInput()
let input = standardInput.availableData
let str = NSString(data: input, encoding: NSUTF8StringEncoding) as! String
let linesArr = str.characters.split{$0 == "\n"}.map(String.init)
for line in linesArr {
let details = line.characters.split{$0 == " "}.map(String.init)
let p = Person(first: details[0], last: details[1], email: details[2], match: nil)
people.append(p)
}
var validInput = true
if people.count > 1 {
var currIdx = 0
var pos = 1
var curr = people[currIdx]
var possible = people[pos]
// Effectively we're treating our array of people as a circular list
// that we navigate "top" to "bottom" until we can find a valid match
// or until we run back into ourselves at which point we exit with
// no match. This no match will then be confirmed by our validation
// at the end of the program.
while curr.match == nil && curr != possible {
if DEBUG {
print("curr: \(curr.first)")
print("possible: \(possible.first)")
print("pos: \(pos)")
print("currIdx: \(currIdx)")
print("*****")
}
if curr.canBeSantaOf(possible) {
if DEBUG {
print("Matching \(curr.first) with \(possible.first)")
}
curr.match = possible
possible.matched = true
currIdx++
if currIdx >= people.count {
currIdx = 0
}
curr = people[currIdx]
pos = currIdx + 1
if pos >= people.count {
pos = 0
}
possible = people[pos]
} else {
pos++
if pos >= people.count {
pos = 0
}
possible = people[pos]
}
}
} else {
validInput = false
}
// Finally, validate our results by doing a once-over on the array of people
for p in people {
if p.match == nil || p.matched == false {
validInput = false
}
}
print("************* RESULTS **************")
if !validInput {
print("Invalid input according to rules of Secret Santa matching")
} else {
for p in people {
print("\(p.first) \(p.last) matched \(p.match!.first) \(p.match!.last)")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment