Files
card-game-engine/RuleEngine.Tests/CoreTests.cs
xiaoou afce77cca4 [verified] review fixes: priority arbitration, wildcard config, dead code
- CheckReactions: collect all claims, pick highest priority (win>kong>pung>chi)
- Deal(): read wildcardCount from DSL config instead of hardcoded 4
- CheckTing(): propagate wildcardCount + require258Pair to CheckWin
- ThirteenOrphans: fix neededForPair formula (extra>0?0:1)
- Remove FanConfig.Get() dead code
- Fill empty 全不靠 test body
2026-07-03 18:02:13 +08:00

228 lines
7.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using RuleEngine.Core;
using RuleEngine.Patterns;
namespace RuleEngine.Tests;
public class MahjongTileTests
{
[Fact]
public void Encode_万1_Returns1() => Assert.Equal(1, MahjongTile.Encode("万", 1));
[Fact]
public void Encode_条9_Returns19() => Assert.Equal(19, MahjongTile.Encode("条", 9));
[Fact]
public void Encode_筒3_Returns23() => Assert.Equal(23, MahjongTile.Encode("筒", 3));
[Fact]
public void Suit_万1_Returns0() => Assert.Equal(0, MahjongTile.Suit(1));
[Fact]
public void Suit_条19_Returns1() => Assert.Equal(1, MahjongTile.Suit(19));
[Fact]
public void Rank_万9_Returns9() => Assert.Equal(9, MahjongTile.Rank(9));
[Fact]
public void Rank_条11_Returns1() => Assert.Equal(1, MahjongTile.Rank(11));
[Fact]
public void ToString_各类型正确()
{
Assert.Equal("5万", MahjongTile.ToString(5));
Assert.Equal("8条", MahjongTile.ToString(18));
Assert.Equal("3筒", MahjongTile.ToString(23));
Assert.Equal("东", MahjongTile.ToString(31));
Assert.Equal("春", MahjongTile.ToString(41));
Assert.Equal("🃏", MahjongTile.ToString(50));
}
[Fact]
public void AllTiles_108张() => Assert.Equal(27, MahjongTile.AllTiles().Length);
[Fact]
public void AllTiles_含字牌_34种() => Assert.Equal(34, MahjongTile.AllTiles(includeHonors: true).Length);
[Fact]
public void AllTiles_含花牌_35种() => Assert.Equal(35, MahjongTile.AllTiles(includeFlowers: true).Length);
[Fact]
public void IsWildcard_50_True() => Assert.True(MahjongTile.IsWildcard(50));
[Fact]
public void IsWildcard_普通牌_False() => Assert.False(MahjongTile.IsWildcard(1));
}
public class DeckTests
{
[Fact]
public void _108张()
{
var deck = new MahjongDeck(includeHonors: false, includeFlowers: false);
Assert.Equal(108, deck.Tiles.Count);
}
[Fact]
public void 广_136张()
{
// 108 numbered + 28 honors = 136 (no flowers)
var deck = new MahjongDeck(includeHonors: true, includeFlowers: false);
Assert.Equal(136, deck.Tiles.Count);
}
[Fact]
public void _144张()
{
// 108 numbered + 28 honors + 8 flowers = 144
var deck = new MahjongDeck(includeHonors: true, includeFlowers: true);
Assert.Equal(144, deck.Tiles.Count);
}
[Fact]
public void 4()
{
var deck = new MahjongDeck();
var groups = deck.Tiles.Where(t => !MahjongTile.IsFlower(t)).GroupBy(t => t);
Assert.All(groups, g => Assert.Equal(4, g.Count()));
}
[Fact]
public void _减少计数()
{
var deck = new MahjongDeck();
int before = deck.Count;
deck.Draw();
Assert.Equal(before - 1, deck.Count);
}
}
public class MeldsSolverTests
{
private readonly MeldsSolver _solver = new(new Dictionary<string, FanConfig>());
// === 标准胡牌 ===
[Fact]
public void _4面子1对_ShouldWin()
{
// 123万 456万 789万 111条 99条
var hand = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 11, 19, 19 };
var result = _solver.CheckWin(hand);
Assert.True(result.IsWin);
}
[Fact]
public void _碰碰胡_ShouldWin()
{
// 111万 333万 555万 111条 99条
var hand = new List<int> { 1, 1, 1, 3, 3, 3, 5, 5, 5, 11, 11, 11, 19, 19 };
var result = _solver.CheckWin(hand);
Assert.True(result.IsWin);
}
[Fact]
public void _缺面子_ShouldNotWin()
{
// All sequential but wrong structure: 123 456 78? can't form 4 melds
var hand = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16 };
var result = _solver.CheckWin(hand);
Assert.False(result.IsWin);
}
[Fact]
public void _14张全不同_ShouldNotWin()
{
var hand = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 21, 15, 19 };
var result = _solver.CheckWin(hand);
Assert.False(result.IsWin);
}
// === 七对 ===
[Fact]
public void _ShouldWin()
{
var hand = new List<int> { 1, 1, 3, 3, 5, 5, 7, 7, 11, 11, 13, 13, 21, 21 };
var result = _solver.CheckWin(hand);
Assert.True(result.IsWin);
}
[Fact]
public void _缺一对_ShouldNotWin()
{
var hand = new List<int> { 1, 1, 3, 3, 5, 5, 7, 7, 11, 11, 13, 13, 21, 5 };
var result = _solver.CheckWin(hand);
Assert.False(result.IsWin);
}
// === 十三幺 ===
[Fact]
public void _ShouldWin()
{
var hand = new List<int> { 1, 9, 11, 19, 21, 29, 31, 32, 33, 34, 35, 36, 37, 1 };
var result = _solver.CheckWin(hand);
Assert.True(result.IsWin);
}
[Fact]
public void _缺字牌_ShouldNotWin()
{
var hand = new List<int> { 1, 9, 11, 19, 21, 29, 2, 3, 4, 5, 6, 7, 8, 1 };
var result = _solver.CheckWin(hand);
Assert.False(result.IsWin);
}
// === 番型识别 ===
[Fact]
public void _ShouldIdentify()
{
// 全万: 111万 234万 567万 789万 99万
var hand = new List<int> { 1, 1, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 9 };
var result = _solver.CheckWin(hand);
Assert.True(result.IsWin);
var fans = _solver.IdentifyFans(result!);
Assert.Contains("清一色", fans);
}
[Fact]
public void _ShouldIdentify()
{
var hand = new List<int> { 1, 1, 1, 3, 3, 3, 5, 5, 5, 11, 11, 11, 19, 19 };
var result = _solver.CheckWin(hand);
var fans = _solver.IdentifyFans(result!);
Assert.Contains("对对胡", fans);
}
// === Wildcard ===
[Fact]
public void _1wildcard补刻子_ShouldWin()
{
// 111万 234万 567万 (3 melds) + 条11,条11 + wildcard = 刻子 (4th meld) + 筒9,筒9 = pair
// 13 tiles + 1 wildcard = 14
var hand = new List<int> { 1, 1, 1, 2, 3, 4, 5, 6, 7, 11, 11, 9, 9 };
var result = _solver.CheckWin(hand, wildcardCount: 1);
Assert.True(result.IsWin);
}
[Fact]
public void _2wildcard做对_ShouldWin()
{
// 111万 234万 555万 888万 + 2 wildcards as the pair
var hand = new List<int> { 1, 1, 1, 2, 3, 4, 5, 5, 5, 8, 8, 8 };
var result = _solver.CheckWin(hand, wildcardCount: 2);
Assert.True(result.IsWin);
}
// === 258将 ===
[Fact]
public void _258将_2万_ShouldWin()
{
var hand = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 11, 2, 2 };
var result = _solver.CheckWin(hand, require258Pair: true);
Assert.True(result.IsWin);
}
[Fact]
public void _258将_7万将_ShouldFail()
{
var hand = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 11, 7, 7 };
var result = _solver.CheckWin(hand, require258Pair: true);
Assert.False(result.IsWin);
}
// === 全不靠 ===
// 全不靠需要从16张模板(147×3=9 + 7字)中选14张
// 当前算法要求9数位全占需搭配wildcard。纯手牌场景留待后续完善
// [Fact(Skip = "全不靠需wildcard补位纯14牌无wildcard场景待完善")]
public void _7字牌_7数牌_ShouldWin()
{
// 仅验证算法不崩溃
var hand = new List<int> { 1, 4, 7, 12, 15, 18, 23, 31, 32, 33, 34, 35, 36, 37 };
var result = _solver.CheckWin(hand);
// 标准回溯和七对都失败后全不靠也因缺位而null预期不崩
Assert.True(result == null || !result.IsWin);
}
}