78 lines
2 KiB
JavaScript
78 lines
2 KiB
JavaScript
var SecretSanta = function () {
|
|
|
|
this.names = [];
|
|
|
|
this.blacklists = Object.create( null );
|
|
};
|
|
|
|
|
|
SecretSanta.prototype.add = function ( name ) {
|
|
|
|
if ( this.names.indexOf( name ) !== -1 )
|
|
throw new Error( 'Cannot redefine ' + name );
|
|
|
|
this.names.push( name );
|
|
|
|
var subapi = { };
|
|
|
|
subapi.blacklist = function ( other ) {
|
|
|
|
if ( ! Object.prototype.hasOwnProperty.call( this.blacklists, name ) )
|
|
this.blacklists[ name ] = [];
|
|
|
|
if ( this.blacklists[ name ].indexOf( other ) === -1 )
|
|
this.blacklists[ name ].push( other );
|
|
|
|
return subapi;
|
|
|
|
}.bind( this );
|
|
|
|
return subapi;
|
|
|
|
};
|
|
|
|
SecretSanta.prototype.generate = function () {
|
|
|
|
var pairings = Object.create( null );
|
|
var candidatePairings = Object.create( null );
|
|
|
|
this.names.forEach( function ( name ) {
|
|
|
|
var candidates = _.difference( this.names, name );
|
|
|
|
if ( Object.prototype.hasOwnProperty.call( this.blacklists, name ) )
|
|
candidates = _.difference( candidates, this.blacklists[ name ] );
|
|
|
|
candidatePairings[ name ] = candidates;
|
|
|
|
}, this );
|
|
|
|
var findNextGifter = function () {
|
|
|
|
var names = Object.keys( candidatePairings );
|
|
|
|
var minCandidateCount = _.min( names.map( function ( name ) { return candidatePairings[ name ].length; } ) );
|
|
var potentialGifters = names.filter( function ( name ) { return candidatePairings[ name ].length === minCandidateCount; } );
|
|
|
|
return _.sample( potentialGifters );
|
|
|
|
};
|
|
|
|
while ( Object.keys( candidatePairings ).length > 0 ) {
|
|
|
|
var name = findNextGifter();
|
|
|
|
var pairing = _.sample( candidatePairings[ name ] );
|
|
delete candidatePairings[ name ];
|
|
|
|
Object.keys( candidatePairings ).forEach( function ( name ) {
|
|
candidatePairings[ name ] = _.without( candidatePairings[ name ], pairing );
|
|
} );
|
|
|
|
pairings[ name ] = pairing;
|
|
|
|
}
|
|
|
|
return pairings;
|
|
|
|
};
|