Used-hardware dealer customer and GPU appraisal registration

A scav-type seller visits now and then with three to five used cards. An
honest dealer sells at true value, a middleman adds 8%, a scammer mixes in
fakes (relabelled cheap chips) priced at 90% of the labelled model's value.
The markup is a client-temporary item feature, so a bought card is only
worth its real value. Cards are registered as appraisal items; the correct
value is the same function as the sale value.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-03 11:40:10 +08:00
1 parent 42608a4acd
commit 9b48d7bf0e
6 files changed
+206

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Decentralized.Domain
{
/// <summary>二手显卡贩子的类型:老实人按真实价卖;中间商加价;骗子夹带假卡,按标称型号的价卖。</summary>
public enum DealerKind { Honest, Middleman, Scammer }
/// <summary>贩子带来的一张卡:<see cref="MarkupPct"/> 是柜台上相对真实价值的加价百分比(骗子卖假卡时是正的,按标称型号报价再打九折)。</summary>
public sealed class UsedCard
{
public string Model;
public string FakeOf;
public double Health;
public int MarkupPct;
}
public static class UsedDealers
{
public const double MiddlemanMarkup = 0.08, ScamDiscount = 0.90;
public const double FakeShareMiddleman = 0.10, FakeShareScammer = 0.45;
/// <summary>今天来的贩子的类型:骗子越往后越多。</summary>
public static DealerKind Kind(int day, Rng rng)
{
double scam = Math.Min(0.30, 0.10 + day * 0.004);
double r = rng.NextDouble();
return r < scam ? DealerKind.Scammer : r < scam + 0.30 ? DealerKind.Middleman : DealerKind.Honest;
}
/// <summary>能出现在二手市场上的型号:按天数放开,旗舰第 30 天起。</summary>
public static string[] Pool(int day)
{
var list = new List<string>(Dealer.Basic);
if (day >= Dealer.AdvancedFromDay) list.AddRange(Dealer.Advanced);
if (day >= Dealer.FlagshipFromDay) list.AddRange(Dealer.Flagship);
return list.ToArray();
}
public static List<UsedCard> Cards(DealerKind kind, int day, Rng rng)
{
var pool = Pool(day);
int count = rng.Range(3, 5);
var cards = new List<UsedCard>();
for (int i = 0; i < count; i++)
{
double share = kind == DealerKind.Scammer ? FakeShareScammer : kind == DealerKind.Middleman ? FakeShareMiddleman : 0;
var label = pool[rng.Range(0, pool.Length - 1)];
var card = new UsedCard { Model = label, Health = 25 + rng.NextDouble() * 60 };
var cheaper = Hardware.Specs.Values.Where(s => !s.Asic && s.Price * 2 <= Hardware.Specs[label].Price).Select(s => s.Model).ToArray();
if (cheaper.Length > 0 && rng.Chance(share))
{
card.FakeOf = cheaper[rng.Range(0, cheaper.Length - 1)];
var u = new Unit { Model = card.Model, FakeOf = card.FakeOf, Health = card.Health };
card.MarkupPct = (int)Math.Round((CardValue.Of(label, card.Health) * ScamDiscount / CardValue.True(u) - 1) * 100);
}
else if (kind == DealerKind.Middleman) card.MarkupPct = (int)Math.Round(MiddlemanMarkup * 100);
cards.Add(card);
}
return cards;
}
}
}