public SuitScoringBitField(ArrangementGroup arrangements, int fuFootprintIndex) { _arrangementGroup = arrangements; _iipeikouCount = CalculateIipeikouCount(); // Yaku SanshokuDoujun(); SanshokuDoukou(); Tanyao(29); IipeikouRyanpeikou(38); Chiitoitsu(40); Pinfu(51); Ankou(32); HonitsuChinitsu(20); KokushiMusou(); Chinroutou(37); Chuuren(62); Chanta(27); Honroutou(26); Toitoi(31); Junchan(49); Ittsuu(44); Ryuuiisou(28); // Fu WaitShiftValue |= (long)fuFootprintIndex << 10; if (arrangements.HasSquareType) { OrValue |= 1L << 34; } }
private static bool Matches(ArrangementGroup arrangements, Arrangement arrangement, FuConstraint constraint) { if (constraint.DoujunIndex >= 0 && !arrangement.ContainsShuntsu(constraint.DoujunIndex)) { // open hands with less than 6 tiles in the arrangement can use a meld to get sanshoku if (arrangements.TileCount > 5 || !constraint.Open) { return(false); } } if (constraint.DoukouIndex >= 0 && !arrangement.ContainsKoutsu(constraint.DoukouIndex)) { // hands with less than 6 tiles in the arrangement can use a meld to get sanshoku. If closed must be ankan if (arrangements.TileCount > 5) { return(false); } } var hasIipeikou = arrangement.Blocks.Where(b => b.IsShuntsu).GroupBy(s => s.Index).Any(g => g.Count() >= 2); if (arrangements.HasIipeikou && !constraint.Open && !hasIipeikou) { if (!arrangements.HasSquareType || constraint.SquareIsNotSanankou) { return(false); } } if (constraint.SquareIsNotSanankou && arrangement.Blocks.Count(b => b.IsKoutsu) >= 3) { return(false); } return(true); }
public FuFootprintCreator(ArrangementGroup arrangements) { // TODO exclude nonstandard hands // Fu does not matter for chinitsu if (arrangements.TileCount == 14) { return; } var constraints = CreateConstraints(arrangements); var constraintToFu = new Dictionary <FuConstraint, int>(); foreach (var constraint in constraints) { var bestFu = 0; foreach (var arrangement in arrangements.Arrangements) { if (!Matches(arrangements, arrangement, constraint)) { continue; } var winningIndex = constraint.WinningIndex; var pairIndex = arrangement.Blocks.FirstOrDefault(b => b.IsPair)?.Index; var shuntsus = arrangement.Blocks.Where(b => b.IsShuntsu).ToList(); var fu = 0; foreach (var koutsu in arrangement.Blocks.Where(b => b.IsKoutsu)) { if (constraint.Tsumo || koutsu.Index != winningIndex || HasShuntsuWithWinningTile(arrangement, winningIndex)) { fu += koutsu.IsJunchanBlock ? 8 : 4; } else { fu += koutsu.IsJunchanBlock ? 4 : 2; } } if (pairIndex == winningIndex) { fu += 2; } else if (shuntsus.Any(s => s.Index == winningIndex - 1)) { fu += 2; } else if (shuntsus.Any(s => s.Index == 0 && winningIndex == 2)) { fu += 2; } else if (shuntsus.Any(s => s.Index == 6 && winningIndex == 6)) { fu += 2; } bestFu = Math.Max(bestFu, fu); } constraintToFu.Add(constraint, bestFu); } foreach (var keyValuePair in constraintToFu) { Footprint[keyValuePair.Key.Id] = (byte)keyValuePair.Value; } }
private static List <FuConstraint> CreateConstraints(ArrangementGroup arrangementGroup) { var uTypeIndex = arrangementGroup.UTypeIndex; var tileCounts = arrangementGroup.TileCounts; var constraints = new List <FuConstraint>(); for (var winningIndex = -1; winningIndex < 9; winningIndex++) { if (winningIndex == -1 || tileCounts[winningIndex] > 0) { AddConstraints(constraints, false, winningIndex, -1, -1); if (uTypeIndex >= 0) { AddConstraints(constraints, false, winningIndex, uTypeIndex, -1); AddConstraints(constraints, false, winningIndex, uTypeIndex + 1, -1); AddConstraints(constraints, false, winningIndex, -1, uTypeIndex); AddConstraints(constraints, false, winningIndex, -1, uTypeIndex + 3); } else if (arrangementGroup.TileCount < 6) // melds can be used for sanshoku here { // could have square in different suit, but not together with sanshoku AddConstraints(constraints, true, winningIndex, -1, -1); for (var i = 0; i < 7; i++) { AddConstraints(constraints, false, winningIndex, i, -1); } for (var i = 0; i < 9; i++) { if (tileCounts[i] < 2 || arrangementGroup.Arrangements.Any(a => a.ContainsKoutsu(i))) { AddConstraints(constraints, false, winningIndex, -1, i); } } } else if (arrangementGroup.TileCount < 9) // melds can't be used for sanshoku here { var shuntsus = arrangementGroup.Arrangements.SelectMany(a => a.Blocks.Where(b => b.IsShuntsu)); var doujunIndexes = shuntsus.Select(s => s.Index).Distinct(); foreach (var doujunIndex in doujunIndexes) { AddConstraints(constraints, false, winningIndex, doujunIndex, -1); } var koustsus = arrangementGroup.Arrangements.SelectMany(a => a.Blocks.Where(b => b.IsKoutsu)); var doukouIndexes = koustsus.Select(s => s.Index).Distinct(); foreach (var doukouIndex in doukouIndexes) { AddConstraints(constraints, false, winningIndex, -1, doukouIndex); } } else if (arrangementGroup.HasSquareType) { AddConstraints(constraints, true, winningIndex, -1, -1); } } } return(constraints); }