The Coffee Experiment

Mapping M1:
Zodiac | Month | Name | Assigned code |
---|---|---|---|

Aquarius | Jan—Feb | The Rebel | AQU |

Pisces | Feb—Mar | The Mystic | PIC1 |

Aries | Mar—Apr | The Warrior | ARI |

Taurus | Apr—May | The Bull | TAU |

Gemini | May—Jun | The Twins | GEM |

Cancer | Jun—Jul | The Moon | CAN |

Leo | Jul—Aug | The Leader | LEO |

Virgo | Aug—Sep | The Thinker | VIR |

Libra | Sep—Oct | The Judge | LIB |

Scorpio | Oct—Nov | The Phoenix | SCO |

Sagittarius | Nov—Dec | The Free Spirit | SAG |

Capricorn | Dec—Jan | The Professional | CAP |

Should be PIS, but I misread “pisces” as “pices”. Oops!

Pairings:
The straightforward way to choose pairings would be to do every 2-tuple $(A, B)$ where $A, B$ are both signs.
However, this would be $12^2 = 144$ pairings, and I don’t have time for that!
Instead let’s do unordered pairings—ie, if we do the pairing $(A, B)$, we don’t do $(B, A)$; there are only $78$ of these, which is more managable. There’s the issue, then, of in each pairing how to decide which sign should be A and which should be B. (Since our pairings are stored in plastic bags, we must distinguish them by designating one as “A” and one as “B”)
We want it to be such that each sign shows up 5-6 times as A, and 5-6 times as B (and once as both, when paired with itself), for the total of its 12 pairings.
The way we can do that is as follows: for a pairing of signs $s, \sigma$, if $\sigma$ is clockwise of $s$, then let $(A, B) = (s, \sigma)$; if $s$ is clockwise of $\sigma$, then let $(A, B) = (\sigma, s)$; if they are opposite, then let $A$ be chosen at random.
...
So I wrote a little program2 to do that, and here are the pairings:
NOTE: I actually decided to not include pairings against self!
(identifiers are randomized)
Number | Ident | A | B |
---|---|---|---|

01 | 63 | AQU | PIC |

02 | 51 | AQU | ARI |

03 | 44 | AQU | TAU |

04 | 64 | AQU | GEM |

05 | 52 | AQU | CAN |

06 | 31 | LEO | AQU |

07 | 32 | VIR | AQU |

08 | 62 | LIB | AQU |

09 | 55 | SCO | AQU |

10 | 20 | SAG | AQU |

11 | 37 | CAP | AQU |

12 | 03 | PIC | ARI |

13 | 10 | PIC | TAU |

14 | 08 | PIC | GEM |

15 | 14 | PIC | CAN |

16 | 28 | PIC | LEO |

17 | 05 | VIR | PIC |

18 | 17 | LIB | PIC |

19 | 23 | SCO | PIC |

20 | 66 | SAG | PIC |

21 | 59 | CAP | PIC |

22 | 42 | ARI | TAU |

23 | 41 | ARI | GEM |

24 | 33 | ARI | CAN |

25 | 16 | ARI | LEO |

26 | 30 | ARI | VIR |

27 | 53 | LIB | ARI |

28 | 25 | SCO | ARI |

29 | 24 | SAG | ARI |

30 | 34 | CAP | ARI |

31 | 46 | TAU | GEM |

32 | 40 | TAU | CAN |

33 | 57 | TAU | LEO |

34 | 29 | TAU | VIR |

35 | 48 | TAU | LIB |

36 | 36 | SCO | TAU |

37 | 13 | SAG | TAU |

38 | 09 | CAP | TAU |

39 | 11 | GEM | CAN |

40 | 47 | GEM | LEO |

41 | 60 | GEM | VIR |

42 | 12 | GEM | LIB |

43 | 26 | GEM | SCO |

44 | 15 | GEM | SAG |

45 | 45 | CAP | GEM |

46 | 35 | CAN | LEO |

47 | 19 | CAN | VIR |

48 | 06 | CAN | LIB |

49 | 18 | CAN | SCO |

50 | 54 | CAN | SAG |

51 | 39 | CAN | CAP |

52 | 38 | LEO | VIR |

53 | 22 | LEO | LIB |

54 | 21 | LEO | SCO |

55 | 43 | LEO | SAG |

56 | 61 | LEO | CAP |

57 | 01 | VIR | LIB |

58 | 65 | VIR | SCO |

59 | 04 | VIR | SAG |

60 | 27 | VIR | CAP |

61 | 02 | LIB | SCO |

62 | 50 | LIB | SAG |

63 | 58 | LIB | CAP |

64 | 07 | SCO | SAG |

65 | 49 | SCO | CAP |

66 | 56 | SAG | CAP |

`${IDENT} ${A or B}`

He will choose randomly from the box and make 1 pairing each day. He will keep track of which IDENT was chosen each day. I will record my experience of the pairing knowing the current date but not the IDENT. This way, neither of us ever know what coffee we’re drinking until the experiment concludes.
```
const signs = 'AQU PIC ARI TAU GEM CAN LEO VIR LIB SCO SAG CAP'.split(' ');
function index(sign) {
const idx = signs.indexOf(sign);
if (idx === -1) throw 'oops';
return idx;
}
// Compute modulus (NOT remainder)
function mod(n, m) {
return ((n % m) + m) % m;
}
function direction({ from, to }) {
const diff = mod( index(to) - index(from), 12 );
if (diff === 0 || diff === 6)
return 'none';
if (diff <= 5)
return 'cw';
if (diff >= 7)
return 'ccw';
throw diff;
}
const pairings = [];
for (let i = 0; i < signs.length; i++) {
for (let j = i + 1; j < signs.length; j++) {
const s1 = signs[i];
const s2 = signs[j];
const dir = direction({ from: s1, to: s2 });
const [A, B] = (
dir === 'none'
? (Math.random() < 0.5 ? [s1, s2] : [s2, s1])
: dir === 'cw'
? [s1, s2]
: dir === 'ccw'
? [s2, s1]
: null
);
pairings.push([A, B]);
}
}
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
const idxs = pairings.map((_, i) => i + 1);
const idxsr = shuffle([...idxs]);
const sf = i => ('' + i).padStart(2, '0');
for (let i = 0; i < pairings.length; i++) {
const [A, B] = pairings[i];
console.log(sf(idxs[i]), sf(idxsr[i]), A, B);
}
// Verify that math was correct
{
const counts = {};
for (const sign of signs)
counts[sign] = { A: 0, B: 0 };
for (const [A, B] of pairings) {
counts[A].A++;
counts[B].B++;
}
for (const sign of signs) {
console.log(
sign,
counts[sign].A,
counts[sign].B,
counts[sign].A + counts[sign].B,
);
}
}
```

Referenced by: