Skip to content

Instantly share code, notes, and snippets.

@timbrandin
Last active December 20, 2017 15:27
Show Gist options
  • Save timbrandin/6d0ee4851d9cae579e0c3f2e3c564920 to your computer and use it in GitHub Desktop.
Save timbrandin/6d0ee4851d9cae579e0c3f2e3c564920 to your computer and use it in GitHub Desktop.
Generate a linked list of people with support for couples, used to create the christmas chain (one person gives only to one other person).
// Unique list of people, list in list is a couple that for some reason only can give to a specific person.
const list = [
['person1', 'person2'], // couple
'person3',
'person4',
['person5', 'person6'], // couple
'person7',
];
// randomize the list of who gives to who.
const shuffle = arr => {
const array = [...arr];
const copy = [];
let n = arr.length;
let i;
// While there remain elements to shuffle.
while (n) {
// Pick a remaining element.
n -= 1;
i = Math.floor(Math.random() * n);
// And move it to the new array.
copy.push(array.splice(i, 1)[0]);
}
return copy;
};
// flattens the array into a one dimensional list.
const flatten = arr => [].concat(...arr.map( v => v instanceof Array ? flatten(val) : [val]))
// print the list of who gives to who.
const print = arr => {
const flat = flatten(arr);
for (let i = 0; i < flat.length; i += 1) {
console.log(flat[i], '=>', flat[(i + 1) % flat.length]);
}
};
print(shuffle(list));
@timbrandin
Copy link
Author

Notice I want to print two lines when finding a couple, and keep the couple as is and then link the right person to the next in the list.

this:

list = [
  [person1, person2]
  person3,
];

should result in:

person1 => person2
person2 => person3

The reason behind this is because some people just isn't capable spending time before to prepare, so in this case the couple can give internally to be part of the game anyways.

@ericwenn
Copy link

ericwenn commented Dec 20, 2017

A version that does not need the condition in the loop.

// unpacks the array into a one dimensional list.
const concat = arr => arr.reduce((acc, val) => acc.concat(val instanceof Array ? val : [val]), []);

// print the list of who gives to who.
const print = arr => {
  const unpacked = concat(arr);
  for (let i = 0; i < unpacked.length; i += 1) {
    console.log(unpacked[i], '=>', unpacked[(i + 1) % unpacked.length]);
  }
};

The inner arrays (the person who need to give to a specific person) are unpacked to a single linear list.

list = [
  [person1, person2],
  person3,
]

becomes:

list = [person1, person2, person3]

With this structure the print method will be a lot simpler.

Tested with the following seedable js random, to check the same result is achieved as in previous version.

// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript
let seed = 1;
function random() {
  const x = Math.sin(seed++) * 10000;
  return x - Math.floor(x);
}

@timbrandin
Copy link
Author

Nice work! Added it now.

Do you mean that it would be faster with the random number generator or just that you tested it with that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment