// §5.1/5.2 正常跟牌/毙牌/垫牌(can_followcard 纯函数)。期望值取自 design §5.2 require('./_shim'); const A = require('../class.arith.js'); const t = require('./_assert')(); const id = (d, f, n) => (d - 1) * 54 + (f - 1) * 13 + (n - 1); const MF = 1; // 主花色=方块(1) // 副花色2的牌(number 避开 2/7,否则是固定主) const K = d => id(d, 2, 13), Q = d => id(d, 2, 12), J = d => id(d, 2, 11), T = d => id(d, 2, 10), N9 = d => id(d, 2, 9), N8 = d => id(d, 2, 8); // 主牌(flower1) const zK = d => id(d, 1, 13), zQ = d => id(d, 1, 12), zJ = d => id(d, 1, 11), z9 = d => id(d, 1, 9); // 另一副花色3(用于垫牌) const oth = n => id(1, 3, n); // follow(inhand, cards, startcount, startflower, startcardtype) -> can_followcard 结果 const f = (inhand, cards, cnt, flw, typ) => A.can_followcard(MF, inhand, cards, cnt, flw, typ); const res = r => r.result; // 能否跟 const beat = r => (r.cardvalue || 0) > 0; // 是否压过(cardvalue>0) // ===================== 单张跟牌(首家 副K 单张,flower2, 101)===================== // §5.2: 跟同花色任意单张;缺门则任意补(毙牌用主牌可压、垫副牌不压) t.eq('单-跟同花色单张(合法)', res(f([N9(1), z9(1)], [N9(1)], 1, 2, 101)), true); t.eq('单-有同花色却出主牌(拒)', res(f([N9(1), zK(1)], [zK(1)], 1, 2, 101)), false); t.eq('单-缺门垫副牌(合法)', res(f([oth(9), zK(1)], [oth(9)], 1, 2, 101)), true); t.eq('单-缺门垫副牌不压', beat(f([oth(9), zK(1)], [oth(9)], 1, 2, 101)), false); t.eq('单-缺门毙牌主单(合法)', res(f([oth(9), zK(1)], [zK(1)], 1, 2, 101)), true); t.eq('单-缺门毙牌主单压过', beat(f([oth(9), zK(1)], [zK(1)], 1, 2, 101)), true); // ===================== 对子跟牌(首家 副K对,flower2, 201, 2张)===================== // §2: 有同花色对必出对;没对用两张同花色单;不足两张任意补;缺门毙牌必须主对(不能任意两张) t.eq('对-有同花色对必出对(合法)', res(f([N9(1), N9(2), N8(1)], [N9(1), N9(2)], 2, 2, 201)), true); t.eq('对-有对却出两散张(拒)', res(f([N9(1), N9(2), N8(1)], [N9(1), N8(1)], 2, 2, 201)), false); t.eq('对-无对出两同花色单(合法)', res(f([N9(1), N8(1), Q(1)], [N9(1), N8(1)], 2, 2, 201)), true); t.eq('对-缺门毙主对(合法且压)', beat(f([zK(1), zK(2), oth(9)], [zK(1), zK(2)], 2, 2, 201)), true); t.eq('对-缺门两散主顶对(可出但不压)', res(f([zK(1), zQ(1), oth(9)], [zK(1), zQ(1)], 2, 2, 201)), true); t.eq('对-缺门两散主顶对 不压', beat(f([zK(1), zQ(1), oth(9)], [zK(1), zQ(1)], 2, 2, 201)), false); // ===================== 拖拉机跟牌(首家 副KQ两连对,flower2, 302, 4张)===================== // §2: 有同花色拖拉机必出拖;无拖但有两对不连也必出两对 t.eq('拖-有同长拖必出拖(合法)', res(f([J(1), J(2), T(1), T(2), N8(1)], [J(1), J(2), T(1), T(2)], 4, 2, 302)), true); t.eq('拖-有拖却出4散(拒)', res(f([J(1), J(2), T(1), T(2), N8(1)], [J(1), T(1), N9(1), N8(1)], 4, 2, 302)), false); t.eq('拖-无拖两对不连必出两对(合法)', res(f([J(1), J(2), N9(1), N9(2), N8(1)], [J(1), J(2), N9(1), N9(2)], 4, 2, 302)), true); t.eq('拖-有两对却出散张(拒)', res(f([J(1), J(2), N9(1), N9(2), N8(1)], [J(1), N9(1), N8(1), Q(1)], 4, 2, 302)), false); t.eq('拖-缺门毙同长主拖(合法且压)', beat(f([zK(1), zK(2), zQ(1), zQ(2), oth(9)], [zK(1), zK(2), zQ(1), zQ(2)], 4, 2, 302)), true); process.exit(t.done('follow') ? 0 : 1);