Love Score

FROM THE MINDS OF TIM & MASHA

BEHIND THE SCENES OF

BEHIND THE SCENES OF

Love Score

FROM THE MINDS OF TIM & MASHA

BEHIND THE SCENES OF

Love Score

FROM THE MINDS OF TIM & MASHA

The Idea

It all sort of began in the internal Discord of Phoenix Nights, we have silly little bot games we all get so hooked onto and one of those was this fun love score meter. It was simple, and yet it occupied my staff for a good few hours on some days. This version of the game just showed a score between 1-100 and it was totally random.

Come Love Island preparation, and I really wanted to bring that same experience over to the Discord - to really connect people together in a whole new way. I reached out to Tim to put together a bot that will calculate the score between two users by identifying certain metrics.

Getting there was a rocky start, how do we define a score? What is the user experience supposed to be like? And what context of information can we give them?

We defined and settled on Roles as the main "user influenced" criteria. This was something I set up on the server long before I started inviting everyone into it. It felt fun, being able to choose a Jewel (Colour), a Zodiac (your Star Sign) and your Love Language (your expression of Love).

Then we wanted a unique footprint, something you couldn't influence however it was already a part of you.

So, lets reveal and pull apart the curtains.

If you prefer to keep it a mystery then I would suggest not reading any further!



















You have been warned!

How we calculated "Love"

How we calculated "Love"

Me & Tim, didn't want it to feel truly random. We wanted you all to feel the "weight" of your choices, to be able to calculate an idea of who would be a stronger match. Randomness would trivialise your choices, although we still wanted to create a nice distribution so the game felt fair and still had a slight "luck" to it.

So here's a breakdown of each component and how it contributes to the final score.


Account Age Score

The Account Age Score is calculated based on the creation timestamps of the users' accounts. Below is the logic:

  • Oldest Timestamp: A predefined timestamp representing the approximate creation date of their Discord account

  • Current Timestamp: The current time when the score is being calculated

  • Difference Calculation: The numerical difference between the creation timestamps of the two users is calculated

  • Score Calculation:

    • If both users have the same creation timestamp, they receive the maximum score of 1

    • Otherwise, the score is calculated inversely based on the age difference, ensuring it remains between 0 and 1 and is rounded to two decimal places.


Zodiac Sign Compatibility

A Zodiac Score is determined by a predefined matrix that assigns compatibility scores between different zodiac signs. The scores range from a minimum of 0.3 to a maximum of 0.95. The assessment of these scores were derived from popular astrology methodologies.

Data was looked at from astrology sources such as Cafe Astrology & Astro.com to understand popular matches and from there - we were able to derive some weighted values that made sense:


