1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
namespace LivingVillage.Kernel.Tests
open Microsoft.VisualStudio.TestTools.UnitTesting
open LivingVillage.Kernel
open LivingVillage.Kernel.Sim
module private TradeBiasHarness =
let quotedWorld () : World = Sim.initialWorldN 42UL 4
let quote (buyer: NpcId) (seller: NpcId) (item: ItemKind) (world: World) : float32 =
match Sim.quotePrice { Buyer = buyer; Seller = seller; Item = item; Quantity = 1 } world with
| Some price -> price
| None -> Assert.Fail("quote expected"); Unchecked.defaultof<float32>
[<TestClass>]
type TradeBiasTests () =
// ---- 默认(无职业)= 旧行为基准 ----
[<TestMethod>]
member _.NoOccupationKeepsTheHistoricQuoteUnchanged () =
Assert.AreEqual<float32>(1.0f, Occupation.quoteBiasOf None true)
Assert.AreEqual<float32>(1.0f, Occupation.quoteBiasOf None false)
Assert.AreEqual<float32 option>(Some 10.0f, Occupation.biasedQuote None true (Some 10.0f))
Assert.AreEqual<float32 option>(None, Occupation.biasedQuote None true None)
[<TestMethod>]
member _.FarmerAndFisherStayUnbiasedLikeTheDefaultPath () =
for kind in [ Occupation.Farmer; Occupation.Fisher ] do
Assert.AreEqual<float32>(1.0f, Occupation.quoteBiasOf (Some kind) true)
Assert.AreEqual<float32>(1.0f, Occupation.quoteBiasOf (Some kind) false)
// ---- 货郎:买卖双向有利偏移(±3.00%,4 位定点基点)----
[<TestMethod>]
member _.PeddlerBuysCheaperAndSellsDearer () =
Assert.AreEqual<float32>(0.97f, Occupation.quoteBiasOf (Some Occupation.Peddler) true)
Assert.AreEqual<float32>(1.03f, Occupation.quoteBiasOf (Some Occupation.Peddler) false)
// ---- 书生:解读行情的小幅加成(±1.00%)----
[<TestMethod>]
member _.ScholarGetsASmallerFavorableEdgeThanPeddler () =
let scholarBuy = Occupation.quoteBiasOf (Some Occupation.Scholar) true
let peddlerBuy = Occupation.quoteBiasOf (Some Occupation.Peddler) true
Assert.AreEqual<float32>(0.99f, scholarBuy)
Assert.AreEqual<float32>(1.01f, Occupation.quoteBiasOf (Some Occupation.Scholar) false)
Assert.IsTrue(scholarBuy > peddlerBuy, "scholar edge must stay inside the peddler edge")
// ---- 确定性与设计区间 [0.95, 1.05] ----
[<TestMethod>]
member _.BiasIsDeterministicAndInsideTheDesignBand () =
for kind in Occupation.all do
for playerIsBuyer in [ true; false ] do
let first = Occupation.quoteBiasOf (Some kind) playerIsBuyer
let second = Occupation.quoteBiasOf (Some kind) playerIsBuyer
Assert.AreEqual<float32>(first, second)
Assert.IsTrue(0.95f <= first && first <= 1.05f, $"{kind} bias {first} escaped the band")
// ---- 与既有 Sim.quotePrice(Food 10.0f 路径)复合 ----
[<TestMethod>]
member _.BiasComposesWithTheExistingQuotePath () =
let world = TradeBiasHarness.quotedWorld ()
let baseBuy = TradeBiasHarness.quote (NpcId 0) (NpcId 1) Food world
let baseSell = TradeBiasHarness.quote (NpcId 1) (NpcId 0) Food world
Assert.AreEqual<float32>(baseBuy * 0.97f, (Occupation.biasedQuote (Some Occupation.Peddler) true (Some baseBuy)).Value)
Assert.AreEqual<float32>(baseSell * 1.03f, (Occupation.biasedQuote (Some Occupation.Peddler) false (Some baseSell)).Value)
Assert.AreEqual<float32>(baseBuy, (Occupation.biasedQuote None true (Some baseBuy)).Value)
|