Labels: eight rows (model, build, fan blades, contacts, bracket, print, serial, seal); serial text rules by brand and tier
This commit is contained in:
1 parent
202bdbbfbc
commit
9d19df407a
3 files changed
+113
-63
No files matched your search
@@ -3,52 +3,56 @@ using System.Linq;
|
||||
|
||||
namespace Decentralized.Domain
|
||||
{
|
||||
/// <summary>卖家的说法:每个标签一项。型号是文字,其余五项取值与 <see cref="CardLook"/> 的取值一致。</summary>
|
||||
/// <summary>卖家的说法:每个标签一项。型号是文字,其余取值与 <see cref="CardLook"/> 一致;「供电与风扇」由说法里的型号决定档次。</summary>
|
||||
public struct Claim
|
||||
{
|
||||
public string Model;
|
||||
public int Fan, Fingers, Bracket, Print, Sticker;
|
||||
public int Fan, Fingers, Bracket, Print, Sticker, Serial;
|
||||
|
||||
public int Get(int row) => row == CardLabels.RowFan ? Fan : row == CardLabels.RowFingers ? Fingers : row == CardLabels.RowBracket ? Bracket : row == CardLabels.RowPrint ? Print : Sticker;
|
||||
public int Tier => Hardware.Specs[Model].Tier;
|
||||
|
||||
public int Get(int row) => row == CardLabels.RowBuild ? Tier : row == CardLabels.RowFan ? Fan : row == CardLabels.RowFingers ? Fingers
|
||||
: row == CardLabels.RowBracket ? Bracket : row == CardLabels.RowPrint ? Print : row == CardLabels.RowSerial ? Serial : Sticker;
|
||||
|
||||
public Claim With(int row, int value)
|
||||
{
|
||||
var c = this;
|
||||
if (row == CardLabels.RowFan) c.Fan = value; else if (row == CardLabels.RowFingers) c.Fingers = value;
|
||||
else if (row == CardLabels.RowBracket) c.Bracket = value; else if (row == CardLabels.RowPrint) c.Print = value; else c.Sticker = value;
|
||||
else if (row == CardLabels.RowBracket) c.Bracket = value; else if (row == CardLabels.RowPrint) c.Print = value;
|
||||
else if (row == CardLabels.RowSerial) c.Serial = value; else if (row == CardLabels.RowSeal) c.Sticker = value;
|
||||
return c;
|
||||
}
|
||||
|
||||
public string Encode() => $"{Model}:{Fan}{Fingers}{Bracket}{Print}{Sticker}";
|
||||
public string Encode() => $"{Model}:{Fan}{Fingers}{Bracket}{Print}{Sticker}{Serial}";
|
||||
|
||||
public static Claim Decode(string s)
|
||||
{
|
||||
var p = (s ?? "").Split(':');
|
||||
if (p.Length != 2 || p[1].Length != 5 || !Hardware.Specs.ContainsKey(p[0])) return default;
|
||||
if (p.Length != 2 || p[1].Length != 6 || !Hardware.Specs.ContainsKey(p[0])) return default;
|
||||
int D(int i) => Math.Max(0, Math.Min(2, p[1][i] - '0'));
|
||||
return new Claim { Model = p[0], Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4) };
|
||||
return new Claim { Model = p[0], Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4), Serial = D(5) };
|
||||
}
|
||||
|
||||
/// <summary>按真实情况写出的说法(没有隐瞒)。</summary>
|
||||
public static Claim Truth(Unit u)
|
||||
{
|
||||
var l = u.Appearance;
|
||||
return new Claim { Model = u.FakeOf ?? u.Model, Fan = l.Fan, Fingers = l.Fingers, Bracket = l.Bracket, Print = l.Print, Sticker = l.Sticker };
|
||||
return new Claim { Model = u.FakeOf ?? u.Model, Fan = l.Fan, Fingers = l.Fingers, Bracket = l.Bracket, Print = l.Print, Sticker = l.Sticker, Serial = l.Serial };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签栏的数据:六个标签(型号、风扇、金手指、挡板、丝印、贴纸),每个标签有卖家的说法和真实情况。
|
||||
/// 标签栏的数据:八个标签(型号、供电与风扇、风扇叶片、金手指、挡板、背面丝印、序列号、封条),每个标签有卖家的说法和真实情况。
|
||||
/// 一个标签被指出(拆穿)之后,说法改回真实情况;价格按「已指出的标签取真实情况,其余取说法」算,
|
||||
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。
|
||||
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。指出假货的证据(供电与风扇、丝印、序列号)会连带把型号改回真实型号。
|
||||
/// </summary>
|
||||
public static class CardLabels
|
||||
{
|
||||
public const int RowSpec = 1, RowFan = 2, RowFingers = 4, RowBracket = 8, RowPrint = 16, RowSticker = 32, AllRows = 63;
|
||||
public static readonly int[] Rows = { RowSpec, RowFan, RowFingers, RowBracket, RowPrint, RowSticker };
|
||||
public const int RowSpec = 1, RowBuild = 2, RowFan = 4, RowFingers = 8, RowBracket = 16, RowPrint = 32, RowSerial = 64, RowSeal = 128, AllRows = 255;
|
||||
public static readonly int[] Rows = { RowSpec, RowBuild, RowFan, RowFingers, RowBracket, RowPrint, RowSerial, RowSeal };
|
||||
|
||||
/// <summary>各标签各取值对价格的影响(百分比,相加):风扇积灰 −4%、缺角 −12%;金手指发暗 −4%、氧化 −12%;挡板划痕 −2%;封条缺失 −6%。
|
||||
/// 接口数不对、丝印、手写序列号本身不扣价,它们是假货的证据。</summary>
|
||||
/// <summary>各标签各取值对价格的影响(百分比,相加):风扇叶片积灰 −4%、缺角 −12%;金手指发暗 −4%、氧化 −12%;挡板划痕 −2%;封条缺失 −6%。
|
||||
/// 型号、供电与风扇、丝印、序列号本身不扣价,它们决定的是这块卡是什么芯片。</summary>
|
||||
public static double Pct(int row, int value)
|
||||
{
|
||||
switch (row)
|
||||
@@ -56,14 +60,22 @@ namespace Decentralized.Domain
|
||||
case RowFan: return value == 1 ? -4 : value == 2 ? -12 : 0;
|
||||
case RowFingers: return value == 1 ? -4 : value == 2 ? -12 : 0;
|
||||
case RowBracket: return value == 1 ? -2 : 0;
|
||||
case RowSticker: return value == 2 ? -6 : 0;
|
||||
case RowSeal: return value == 2 ? -6 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>这一项的真实取值是不是假货的证据。</summary>
|
||||
public static bool IsFakeSign(int row, int realValue) =>
|
||||
(row == RowBracket && realValue == 2) || (row == RowPrint && realValue != 0) || (row == RowSticker && realValue == 1);
|
||||
/// <summary>这一行是不是假货的证据:说法与真实情况不同,并且真实情况本身不该出现在真卡上。</summary>
|
||||
public static bool IsEvidence(int row, Claim claim, Claim real)
|
||||
{
|
||||
switch (row)
|
||||
{
|
||||
case RowBuild: return claim.Tier != real.Tier;
|
||||
case RowPrint: return real.Print != 0 && claim.Print != real.Print;
|
||||
case RowSerial: return real.Serial != 0 && claim.Serial != real.Serial;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 价值:claim 为空表示没有人说过什么,一律按真实情况;exposed 里的位表示已指出的标签(取真实情况)。
|
||||
@@ -74,9 +86,8 @@ namespace Decentralized.Domain
|
||||
var real = Claim.Truth(u);
|
||||
Claim believed = claim == null ? real : claim.Value;
|
||||
double sum = 0;
|
||||
foreach (int r in Rows)
|
||||
foreach (int r in new[] { RowFan, RowFingers, RowBracket, RowSeal })
|
||||
{
|
||||
if (r == RowSpec) continue;
|
||||
int v = claim == null || (exposed & r) != 0 ? real.Get(r) : believed.Get(r);
|
||||
sum += Pct(r, v);
|
||||
}
|
||||
@@ -85,24 +96,23 @@ namespace Decentralized.Domain
|
||||
return Math.Max(1, (long)Math.Round(value));
|
||||
}
|
||||
|
||||
/// <summary>指出一个标签:返回 0 没问题(说法属实)、1 隐瞒了对价格不利的情况、2 拆穿了假货。
|
||||
/// 指出假货的证据(接口数、丝印、手写序列号)时,型号标签一并拆穿。</summary>
|
||||
/// <summary>指出一个标签:返回 0 没问题(说法属实)、1 隐瞒了对价格不利的情况、2 拆穿了假货(型号一并改回真实型号)。</summary>
|
||||
public static int Point(Unit u, Claim claim, int row, ref int exposed)
|
||||
{
|
||||
var real = Claim.Truth(u);
|
||||
bool wasExposed = (exposed & row) != 0;
|
||||
exposed |= row;
|
||||
if (row == RowSpec) return claim.Model != real.Model ? 2 : 0;
|
||||
if (IsFakeSign(row, real.Get(row)) && claim.Get(row) != real.Get(row))
|
||||
if (IsEvidence(row, claim, real))
|
||||
{
|
||||
exposed |= RowSpec;
|
||||
exposed |= RowSpec | RowBuild;
|
||||
return 2;
|
||||
}
|
||||
if (wasExposed) return 0;
|
||||
return claim.Get(row) != real.Get(row) ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>说法里隐瞒了什么:说法比真实情况价值高的标签,以及型号不符。</summary>
|
||||
/// <summary>说法里隐瞒了什么:说法比真实情况价值高的标签,型号不符,以及假货的证据。</summary>
|
||||
public static int Lies(Unit u, Claim claim, int exposed)
|
||||
{
|
||||
var real = Claim.Truth(u);
|
||||
@@ -111,24 +121,58 @@ namespace Decentralized.Domain
|
||||
{
|
||||
if ((exposed & r) != 0) continue;
|
||||
if (r == RowSpec) { if (claim.Model != real.Model) lies |= r; }
|
||||
else if (claim.Get(r) != real.Get(r) && (Pct(r, claim.Get(r)) > Pct(r, real.Get(r)) || IsFakeSign(r, real.Get(r)))) lies |= r;
|
||||
else if (IsEvidence(r, claim, real)) lies |= r;
|
||||
else if (claim.Get(r) != real.Get(r) && Pct(r, claim.Get(r)) > Pct(r, real.Get(r))) lies |= r;
|
||||
}
|
||||
return lies;
|
||||
}
|
||||
|
||||
/// <summary>卖家怎么说:老实人如实说;中间商每项有三成概率隐瞒;骗子全部说成没问题。假卡的型号一律说成标称型号。</summary>
|
||||
/// <summary>卖家怎么说:老实人如实说;中间商每项有七成概率说成没问题;骗子全部说成没问题。假卡的型号一律说成标称型号。</summary>
|
||||
public static Claim DealerClaim(Unit u, DealerKind kind, Rng rng)
|
||||
{
|
||||
var c = Claim.Truth(u);
|
||||
if (kind == DealerKind.Honest) return c;
|
||||
c.Model = u.Model;
|
||||
if (kind == DealerKind.Honest) { c.Model = u.FakeOf ?? u.Model; return c; }
|
||||
double hide = kind == DealerKind.Scammer ? 1.0 : 0.7;
|
||||
foreach (int r in Rows)
|
||||
{
|
||||
if (r == RowSpec) continue;
|
||||
foreach (int r in new[] { RowFan, RowFingers, RowBracket, RowPrint, RowSerial, RowSeal })
|
||||
if (rng.Chance(hide)) c = c.With(r, 0);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// ---------- 序列号 ----------
|
||||
|
||||
/// <summary>各牌子的序列号前缀与合法工厂码。序列号格式:前缀 + 档次码(1 到 4)+ "-" + 工厂码(两位)+ "-" + 四位流水。</summary>
|
||||
public static string BrandCode(string brand) => brand == Hardware.Probidia ? "PB" : "MD";
|
||||
public static readonly int[] ProbidiaFactories = { 11, 12, 21, 34, 47 }, PmdFactories = { 13, 22, 35, 41, 58 };
|
||||
public static int[] Factories(string brand) => brand == Hardware.Probidia ? ProbidiaFactories : PmdFactories;
|
||||
|
||||
private static uint Mix(uint seed, int salt)
|
||||
{
|
||||
uint x = seed * 2654435761u + (uint)salt * 40503u + 777u;
|
||||
x ^= x >> 15; x *= 2246822519u; x ^= x >> 13; x *= 3266489917u; x ^= x >> 16;
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卡上贴纸的序列号。合规:前缀(牌子)+ 标称型号的档次码 + 合法工厂码 + 四位流水。
|
||||
/// 不合规(贴纸是后补的):工厂码不在合法范围,或流水只有三位。档次码不符:贴的是原芯片的序列号,档次码是真实芯片的档次。
|
||||
/// </summary>
|
||||
public static string SerialText(Unit u)
|
||||
{
|
||||
var label = Hardware.Specs[u.Model];
|
||||
var chip = Hardware.Specs[u.FakeOf ?? u.Model];
|
||||
uint seed = u.Look.Seed == 0 ? 12345u : u.Look.Seed;
|
||||
int kind = u.Appearance.Serial;
|
||||
int[] ok = Factories(label.Brand);
|
||||
int tier = (kind == 2 ? chip.Tier : label.Tier) + 1;
|
||||
int factory = ok[(int)(Mix(seed, 1) % (uint)ok.Length)];
|
||||
int number = 1000 + (int)(Mix(seed, 2) % 9000);
|
||||
if (kind == 1)
|
||||
{
|
||||
if (Mix(seed, 3) % 2 == 0) { int[] bad = { 0, 9, 66, 77, 88, 99 }; factory = bad[(int)(Mix(seed, 4) % (uint)bad.Length)]; }
|
||||
else number = 100 + (int)(Mix(seed, 5) % 900);
|
||||
}
|
||||
return $"{BrandCode(label.Brand)}{tier}-{factory:00}-{number}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user