yairm210 / Unciv

Open-source Android/Desktop remake of Civ V
Mozilla Public License 2.0
8.52k stars 1.58k forks source link

Easy pickings for colourblindness support? #5722

Closed will-ca closed 2 years ago

will-ca commented 2 years ago

Version Git master.

Describe the bug I wrote a quick Python script to find nation colours that might be easily confused with different types of colourblindness.

It turns out that for deuteranomaly, which is apparently by far the most common type of colourblindness, there's only a handful of countries that are probably the most problematic:

>>> testNations(filternations=isPlayableNation, mindifference=0.1, minprevalence=0.01)

India and Denmark may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.099, Affects: ~4.0%)
Rome and Sweden may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.089, Affects: ~4.0%)
Rome and Korea may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.081, Affects: ~4.0%)
China and America may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.07, Affects: ~4.0%)
The Netherlands and Austria may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.058, Affects: ~4.0%)
India and Ethiopia may be hard to tell apart with:
    Deuteranomaly. (Diff: 0.033, Affects: ~4.0%)

Found 6 potentially problematic pairings.

For every other pairing of countries, the difference in either inner colour or outer colour is at least 10% of the dimensional width of the simulated colourblind colour-space (in which, for deuteranomaly, I'm currently just zeroing the Green RGB channel and then converting to YIQ).

For reference, the most similar nation colours with "normal"/"healthy" human vision, as measured in the same colour-space, have a distance of 0.11. The next most similar nation colours all have distances of at least 0.18.

>>> print(formatNationTestResults(dict([*testNations(filternations=isPlayableNation, mindifference=2, minprevalence=0.5).items()][-5:])))

Spain and Mongolia may be hard to tell apart with:
    Normal_Vision. (Diff: 0.2, Affects: ~100.0%)
Germany and The Maya may be hard to tell apart with:
    Normal_Vision. (Diff: 0.19, Affects: ~100.0%)
Korea and Ethiopia may be hard to tell apart with:
    Normal_Vision. (Diff: 0.18, Affects: ~100.0%)
Iroquois and Sweden may be hard to tell apart with:
    Normal_Vision. (Diff: 0.18, Affects: ~100.0%)
Babylon and America may be hard to tell apart with:
    Normal_Vision. (Diff: 0.11, Affects: ~100.0%)

Found 5 potentially problematic pairings.

So, in theory, if we slightly change just one of the colours on five different nations, then the distinguishability of every pair of nations with the most common form of colourblindness should hopefully be no worse than the distinguishability of Babylon and America with normal human vision, which I (with normal human vision) have never had much difficulty telling apart.

(Once you include protanopia, tritanopia, and different types of monochromacy, and when you include city states and increase the minimum required colour distance, then literally thousands of potentially problematic pairings are detected. But those conditions are apparently quite rare in comparison, and I already kinda see city state units as interchangeable anyway.)

The models that I'm using are all very crude. But I figure they're probably better than nothing.

yairm210 commented 2 years ago

First of, nice work! The real question is what do we do with this information. For example Babylon and America.

will-ca commented 2 years ago

Could just start tweaking values until they're all a minimum distance apart. But due to the huge number of potential collisions, I think that should probably be done semi-automatically. It wouldn't be a huge addition to the script for me to generate and PR new colours that should look mostly the same with normal vision but are hopefully clearer with colourblindness.

I was thinking the Python script could be a tool for modders and such. But accessibility could also be done dynamically in the program code instead of statically in JSONs. With a nearly 1:1 port of the script to Kotlin (and possibly the addition of more robust colourblindness simulation algorithms) it would be… "Fairly straightforward" to add an options menu enum/dropdown and a function on game load that slightly mutates any colours that are too close to each other in the same save file. That would also let different types of colourblindness all be equally accounted for.

I don't think Babylon and America are a problem. The distance listed is with normal vision, and I've personally generally been okay with telling them apart (with normal vision). Because they both only use the blue channel, which is apparently by far the rarest type of colourblindness, they're also not the biggest concern there (though, TBF, they'd both look completely pitch black to someone with blue colourblindness). Hence, I see them as a reference point for the minimum distinguishable difference— If two nations' colours have at least as much distance with colourblindness as Babylon and America do without it, then I figure they're probably fine.

BUT: The list of Civs in my original comment is only as good as the colour model I used to simulate them. I think the math should check out— Missing or abnormal red/green/blue photoreceptors, so block out that RGB channel. The wavelengths might be a tiny bit off, and it's technically a simulation of deuteranopia (missing green cones, rare-ish) instead of deuteranomaly (atypical green cones, pretty common), but the colours visible with deuteranomaly should be a strict superset of those visible with deuteranopia, so anything designed with this crude-ish simulation of deuteranopia should also work for anyone with deuteranomaly, I think. But there's obviously no substitute for actually asking someone with colourblindness if they can tell the colours apart, and I don't wanna be the guy that writes an ignorant model that may not help, so I'd be hesitant to make any concrete changes until/unless input is available from people who would be affected.

yairm210 commented 2 years ago

Closing this as "not actionable" - this is the beginning of something, but it's unclear what to do with this going forward