Compare commits
7 Commits
12d85d9796
...
feature/ge
| Author | SHA1 | Date | |
|---|---|---|---|
| bda5479b93 | |||
| d5c155953b | |||
| 36795bd974 | |||
| ae60b47ad3 | |||
| adb9e93cdb | |||
| 3aa9ac9811 | |||
| b72e0a9d9a |
@@ -291,7 +291,7 @@ public class ApplicationContext : DbContext
|
||||
(string Name, string Genotype, int SortOrder)[] catalog =
|
||||
{
|
||||
// --- C-locus white / partial albino (IDs 1-3) ---
|
||||
("Pink Eyed White (PEW)", "AA chch DD EE GG pp spsp rere", 0),
|
||||
("REW", "AA chch DD EE GG pp spsp rere", 0),
|
||||
("Hermelin", "aa chch DD EE GG PP spsp rere", 1),
|
||||
("Himalaya", "AA chch DD EE GG PP spsp rere", 2),
|
||||
// --- Zobel / colourpoint dark (ID 4) ---
|
||||
|
||||
1430
GerbilManagerWebAPI/Migrations/20260606231220_RenameREW.Designer.cs
generated
Normal file
1430
GerbilManagerWebAPI/Migrations/20260606231220_RenameREW.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
GerbilManagerWebAPI/Migrations/20260606231220_RenameREW.cs
Normal file
33
GerbilManagerWebAPI/Migrations/20260606231220_RenameREW.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GerbilManagerWebAPI.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RenameREW : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000001"),
|
||||
column: "Name",
|
||||
value: "REW");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000001"),
|
||||
column: "Name",
|
||||
value: "Pink Eyed White (PEW)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ namespace GerbilManagerWebAPI.Migrations
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000001"),
|
||||
CanonicalGenotype = "AA chch DD EE GG pp spsp rere",
|
||||
Name = "Pink Eyed White (PEW)",
|
||||
Name = "REW",
|
||||
SortOrder = 0
|
||||
},
|
||||
new
|
||||
|
||||
@@ -50,28 +50,30 @@ Weitere Eigenschaften lassen sich jederzeit **additiv** ergänzen (1-Zeilen-Änd
|
||||
|
||||
Durch die vielen neuen Stammbaum-Dateien sind **13 neue Konflikt-Tiere** aufgetaucht (**7 erledigt:** Kazumi/Filou/Sokrates/Osamu/Percy/Iwana/Eragon ✅ — **6 offen**) (gleicher Name+Datum, widersprüchliche Angaben in mehreren Diagrammen). Sie warten in Quarantäne — **nichts ist verloren**, sie laden automatisch nach, sobald du je Tier kurz sagst was stimmt. (Uw=G + „Vorhandensein gewinnt" sind schon angewendet; das hier ist der echte Rest.)
|
||||
|
||||
_Quelldatei = die Stammbaum-Datei(en) in `C:\Users\gulum\dev\Sttammbäume\`, in denen das Tier vorkommt. **Mehrere Dateien = Ursache des Konflikts** (widersprüchliche Angaben in verschiedenen Diagrammen)._
|
||||
|
||||
**A) Nur Sterbedatum offen** (Gencode einig — bei Osamu/Filou/Sunny zusätzlich „taub" beibehalten):
|
||||
| Tier | Sterbedatum — welches? |
|
||||
|---|---|
|
||||
| Isa of Golden Lights (*24.12.2014) | 21.07.2018 ↔ 21.10.2018 |
|
||||
| Jack II v.d. K.C. (*14.02.2016) | 06.10.2019 ↔ 20.10.2019 |
|
||||
| ~~Osamu v.d. K.C. (*10.12.2015)~~ ✅ | **18.12.2020** (erledigt) |
|
||||
| ~~Filou v.d. K.C. (*24.11.2014)~~ ✅ | **31.08.2019** (erledigt) |
|
||||
| Sunny von PZ Karl (*10.04.2014) | 30.04.2019 ↔ 05.05.2019 |
|
||||
| Tier | Sterbedatum — welches? | Quelldatei(en) |
|
||||
|---|---|---|
|
||||
| Isa of Golden Lights (*24.12.2014) | 21.07.2018 ↔ 21.10.2018 | Stammbaum von **Ella**.xlsx · von **Kalea**.xlsx |
|
||||
| Jack II v.d. K.C. (*14.02.2016) | 06.10.2019 ↔ 20.10.2019 | Stammbaum von **Kalea**.xlsx · von **Rainny**.xlsx · von **Ren**.xlsx |
|
||||
| ~~Osamu v.d. K.C. (*10.12.2015)~~ ✅ | **18.12.2020** (erledigt) | — |
|
||||
| ~~Filou v.d. K.C. (*24.11.2014)~~ ✅ | **31.08.2019** (erledigt) | — |
|
||||
| Sunny von PZ Karl (*10.04.2014) | 30.04.2019 ↔ 05.05.2019 | Stammbaum von **Vance**.xlsx · von **Yurikas und Pintos Sohn**.xlsx |
|
||||
|
||||
**B) Gencode-Konflikt** (+ ggf. Sterbedatum):
|
||||
| Tier | Konflikt — was stimmt? |
|
||||
|---|---|
|
||||
| Milon v.d. K.C. (*27.11.2014) | A-Locus: **Aa** ↔ **aa** |
|
||||
| ~~Percy of little runners (*16.12.2017)~~ ✅ | P-Locus **Pp** (erledigt) |
|
||||
| ~~Iwana of little runners (*02.10.2018)~~ ✅ | P-Locus **Pp** (erledigt) |
|
||||
| ~~Sokrates v.d. K.C. (*14.12.2015)~~ ✅ | **D-** + Sterbedatum **20.05.2019** (erledigt) |
|
||||
| ~~Eragon (Elieus, *18.05.2016)~~ ✅ | C **CC** (vollfarbig) + Name **„Elieus gen. Eragon"**. Korrekter Datensatz lädt bereits (CC); Colourpoint-Variante „Kleiner Warnowrenner …" bleibt als Dublette in Quarantäne — kein weiterer Schritt nötig. |
|
||||
| Dakota of sweet little mouse (*30.01.2015) | A: **Aa**↔**aa** · P: **pp**↔**PP** · Sp: **Spsp**↔**spsp** |
|
||||
| ~~Kazumi v.d. K.C. (*23.04.2013)~~ ✅ | **Aa Cc[chm] DD ee[f] GG PP Spsp** (erledigt) |
|
||||
| Max von Privat (*01.02.2013) | D: **D-**↔**DD** · P: **P-**↔**PP** · Sterbedatum (4 Varianten: 04.02.2016 / 04.03.2016 / 2014 / 30.12.2015) |
|
||||
| Tier | Konflikt — was stimmt? | Quelldatei(en) |
|
||||
|---|---|---|
|
||||
| Milon v.d. K.C. (*27.11.2014) | A-Locus: **Aa** ↔ **aa** | Stammbaum von **South Dakota**.xlsx · von **Tennessee**.xlsx |
|
||||
| ~~Percy of little runners (*16.12.2017)~~ ✅ | P-Locus **Pp** (erledigt) | — |
|
||||
| ~~Iwana of little runners (*02.10.2018)~~ ✅ | P-Locus **Pp** (erledigt) | — |
|
||||
| ~~Sokrates v.d. K.C. (*14.12.2015)~~ ✅ | **D-** + Sterbedatum **20.05.2019** (erledigt) | — |
|
||||
| ~~Eragon (Elieus, *18.05.2016)~~ ✅ | C **CC** (vollfarbig) + Name **„Elieus gen. Eragon"**. Korrekter Datensatz lädt bereits (CC); Colourpoint-Variante „Kleiner Warnowrenner …" bleibt als Dublette in Quarantäne — kein weiterer Schritt nötig. | — |
|
||||
| Dakota of sweet little mouse (*30.01.2015) | A: **Aa**↔**aa** · P: **pp**↔**PP** · Sp: **Spsp**↔**spsp** | Stammbaum von **Jiminy of Black Forest**.xlsx · von **Yurikas und Pintos Sohn**.xlsx |
|
||||
| ~~Kazumi v.d. K.C. (*23.04.2013)~~ ✅ | **Aa Cc[chm] DD ee[f] GG PP Spsp** (erledigt) | — |
|
||||
| Max von Privat (*01.02.2013) | D: **D-**↔**DD** · P: **P-**↔**PP** · Sterbedatum (4 Varianten: 04.02.2016 / 04.03.2016 / 2014 / 30.12.2015) | Stammbaum von **Danako**.xlsx · von **Kalea**.xlsx · von **Vance**.xlsx · von **Wildfire und Vestras Kids**.xlsx · von **Yurikas und Pintos Sohn**.xlsx |
|
||||
|
||||
*(Alle Gencode-Varianten + Quelldateien: `tools/import/output/review-report.md`.)*
|
||||
*(Alle Gencode-Varianten + Quelldateien-Details: `tools/import/output/review-report.md`.)*
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ describe('Fraction', () => {
|
||||
describe('Genotype serialization', () => {
|
||||
it('round-trips display string <-> structured form', () => {
|
||||
const g = fromDisplayString('Aa CC Dd EE GG Pp Spsp rere')
|
||||
expect(toDisplayString(g)).toBe('Aa CC Dd EE GG Pp Spsp rere')
|
||||
expect(toDisplayString(fromJSON(toJSON(g)))).toBe('Aa CC Dd EE GG Pp Spsp rere')
|
||||
expect(toDisplayString(g)).toBe('Aa CC Dd EE GG Pp Spsp')
|
||||
expect(toDisplayString(fromJSON(toJSON(g)))).toBe('Aa CC Dd EE GG Pp Spsp')
|
||||
})
|
||||
|
||||
it('parses multi-char C-series alleles via maximal munch', () => {
|
||||
@@ -72,8 +72,8 @@ describe('Genotype serialization', () => {
|
||||
expect(g.P).toEqual(['P', 'p'])
|
||||
})
|
||||
|
||||
it('wild type is AA CC DD EE GG PP spsp rere', () => {
|
||||
expect(toDisplayString(wildType())).toBe('AA CC DD EE GG PP spsp rere')
|
||||
it('wild type is AA CC DD EE GG PP spsp (rere omitted)', () => {
|
||||
expect(toDisplayString(wildType())).toBe('AA CC DD EE GG PP spsp')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -102,7 +102,7 @@ describe('Worked example from research report', () => {
|
||||
|
||||
expect(result.offspring).toHaveLength(1)
|
||||
const only = result.offspring[0]
|
||||
expect(only.genotype).toBe('Aa CC DD EE GG Pp spsp rere')
|
||||
expect(only.genotype).toBe('Aa CC DD EE GG Pp spsp')
|
||||
expect(only.probability.text).toBe('1')
|
||||
expect(result.warnings).toHaveLength(0)
|
||||
})
|
||||
@@ -185,15 +185,11 @@ describe('Farbschlag catalog', () => {
|
||||
})
|
||||
|
||||
it('frozen contract names round-trip to themselves (DB-key guard)', () => {
|
||||
// The first 18 are the frozen ColorVariety keys — their representative
|
||||
// genotype MUST resolve back to their own name, never a later variety.
|
||||
// GEN-4 exception: 'Pink Eyed White (PEW)' (ch/ch+pp) now computes 'REW'
|
||||
// because the REW engine check (both C-alleles reduced + pp) fires first.
|
||||
// PEW stays in the catalog as a user-pickable import name; its computed
|
||||
// farbschlag is intentionally 'REW' per Julian's extended rule.
|
||||
const REW_SHADOWED = new Set(['Pink Eyed White (PEW)'])
|
||||
// The first 17 frozen ColorVariety keys — their representative genotype
|
||||
// MUST resolve back to their own name, never a later variety.
|
||||
// GEN-4c: 'REW' (formerly 'Pink Eyed White (PEW)') round-trips correctly:
|
||||
// chch+pp → REW engine check → 'REW' = entry.name.
|
||||
for (const entry of BASE_COLORS.slice(0, FROZEN_COUNT)) {
|
||||
if (REW_SHADOWED.has(entry.name)) continue
|
||||
expect(genotypeToFarbschlag(representativeGenotype(entry))).toBe(entry.name)
|
||||
}
|
||||
})
|
||||
@@ -224,11 +220,12 @@ describe('Farbschlag catalog', () => {
|
||||
|
||||
it('CATALOG seed view mirrors the ColorVariety table shape', () => {
|
||||
expect(CATALOG).toHaveLength(CATALOG_SIZE)
|
||||
expect(CATALOG[0]).toMatchObject({ name: 'Pink Eyed White (PEW)', sortOrder: 0 })
|
||||
expect(CATALOG[0]).toMatchObject({ name: 'REW', sortOrder: 0 })
|
||||
// Every row has a non-empty canonical genotype display string and unique name.
|
||||
// GEN-3h: bracket notation (e[f], c[chm], c[h]) allowed in tokens.
|
||||
// GEN-4d: rere omitted from display -> 7 tokens (no Rex, no Sls), 8 (Rex or Sls), 9 (both).
|
||||
expect(new Set(CATALOG.map((c) => c.name)).size).toBe(CATALOG.length)
|
||||
expect(CATALOG.every((c) => /^[A-Za-z[\]?-]+( [A-Za-z[\]?-]+){7}$/.test(c.canonicalGenotype))).toBe(true)
|
||||
expect(CATALOG.every((c) => /^[A-Za-z[\]?-]+( [A-Za-z[\]?-]+){6,8}$/.test(c.canonicalGenotype))).toBe(true)
|
||||
})
|
||||
|
||||
it('genotypeToFarbschlag (DATA-1 denormalization contract) returns the plain name', () => {
|
||||
@@ -289,7 +286,7 @@ describe('GEN-3a: Uw=G alias', () => {
|
||||
it('always RENDERS G, never Uw (breeder preference)', () => {
|
||||
// Uw/uw is an input/import alias only; output must echo G/g.
|
||||
expect(toDisplayString(fromDisplayString('AA CC DD EE Uwuw PP spsp rere'))).toBe(
|
||||
'AA CC DD EE Gg PP spsp rere',
|
||||
'AA CC DD EE Gg PP spsp',
|
||||
)
|
||||
expect(toDisplayString(fromDisplayString('AA CC DD EE uwuw PP spsp rere'))).not.toContain('uw')
|
||||
})
|
||||
@@ -301,10 +298,16 @@ describe('GEN-3a: second spotting locus Sls (WP)', () => {
|
||||
expect(fromDisplayString('AA CC DD EE GG PP spsp rere WP').Sls).toEqual(['Sl', 'sl'])
|
||||
})
|
||||
|
||||
it('toDisplayString omits wild-type Sls but shows Slsl', () => {
|
||||
expect(toDisplayString(wildType())).toBe('AA CC DD EE GG PP spsp rere')
|
||||
it('toDisplayString omits wild-type Sls and Re, shows Slsl/Rere when non-wildtype', () => {
|
||||
// GEN-4d: Re (rere) omitted at wildtype, like Sls.
|
||||
expect(toDisplayString(wildType())).toBe('AA CC DD EE GG PP spsp')
|
||||
// Rex het → Rere shown
|
||||
expect(toDisplayString(fromDisplayString('AA CC DD EE GG PP spsp Rere'))).toBe(
|
||||
'AA CC DD EE GG PP spsp Rere',
|
||||
)
|
||||
// WP → Slsl shown, rere still omitted
|
||||
expect(toDisplayString(fromDisplayString('AA CC DD EE GG PP spsp rere WP'))).toBe(
|
||||
'AA CC DD EE GG PP spsp rere Slsl',
|
||||
'AA CC DD EE GG PP spsp Slsl',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -334,7 +337,7 @@ describe('GEN-3a: second spotting locus Sls (WP)', () => {
|
||||
describe('GEN-3a: flag/metadata tokens tolerated', () => {
|
||||
it('dea/taub/Dea/DP/WFNZ/RV/GV do not break parsing (stripped)', () => {
|
||||
const g = fromDisplayString('AA CC DD EE GG PP spsp rere dea WFNZ DP RV GV')
|
||||
expect(toDisplayString(g)).toBe('AA CC DD EE GG PP spsp rere')
|
||||
expect(toDisplayString(g)).toBe('AA CC DD EE GG PP spsp')
|
||||
})
|
||||
|
||||
it('extractGenotypeFlags reads deafness + tags', () => {
|
||||
@@ -367,11 +370,11 @@ describe("GEN-3c: unknown allele displays as '-' (stored as '?')", () => {
|
||||
it("accepts '-' input, stores '?', displays '-'", () => {
|
||||
const g = fromDisplayString('Aa C- DD EE GG Pp spsp rere')
|
||||
expect(g.C).toEqual(['C', '?']) // stored internal contract stays '?'
|
||||
expect(toDisplayString(g)).toBe('Aa C- DD EE GG Pp spsp rere') // displayed as '-'
|
||||
expect(toDisplayString(g)).toBe('Aa C- DD EE GG Pp spsp') // displayed as '-'
|
||||
})
|
||||
it("'?' and '-' inputs are equivalent", () => {
|
||||
expect(toDisplayString(fromDisplayString('Aa C? DD EE GG Pp spsp rere'))).toBe(
|
||||
'Aa C- DD EE GG Pp spsp rere',
|
||||
'Aa C- DD EE GG Pp spsp',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -396,10 +399,10 @@ describe('GEN-3c: no Unbekannt when the E locus is known (family fallback)', ()
|
||||
|
||||
describe('GEN-3d: dominance tiebreak for unknown loci', () => {
|
||||
it('unknown-C reads as full-colour, NOT a c^h/c^chm white', () => {
|
||||
// 'aa C- DD EE GG PP' -> Schwarz (dominant C reading), never PEW/Hermelin/Himalaya.
|
||||
// 'aa C- DD EE GG PP' -> Schwarz (dominant C reading), never REW/Hermelin/Himalaya.
|
||||
const name = genotypeToFarbschlag(fromDisplayString('aa C- DD EE GG PP spsp rere'))
|
||||
expect(name).toBe('Schwarz')
|
||||
expect(['Pink Eyed White (PEW)', 'Hermelin', 'Himalaya']).not.toContain(name)
|
||||
expect(['REW', 'Hermelin', 'Himalaya']).not.toContain(name)
|
||||
})
|
||||
|
||||
it('unknown second marker allele defaults UNMARKED, not Schecke (marker-aware)', () => {
|
||||
@@ -549,15 +552,16 @@ describe('GEN-4: Dilute prefix, REW, no-bare-Fuchs', () => {
|
||||
})
|
||||
|
||||
it('REW: both C alleles reduced (no full C) + pp = REW — all three cases (Julian confirmed)', () => {
|
||||
// hom cchm/cchm + pp
|
||||
expect(name('AA cchmcchm DD EE GG pp spsp rere')).toBe('REW') // CP-Gold
|
||||
// hom cchm/cchm + pp — A/D/E/G-independent (REW-2: Julian: "egal ob AA oder aa")
|
||||
expect(name('AA cchmcchm DD EE GG pp spsp rere')).toBe('REW') // CP-Gold (A-)
|
||||
expect(name('aa cchmcchm DD EE GG pp spsp rere')).toBe('REW') // aa: REW-2 verification
|
||||
expect(name('AA cchmcchm DD ee GG pp spsp rere')).toBe('REW') // CP-Goldfuchs
|
||||
expect(name('AA cchmcchm DD EE gg pp spsp rere')).toBe('REW') // CP-Elfenbein
|
||||
expect(name('AA cchmcchm DD ee gg pp spsp rere')).toBe('REW') // CP-Apricot
|
||||
expect(name('AA cchmcchm dd EE GG pp spsp rere')).toBe('REW') // CP-dd Gold
|
||||
// het cchm/ch + pp (Julian: also REW)
|
||||
expect(name('AA cchmch DD EE GG pp spsp rere')).toBe('REW')
|
||||
// ch/ch + pp (Julian: also REW — subsumes PEW)
|
||||
// ch/ch + pp (Julian: also REW; PEW renamed to REW in catalog per GEN-4c)
|
||||
expect(name('AA chch DD EE GG pp spsp rere')).toBe('REW')
|
||||
expect(name('aa chch DD EE GG pp spsp rere')).toBe('REW')
|
||||
// Counterproof: full C present → NOT REW (residual pigment)
|
||||
@@ -593,15 +597,15 @@ describe('GEN-3h: breeder bracket-notation display + E-locus e-before-ef order',
|
||||
it('ef displays as e[f], cchm as c[chm], ch as c[h]', () => {
|
||||
// Fuchsschimmel: E=[ef,ef] hom
|
||||
expect(toDisplayString(fromDisplayString('AA CC DD efef GG PP spsp rere'))).toBe(
|
||||
'AA CC DD e[f]e[f] GG PP spsp rere',
|
||||
'AA CC DD e[f]e[f] GG PP spsp',
|
||||
)
|
||||
// C-locus het: cchm + ch
|
||||
expect(toDisplayString(fromDisplayString('aa cchmch DD EE GG PP spsp rere'))).toBe(
|
||||
'aa c[chm]c[h] DD EE GG PP spsp rere',
|
||||
'aa c[chm]c[h] DD EE GG PP spsp',
|
||||
)
|
||||
// C-locus hom cchm
|
||||
expect(toDisplayString(fromDisplayString('aa cchmcchm DD EE GG PP spsp rere'))).toBe(
|
||||
'aa c[chm]c[chm] DD EE GG PP spsp rere',
|
||||
'aa c[chm]c[chm] DD EE GG PP spsp',
|
||||
)
|
||||
})
|
||||
|
||||
@@ -611,24 +615,24 @@ describe('GEN-3h: breeder bracket-notation display + E-locus e-before-ef order',
|
||||
// Display must swap to [e, ef] per breeder convention.
|
||||
const g = fromDisplayString('aa CC DD eef Gg Pp spsp rere')
|
||||
expect(g.E).toEqual(['ef', 'e']) // storage order unchanged
|
||||
expect(toDisplayString(g)).toBe('aa CC DD ee[f] Gg Pp spsp rere')
|
||||
expect(toDisplayString(g)).toBe('aa CC DD ee[f] Gg Pp spsp')
|
||||
})
|
||||
|
||||
it('E+e stays Ee (E dominant over e, no swap needed)', () => {
|
||||
expect(toDisplayString(fromDisplayString('aa CC DD Ee GG PP spsp rere'))).toBe(
|
||||
'aa CC DD Ee GG PP spsp rere',
|
||||
'aa CC DD Ee GG PP spsp',
|
||||
)
|
||||
})
|
||||
|
||||
it('E+ef displays Ee[f] (E dominant stays first, ef renders as e[f])', () => {
|
||||
expect(toDisplayString(fromDisplayString('aa CC DD Eef GG PP spsp rere'))).toBe(
|
||||
'aa CC DD Ee[f] GG PP spsp rere',
|
||||
'aa CC DD Ee[f] GG PP spsp',
|
||||
)
|
||||
})
|
||||
|
||||
// ── Julian oracle fixtures (HUMANQUESTION D3/D4) ─────────────────────
|
||||
it('Tier C: oracle display string round-trips exactly (aa C- D- ee[f] Gg Pp spsp rere)', () => {
|
||||
const display = 'aa C- D- ee[f] Gg Pp spsp rere'
|
||||
it('Tier C: oracle display string round-trips exactly (aa C- D- ee[f] Gg Pp spsp)', () => {
|
||||
const display = 'aa C- D- ee[f] Gg Pp spsp'
|
||||
const g = fromDisplayString(display)
|
||||
expect(g.E).toEqual(['ef', 'e'])
|
||||
expect(g.C).toEqual(['C', '?'])
|
||||
@@ -636,16 +640,16 @@ describe('GEN-3h: breeder bracket-notation display + E-locus e-before-ef order',
|
||||
// Farbschlag scope is outside GEN-3h; god confirmed colour is correct as-is.
|
||||
})
|
||||
|
||||
it('Zuleika oracle: aa c[chm]c[h] DD Ee Gg PP spsp rere', () => {
|
||||
const display = 'aa c[chm]c[h] DD Ee Gg PP spsp rere'
|
||||
it('Zuleika oracle: aa c[chm]c[h] DD Ee Gg PP spsp', () => {
|
||||
const display = 'aa c[chm]c[h] DD Ee Gg PP spsp'
|
||||
const g = fromDisplayString(display)
|
||||
expect(g.C).toEqual(['cchm', 'ch'])
|
||||
expect(g.E).toEqual(['E', 'e'])
|
||||
expect(toDisplayString(g)).toBe(display)
|
||||
})
|
||||
|
||||
it('Milka oracle: aa Cc[h] dd EE Gg P- Spsp rere', () => {
|
||||
const display = 'aa Cc[h] dd EE Gg P- Spsp rere'
|
||||
it('Milka oracle: aa Cc[h] dd EE Gg P- Spsp', () => {
|
||||
const display = 'aa Cc[h] dd EE Gg P- Spsp'
|
||||
const g = fromDisplayString(display)
|
||||
expect(g.C).toEqual(['C', 'ch'])
|
||||
expect(g.D).toEqual(['d', 'd'])
|
||||
@@ -668,7 +672,7 @@ describe('GEN-3h: breeder bracket-notation display + E-locus e-before-ef order',
|
||||
it('e[-] standalone: parses as [e,?], displays e-', () => {
|
||||
const g = fromDisplayString('aa CC DD e[-] GG PP spsp rere')
|
||||
expect(g.E).toEqual(['e', '?'])
|
||||
expect(toDisplayString(g)).toBe('aa CC DD e- GG PP spsp rere')
|
||||
expect(toDisplayString(g)).toBe('aa CC DD e- GG PP spsp')
|
||||
})
|
||||
|
||||
it('CR-1a: Silvain oracle ee[-] parses without crash → [e,?], displays e-', () => {
|
||||
@@ -680,6 +684,6 @@ describe('GEN-3h: breeder bracket-notation display + E-locus e-before-ef order',
|
||||
expect(g.C).toEqual(['cchm', 'cchm'])
|
||||
expect(g.D).toEqual(['D', 'd'])
|
||||
expect(g.Sp).toEqual(['Sp', 'sp'])
|
||||
expect(toDisplayString(g)).toBe('aa c[chm]c[chm] Dd e- Gg Pp Spsp rere')
|
||||
expect(toDisplayString(g)).toBe('aa c[chm]c[chm] Dd e- Gg Pp Spsp')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -51,7 +51,7 @@ export const BASE_COLORS: readonly FarbschlagEntry[] = [
|
||||
// GEN-3a: 'Schwarzschimmel' REMOVED (breeder C5: no such variety; efef base is
|
||||
// Orangeschimmel — see the GEN-2 block below). This was an authorized exception
|
||||
// to the frozen-name rule; the ColorVariety seed drops it too.
|
||||
{ name: 'Pink Eyed White (PEW)', english: 'Pink Eyed White', tokens: { C: 'ch', P: 'p' }, image: 'rotaugen-weiss-pew-d-sep-e-sep.jpg' },
|
||||
{ name: 'REW', english: 'Pink Eyed White', tokens: { C: 'ch', P: 'p' }, image: 'rotaugen-weiss-pew-d-sep-e-sep.jpg' },
|
||||
{ name: 'Hermelin', english: 'Dark Tailed White', tokens: { A: 'a', C: 'ch', D: 'D', P: 'P' }, image: 'hermelin.jpeg' },
|
||||
{ name: 'Himalaya', english: 'Himalayan', tokens: { A: 'A', C: 'ch', D: 'D', P: 'P' }, image: 'himalaya.jpg' },
|
||||
{ name: 'Zobel', english: 'Sable', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'zobel.jpeg' },
|
||||
@@ -268,7 +268,7 @@ export function farbschlagFor(g: Genotype): FarbschlagMatch {
|
||||
// AND pink-eyed (pp) = REW (Rotaugenweiß), A/D/E/G-independent.
|
||||
// cchm/cchm + pp → REW (CP varieties with pink-eye)
|
||||
// cchm/ch + pp → REW (het colourpoint + pink-eye)
|
||||
// ch/ch + pp → REW (this also subsumes the frozen 'Pink Eyed White (PEW)' entry)
|
||||
// ch/ch + pp → REW (Julian confirmed PEW=REW; the 'REW' catalog entry matches here)
|
||||
// Counterproof: at least one full 'C' + pp → NOT REW (residual pigment remains).
|
||||
const [c0, c1] = resolvedPair(g, 'C')
|
||||
const [p0, p1] = resolvedPair(g, 'P')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name": "Pink Eyed White (PEW)",
|
||||
"name": "REW",
|
||||
"english": "Pink Eyed White",
|
||||
"canonicalGenotype": "AA chch DD EE GG pp spsp rere",
|
||||
"sortOrder": 0,
|
||||
|
||||
@@ -1,426 +1,426 @@
|
||||
[
|
||||
{
|
||||
"name": "Pink Eyed White (PEW)",
|
||||
"name": "REW",
|
||||
"english": "Pink Eyed White",
|
||||
"canonicalGenotype": "AA c[h]c[h] DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA c[h]c[h] DD EE GG pp spsp",
|
||||
"sortOrder": 0,
|
||||
"image": "rotaugen-weiss-pew-d-sep-e-sep.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Hermelin",
|
||||
"english": "Dark Tailed White",
|
||||
"canonicalGenotype": "aa c[h]c[h] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "aa c[h]c[h] DD EE GG PP spsp",
|
||||
"sortOrder": 1,
|
||||
"image": "hermelin.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "Himalaya",
|
||||
"english": "Himalayan",
|
||||
"canonicalGenotype": "AA c[h]c[h] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[h]c[h] DD EE GG PP spsp",
|
||||
"sortOrder": 2,
|
||||
"image": "himalaya.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Zobel",
|
||||
"english": "Sable",
|
||||
"canonicalGenotype": "aa c[chm]c[chm] DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "aa c[chm]c[chm] DD EE gg PP spsp",
|
||||
"sortOrder": 3,
|
||||
"image": "zobel.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "Rotaugenschimmel",
|
||||
"english": "Red-Eyed Roan",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG pp spsp",
|
||||
"sortOrder": 4,
|
||||
"image": "rotaugen-schimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Agouti",
|
||||
"english": "Golden Agouti",
|
||||
"canonicalGenotype": "AA CC DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE GG PP spsp",
|
||||
"sortOrder": 5,
|
||||
"image": "agouti-mit-erklaerung-der-genloci.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Schwarz",
|
||||
"english": "Black",
|
||||
"canonicalGenotype": "aa CC DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE GG PP spsp",
|
||||
"sortOrder": 6,
|
||||
"image": "schwarz.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Silberagouti",
|
||||
"english": "Grey Agouti",
|
||||
"canonicalGenotype": "AA CC DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE gg PP spsp",
|
||||
"sortOrder": 7,
|
||||
"image": "silberagouti.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Anthrazit",
|
||||
"english": "Slate",
|
||||
"canonicalGenotype": "aa CC DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE gg PP spsp",
|
||||
"sortOrder": 8,
|
||||
"image": "anthrazit.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Algierfuchs",
|
||||
"english": "Dark-Eyed Honey",
|
||||
"canonicalGenotype": "AA CC DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee GG PP spsp",
|
||||
"sortOrder": 9,
|
||||
"image": "algierfuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Blau",
|
||||
"english": "Blue",
|
||||
"canonicalGenotype": "aa CC dd EE GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC dd EE GG PP spsp",
|
||||
"sortOrder": 10,
|
||||
"image": "blau-schwarz-dd.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Gold",
|
||||
"english": "Argente Golden",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp",
|
||||
"sortOrder": 11,
|
||||
"image": "gold.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Platin",
|
||||
"english": "Lilac",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp",
|
||||
"sortOrder": 12,
|
||||
"image": "platin.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Goldfuchs",
|
||||
"english": "Yellow Fox",
|
||||
"canonicalGenotype": "AA CC DD ee GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee GG pp spsp",
|
||||
"sortOrder": 13,
|
||||
"image": "goldfuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Rotfuchs",
|
||||
"english": "Argente Nutmeg",
|
||||
"canonicalGenotype": "aa CC DD ee GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee GG pp spsp",
|
||||
"sortOrder": 14,
|
||||
"image": "rotfuchs.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Gold",
|
||||
"english": "dd Argente Golden",
|
||||
"canonicalGenotype": "AA CC dd EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC dd EE GG pp spsp",
|
||||
"sortOrder": 15,
|
||||
"image": "gold-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Platin",
|
||||
"english": "dd Lilac",
|
||||
"canonicalGenotype": "aa CC dd EE GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC dd EE GG pp spsp",
|
||||
"sortOrder": 16,
|
||||
"image": "platin-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Altweiss (REW)",
|
||||
"canonicalGenotype": "aa CC DD EE gg pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE gg pp spsp",
|
||||
"sortOrder": 17,
|
||||
"image": "altweiss-rew.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "Apricot (Blassfuchs)",
|
||||
"canonicalGenotype": "AA CC DD ee gg pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee gg pp spsp",
|
||||
"sortOrder": 18,
|
||||
"image": "apricot-blassfuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Blaufuchs",
|
||||
"canonicalGenotype": "aa CC DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee gg PP spsp",
|
||||
"sortOrder": 19,
|
||||
"image": "blaufuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "C-Separator",
|
||||
"canonicalGenotype": "aa CC DD ee gg pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee gg pp spsp",
|
||||
"sortOrder": 20,
|
||||
"image": "c-separator.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Elfenbein",
|
||||
"canonicalGenotype": "AA CC DD EE gg pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE gg pp spsp",
|
||||
"sortOrder": 21,
|
||||
"image": "elfenbein.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Kohlfuchs",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp",
|
||||
"sortOrder": 22,
|
||||
"image": "kohlfuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Polarfuchs",
|
||||
"canonicalGenotype": "AA CC DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee gg PP spsp",
|
||||
"sortOrder": 23,
|
||||
"image": "polarfuchs.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Saphir",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp",
|
||||
"sortOrder": 24,
|
||||
"image": "saphir.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Orangeschimmel",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 25,
|
||||
"image": "schimmel-orangeschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Topas",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp",
|
||||
"sortOrder": 26,
|
||||
"image": "topas.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Platin-Hell",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD EE GG pp spsp",
|
||||
"sortOrder": 27,
|
||||
"image": "platin-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Agouti",
|
||||
"canonicalGenotype": "AA CC dd EE GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC dd EE GG PP spsp",
|
||||
"sortOrder": 28,
|
||||
"image": "agouti-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Silberagouti",
|
||||
"canonicalGenotype": "AA CC dd EE gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC dd EE gg PP spsp",
|
||||
"sortOrder": 29,
|
||||
"image": "silberagouti-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Kohlfuchs",
|
||||
"canonicalGenotype": "aa CC dd ee GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC dd ee GG PP spsp",
|
||||
"sortOrder": 30,
|
||||
"image": "kohlfuchs-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Anthrazit",
|
||||
"canonicalGenotype": "aa CC dd EE gg PP spsp rere",
|
||||
"canonicalGenotype": "aa CC dd EE gg PP spsp",
|
||||
"sortOrder": 31,
|
||||
"image": "anthrazit-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Algierfuchs",
|
||||
"canonicalGenotype": "AA CC dd ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC dd ee GG PP spsp",
|
||||
"sortOrder": 32
|
||||
},
|
||||
{
|
||||
"name": "Dilute Goldfuchs",
|
||||
"canonicalGenotype": "AA CC dd ee GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC dd ee GG pp spsp",
|
||||
"sortOrder": 33
|
||||
},
|
||||
{
|
||||
"name": "Dilute Rotfuchs",
|
||||
"canonicalGenotype": "aa CC dd ee GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC dd ee GG pp spsp",
|
||||
"sortOrder": 34
|
||||
},
|
||||
{
|
||||
"name": "Dilute Polarfuchs",
|
||||
"canonicalGenotype": "AA CC dd ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC dd ee gg PP spsp",
|
||||
"sortOrder": 35
|
||||
},
|
||||
{
|
||||
"name": "Silberschimmel",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] gg PP spsp",
|
||||
"sortOrder": 36,
|
||||
"image": "silberschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Polarfuchsschimmel",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] gg PP spsp",
|
||||
"sortOrder": 37,
|
||||
"image": "polarfuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Algierfuchsschimmel",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 38,
|
||||
"image": "algierfuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Kohlfuchsschimmel",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 39,
|
||||
"image": "kohlfuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Blaufuchsschimmel",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] gg PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] gg PP spsp",
|
||||
"sortOrder": 40,
|
||||
"image": "blaufuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Kohlfuchs, hell",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp",
|
||||
"sortOrder": 41,
|
||||
"image": "kohlfuchs-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Goldfuchs, hell",
|
||||
"canonicalGenotype": "AA CC DD ee GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee GG pp spsp",
|
||||
"sortOrder": 42,
|
||||
"image": "goldfuchs-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Goldfuchsschimmel",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD e[f]e[f] GG pp spsp",
|
||||
"sortOrder": 43,
|
||||
"image": "goldfuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Gold-Hell",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC DD EE GG pp spsp",
|
||||
"sortOrder": 44,
|
||||
"image": "gold-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Blaufuchs, hell",
|
||||
"canonicalGenotype": "aa CC DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee gg PP spsp",
|
||||
"sortOrder": 45,
|
||||
"image": "blaufuchs-hell.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "Rotfuchsschimmel",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG pp spsp",
|
||||
"sortOrder": 46,
|
||||
"image": "rotfuchsschimmel.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Polarfuchs, hell",
|
||||
"canonicalGenotype": "AA CC DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee gg PP spsp",
|
||||
"sortOrder": 47,
|
||||
"image": "polarfuchs-hell.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "Kohlfuchsschimmel, hell",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 48,
|
||||
"image": "kohlfuchsschimmel-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Rotfuchs, hell",
|
||||
"canonicalGenotype": "aa CC DD ee GG pp spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee GG pp spsp",
|
||||
"sortOrder": 49,
|
||||
"image": "rotfuchs-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Kohlfuchs-Hell",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "aa CC DD ee GG PP spsp",
|
||||
"sortOrder": 50,
|
||||
"image": "kohlfuchs-hell-2.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Algierfuchs, hell",
|
||||
"canonicalGenotype": "AA CC DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA CC DD ee GG PP spsp",
|
||||
"sortOrder": 51,
|
||||
"image": "algierfuchs-hell.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Topas",
|
||||
"canonicalGenotype": "AA CC dd EE GG pp spsp rere",
|
||||
"canonicalGenotype": "AA CC dd EE GG pp spsp",
|
||||
"sortOrder": 52,
|
||||
"image": "topas-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Dilute Blaufuchs",
|
||||
"canonicalGenotype": "aa CC dd ee gg pp spsp rere",
|
||||
"canonicalGenotype": "aa CC dd ee gg pp spsp",
|
||||
"sortOrder": 53,
|
||||
"image": "blaufuchs-dd.jpg"
|
||||
},
|
||||
{
|
||||
"name": "Marder",
|
||||
"canonicalGenotype": "aa c[chm]c[chm] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "aa c[chm]c[chm] DD EE GG PP spsp",
|
||||
"sortOrder": 54,
|
||||
"image": "marder.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Siam",
|
||||
"canonicalGenotype": "aa c[chm]c[h] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "aa c[chm]c[h] DD EE GG PP spsp",
|
||||
"sortOrder": 55,
|
||||
"image": "siam-marder-hell.JPG"
|
||||
},
|
||||
{
|
||||
"name": "Zobel-Hell",
|
||||
"canonicalGenotype": "aa c[chm]c[h] DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "aa c[chm]c[h] DD EE gg PP spsp",
|
||||
"sortOrder": 56,
|
||||
"image": "zobel-hell.jpg"
|
||||
},
|
||||
{
|
||||
"name": "CP-Agouti",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD EE GG PP spsp",
|
||||
"sortOrder": 57,
|
||||
"image": "agouti-cp.jpg"
|
||||
},
|
||||
{
|
||||
"name": "CP-Agouti-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD EE GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD EE GG PP spsp",
|
||||
"sortOrder": 58
|
||||
},
|
||||
{
|
||||
"name": "CP-Silberagouti",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD EE gg PP spsp",
|
||||
"sortOrder": 59,
|
||||
"image": "silberagouti-cp.JPG"
|
||||
},
|
||||
{
|
||||
"name": "CP-Silberagouti-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD EE gg PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD EE gg PP spsp",
|
||||
"sortOrder": 60
|
||||
},
|
||||
{
|
||||
"name": "CP-Algierfuchs",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD ee GG PP spsp",
|
||||
"sortOrder": 61,
|
||||
"image": "algierfuchs-cp.jpg"
|
||||
},
|
||||
{
|
||||
"name": "CP-Algierfuchs-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD ee GG PP spsp",
|
||||
"sortOrder": 62
|
||||
},
|
||||
{
|
||||
"name": "CP-Polarfuchs",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD ee gg PP spsp",
|
||||
"sortOrder": 63,
|
||||
"image": "polarfuchs-cp.jpg"
|
||||
},
|
||||
{
|
||||
"name": "CP-Polarfuchs-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD ee gg PP spsp",
|
||||
"sortOrder": 64
|
||||
},
|
||||
{
|
||||
"name": "CP-Fuchs",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] dd ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] dd ee GG PP spsp",
|
||||
"sortOrder": 65
|
||||
},
|
||||
{
|
||||
"name": "CP-Fuchs-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] dd ee GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] dd ee GG PP spsp",
|
||||
"sortOrder": 66
|
||||
},
|
||||
{
|
||||
"name": "CP-Blaufuchs",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] dd ee gg PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] dd ee gg PP spsp",
|
||||
"sortOrder": 67
|
||||
},
|
||||
{
|
||||
"name": "CP-Orangeschimmel",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[chm] DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 68
|
||||
},
|
||||
{
|
||||
"name": "CP-Orangeschimmel-Hell",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD e[f]e[f] GG PP spsp rere",
|
||||
"canonicalGenotype": "AA c[chm]c[h] DD e[f]e[f] GG PP spsp",
|
||||
"sortOrder": 69
|
||||
}
|
||||
]
|
||||
|
||||
@@ -101,18 +101,21 @@ function displayPair(locus: LocusKey, pair: AllelePair): AllelePair {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact display string, e.g. "Aa CC Dd EE GG Pp spsp rere".
|
||||
* The Sls locus is OMITTED when wild-type (sl/sl) so legacy 8-locus strings and
|
||||
* the colour catalog stay byte-identical; it only appears for WP/Sls carriers
|
||||
* (e.g. "… spsp rere Slsl"). Round-trips: a missing Sls re-parses to sl/sl.
|
||||
* GEN-3c: unknown alleles are STORED as '?' but DISPLAYED as '-' (breeder
|
||||
* convention) — e.g. ['C','?'] renders "C-".
|
||||
* GEN-3h: sub-alleles use breeder bracket notation (e[f], c[chm], c[h]);
|
||||
* E-locus display order is E > e > e[f] (e before e[f] in het pairs).
|
||||
* Compact display string, e.g. "Aa CC Dd EE GG Pp spsp".
|
||||
* The Re locus is OMITTED when wild-type (re/re) — Julian: only show Rex when a
|
||||
* Rex allele is present (Rere/ReRe). Matches the 7-locus notation used by the
|
||||
* breeder. The Sls locus is likewise omitted when wild-type (sl/sl) so legacy
|
||||
* 8-locus strings and the colour catalog stay byte-identical; it only appears for
|
||||
* WP/Sls carriers (e.g. "… spsp Slsl"). Round-trips: missing Re → re/re; missing
|
||||
* Sls → sl/sl. GEN-3c: unknown alleles stored as '?' displayed as '-' (breeder
|
||||
* convention). GEN-3h: bracket notation (e[f], c[chm], c[h]); E-locus display
|
||||
* order E > e > e[f].
|
||||
*/
|
||||
export function toDisplayString(g: Genotype): string {
|
||||
return LOCUS_ORDER.filter(
|
||||
(locus) => locus !== 'Sls' || !(g.Sls[0] === 'sl' && g.Sls[1] === 'sl'),
|
||||
(locus) =>
|
||||
!(locus === 'Re' && g.Re[0] === 're' && g.Re[1] === 're') &&
|
||||
!(locus === 'Sls' && g.Sls[0] === 'sl' && g.Sls[1] === 'sl'),
|
||||
)
|
||||
.map((locus) => {
|
||||
const [a, b] = displayPair(locus, g[locus])
|
||||
|
||||
@@ -27,7 +27,7 @@ import { getInbreedingCoefficient } from '../api/pedigree'
|
||||
import type { Gender, Gerbil } from '../api/types'
|
||||
import { useApi } from '../hooks/useApi'
|
||||
import { formatDate, genderLabel } from '../format/labels'
|
||||
import { UNKNOWN_FARBSCHLAG, fromDisplayString, genotypeToFarbschlag } from '../genetics'
|
||||
import { UNKNOWN_FARBSCHLAG, fromDisplayString, genotypeToFarbschlag, toDisplayString } from '../genetics'
|
||||
import {
|
||||
DEFAULT_GENERATIONS,
|
||||
ancestorsAt,
|
||||
@@ -512,7 +512,11 @@ function PrintCell({
|
||||
</div>
|
||||
)}
|
||||
{farbschlag && <div className="stammbaum-print__sub">{farbschlag}</div>}
|
||||
{g.genotype && gen <= 2 && <div className="stammbaum-print__geno">{g.genotype}</div>}
|
||||
{g.genotype && gen <= 2 && (
|
||||
<div className="stammbaum-print__geno">
|
||||
{toDisplayString(fromDisplayString(g.genotype))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,6 @@ export default function WurfDetailPage() {
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<h3>{t.detail.expectedColors}</h3>
|
||||
{expected ? (
|
||||
<BreedingResultView result={expected} title={t.detail.expectedColors} />
|
||||
) : (
|
||||
|
||||
@@ -13,6 +13,9 @@ export interface ChipColor {
|
||||
|
||||
const CHIP_COLORS: Record<string, ChipColor> = {
|
||||
// Colourpoint / C-Serie
|
||||
// GEN-4c: PEW renamed to REW in catalog (Julian: PEW=REW). Both kept here for
|
||||
// backward-compat during DB migration (old animals may still carry the old name).
|
||||
'REW': { bg: '#f7f3ec', fg: '#8a7d6b' },
|
||||
'Pink Eyed White (PEW)': { bg: '#f7f3ec', fg: '#8a7d6b' },
|
||||
Hermelin: { bg: '#f3ede2', fg: '#8a7d6b' },
|
||||
Himalaya: { bg: '#efe6d8', fg: '#8a7d6b' },
|
||||
|
||||
Reference in New Issue
Block a user