const zodiacCompatibility = {
  Aries:     { Aries: 0.7, Taurus: 0.6, Gemini: 0.9, Cancer: 0.5, Leo: 0.95, Virgo: 0.4, Libra: 0.6, Scorpio: 0.5, Sagittarius: 0.85, Capricorn: 0.4, Aquarius: 0.8, Pisces: 0.3 },
  Taurus:    { Aries: 0.6, Taurus: 0.8, Gemini: 0.5, Cancer: 0.85, Leo: 0.6, Virgo: 0.9, Libra: 0.65, Scorpio: 0.7, Sagittarius: 0.4, Capricorn: 0.9, Aquarius: 0.5, Pisces: 0.85 },
  Gemini:    { Aries: 0.9, Taurus: 0.5, Gemini: 0.8, Cancer: 0.4, Leo: 0.85, Virgo: 0.5, Libra: 0.95, Scorpio: 0.6, Sagittarius: 0.9, Capricorn: 0.45, Aquarius: 0.9, Pisces: 0.65 },
  Cancer:    { Aries: 0.5, Taurus: 0.85, Gemini: 0.4, Cancer: 0.85, Leo: 0.7, Virgo: 0.75, Libra: 0.6, Scorpio: 0.9, Sagittarius: 0.3, Capricorn: 0.8, Aquarius: 0.45, Pisces: 0.95 },
  Leo:       { Aries: 0.95, Taurus: 0.6, Gemini: 0.85, Cancer: 0.7, Leo: 0.85, Virgo: 0.6, Libra: 0.9, Scorpio: 0.5, Sagittarius: 0.95, Capricorn: 0.4, Aquarius: 0.8, Pisces: 0.55 },
  Virgo:     { Aries: 0.4, Taurus: 0.9, Gemini: 0.5, Cancer: 0.75, Leo: 0.6, Virgo: 0.8, Libra: 0.65, Scorpio: 0.75, Sagittarius: 0.45, Capricorn: 0.85, Aquarius: 0.5, Pisces: 0.9 },
  Libra:     { Aries: 0.6, Taurus: 0.65, Gemini: 0.95, Cancer: 0.6, Leo: 0.9, Virgo: 0.65, Libra: 0.85, Scorpio: 0.7, Sagittarius: 0.85, Capricorn: 0.55, Aquarius: 0.95, Pisces: 0.75 },
  Scorpio:   { Aries: 0.5, Taurus: 0.7, Gemini: 0.6, Cancer: 0.9, Leo: 0.5, Virgo: 0.75, Libra: 0.7, Scorpio: 0.85, Sagittarius: 0.55, Capricorn: 0.8, Aquarius: 0.5, Pisces: 0.9 },
  Sagittarius:{ Aries: 0.85, Taurus: 0.4, Gemini: 0.9, Cancer: 0.3, Leo: 0.95, Virgo: 0.45, Libra: 0.85, Scorpio: 0.55, Sagittarius: 0.9, Capricorn: 0.35, Aquarius: 0.95, Pisces: 0.65 },
  Capricorn: { Aries: 0.4, Taurus: 0.9, Gemini: 0.45, Cancer: 0.8, Leo: 0.4, Virgo: 0.85, Libra: 0.55, Scorpio: 0.8, Sagittarius: 0.35, Capricorn: 0.85, Aquarius: 0.5, Pisces: 0.75 },
  Aquarius:  { Aries: 0.8, Taurus: 0.5, Gemini: 0.9, Cancer: 0.45, Leo: 0.8, Virgo: 0.5, Libra: 0.95, Scorpio: 0.5, Sagittarius: 0.95, Capricorn: 0.5, Aquarius: 0.85, Pisces: 0.75 },
  Pisces:    { Aries: 0.3, Taurus: 0.85, Gemini: 0.65, Cancer: 0.95, Leo: 0.55, Virgo: 0.9, Libra: 0.75, Scorpio: 0.9, Sagittarius: 0.65, Capricorn: 0.75, Aquarius: 0.75, Pisces: 0.9 }
};

A little fun fact, we did explore FFXIV races to determine a compatibility but we opted out of this. I personally wasn't sure how to grade that sort of metric and it doesn't lend itself well to those who have a special defined roleplay race etc.

Zodiac signs was great as people are familiar with it, and already have an idea based on their birthdates - it was well on theme for an event centred around love & connections.


Jewel Compatibility

I love gemstones, and gemstones also can have colours to them. Love Island was all about colour harmonies and colour is a great expression of you. We all have our favourites, and i'm totally sorry I didn't have Silver & Black Jewels! They just wouldn't look great on Discord!

Jewel compatibilities was based around simple colour theory, opposite colours are complimentary and are great harmonies, whilst some neighbouring colours also had great strengths as matches.



By applying that idea, we can also create a matrix to define those scores. For this we defined it from 0.5 to 0.95

We varied colours of the same in their value to throw off the scores so it didn't seem obvious.


const jewelCompatibility = {
    Sapphire: {
        Sapphire: 0.75,
        Amber: 0.6,
        Ruby: 0.5,
        Emerald: 0.8,
        Pearl: 0.6,
        Topaz: 0.95
    },
    Amber: {
        Sapphire: 0.6,
        Amber: 0.75,
        Ruby: 0.7,
        Emerald: 0.5,
        Pearl: 0.9,
        Topaz: 0.7
    },
    Ruby: {
        Sapphire: 0.5,
        Amber: 0.7,
        Ruby: 0.8,
        Emerald: 0.95,
        Pearl: 0.85,
        Topaz: 0.75
    },
    Emerald: {
        Sapphire: 0.8,
        Amber: 0.5,
        Ruby: 0.95,
        Emerald: 0.8,
        Pearl: 0.6,
        Topaz: 0.5
    },
    Pearl: {
        Sapphire: 0.6,
        Amber: 0.9,
        Ruby: 0.85,
        Emerald: 0.6,
        Pearl: 0.8,
        Topaz: 0.55
    },
    Topaz: {
        Sapphire: 0.95,
        Amber: 0.7,
        Ruby: 0.75,
        Emerald: 0.5,
        Pearl: 0.55,
        Topaz: 0.75
    }
};

Love Language Compatibility

Love Language Compatibility

I applied this from my general philosophy of attraction, and how we determine what makes us connect with someone. Think like the idea of if someone is a swiss army knife in what they can do, it can seem intimidating with someone who just has one preferred language. It was also a good method to prevent "cheating". I know some of you got it figured out in the end.

Less was better, in fact - 1 Love Language would give you the strongest scores. Those who selected every single one to try and apply a match to anyone would suffer a negative penalty. This is the only weighted metric that applies negative values.

A base score of 0.95 is given if there is at least one matching love language role between the two users


Penalties for Extra Roles: If either user has additional roles beyond the first match, penalties are applied at a rate of 0.1 for each extra role. The score is adjusted to ensure it does not fall below 0.

In my definition of connecting with someone, if you share a specific interest in how you apply love and that's your main definition - then you would naturally be stronger. I thought about applying values between certain Love Languages but it's a lot of room for interpretation.

The value here is less is more.

Seeded Score Number Generation & Mersenne Twister

Seeded Score Number Generation & Mersenne Twister

Tim didn't like or want pure randomness, so we opted in using a pseudorandom generator to create an "idea" of randomness that had a fair distribution.

To get to that point, we needed first to create a digital signature between two matches and what better to do this than to use their display names. We avoided using Discord ID as we felt people may use their display names to properly represent their characters/individuality.

To turn names to numbers we first need to convert the names into a number. We mix the names together with a piece of information called "salt" to ensure varied outcomes.

We then generate a SHA-256 Hash out of this, it's just a long string of characters. We extract the number from this by taking the first few characters and converting that to a number.

Then we apply something that's known as a Mersenne Twister, it is an algorithm used for generating pseudo-random numbers, widely used in Cryptography and simulations. Was developed by Makoto Matsumoto & Takuji Nishimura in 1997.

Pseudo random generators are not like true random numbers, they are deterministic - it means if you start with a "seed" it will always generate the same sequence numbers.

The algorithm maintains an internal state vector of 624 integers (each 32 bits).

The number we generate is a score between 0 and 1. This is a digital footprint between two users. This was probably the metric that really made scores varied despite having a solid match from the other scores. This was the slight luck component.

The final score formula

We aggregate all the scores from the above vectors. We then multiply this by 1000. Then we add a slight fractional part of the total score to "amplify" the values very slightly. We round it to the nearest integer and that's how we derive your score.

Final Score = Round(((Zodiac Score + Age Score + Jewel Score + Love Language Score + Seeded Score) * 1000) + (Fractional Part of Total Score))

You're probably interested to know the actual ceiling value, the highest attainable score.

It is 4851.

We actually added a special trigger if anyone got close to 100 of this score, which would have to pass all the checks in being as close to perfection by all the vectors. It is possible and achievable but no one managed to get to it!

Closing Statistics from Game End

Closing Statistics from Game End

Total Scores: 2936

Average Score: 3050.83

Minimum Score: 1389

Maximum Score: 4589

Median Score: 3043.50

Total Unique Users Matched: 438

Scores Above Average: 1455

User Match Statistics

Most Matches: 236

Average Matches per User: 13.41

Median Matches per User: 5.00

This unfortunately included the bots in this statistic, it was quite amusing to see a Bot reach the Top 10. Thankfully we patched out that very quickly, you cheeky bunch!

To ensure absolute fairness, myself (Masha) and Tim removed ourselves from getting to the scoreboard, that would be controversial!

Closing the results & deciding the Winners

Closing the results & deciding the Winners

Following #chugate in which we saw Chu dominate the Top 10 by 6 entries, I decided to not include duplicates. So their highest matches are only counted.

You can see the winners over on the Discord!

Safe to say, I think me & Tim need to go outside more.