diff --git a/BiddingLogic/BidManager.cs b/BiddingLogic/BidManager.cs index 1b2c68e..4438474 100644 --- a/BiddingLogic/BidManager.cs +++ b/BiddingLogic/BidManager.cs @@ -115,6 +115,8 @@ public static void SetOptimizationParameters(string json) public ConstructedSouthhandOutcome constructedSouthhandOutcome = ConstructedSouthhandOutcome.NotSet; public BiddingState BiddingState { get; set; } + private bool CanSkipControlScanningFase { get; set; } = true; + public bool HasSkippedControlScanningFase { get; private set; } = false; // Constructor used for test public BidManager(IBidGenerator bidGenerator, Dictionary fasesWithOffset, ReverseDictionaries reverseDictionaries, RelayBidKindFunc getRelayBidKindFunc) : @@ -243,6 +245,10 @@ private Bid GetNorthBid(BiddingState biddingState, Auction auction, string north if (useSingleDummySolverDuringRelaying) if (TryGetEndContract(southInformation, out var bid)) return bid; + if (CanSkipControlScanningFase) + if (TryGetAskQueensBid(southInformation, out var askQueensbid)) + return askQueensbid; + } } @@ -326,7 +332,7 @@ bool TryGetEndContract(SouthInformation southInformation, out Bid bid) bid = GetEndContract(possibleContracts, biddingState.CurrentBid); if (bid != null) { - if (biddingState.Fase == Fase.ScanningOther) + if (biddingState.Fase == Fase.ScanningOther && southInformation.SpecificControls != null) constructedSouthhandOutcome = southInformation.SpecificControls.Count() == 1 ? ConstructedSouthhandOutcome.SouthhandMatches : ConstructedSouthhandOutcome.MultipleMatchesFound; biddingState.Fase = Fase.End; @@ -338,6 +344,22 @@ bool TryGetEndContract(SouthInformation southInformation, out Bid bid) return bid != null; } + bool TryGetAskQueensBid(SouthInformation southInformation, out Bid askQueensbid) + { + askQueensbid = null; + if (southInformation.SpecificControls != null && southInformation.Controls.Min >= 6 && biddingState.Fase == Fase.ScanningControls) + { + askQueensbid = Bid.NextBid(Bid.NextBid(biddingState.CurrentBid)); + biddingState.Fase = Fase.ScanningOther; + biddingState.RelayBidIdLastFase++; + loggerBidding.Info("Special ask for queens because controls >= 6 and controls scanning is known"); + HasSkippedControlScanningFase = true; + return true; + } + return false; + } + + Bid GetRelayBid() { if (biddingState.CurrentBid == Bid.threeSpadeBid && biddingState.Fase != Fase.Shape && reverseDictionaries != null) @@ -469,11 +491,11 @@ public void SouthBid(Auction auction, string handsString) var lzoomOffset = nextfase switch { Fase.Controls => reverseDictionaries == null ? zoomOffset : biddingInformation.Shape.Value.zoomOffset, - Fase.ScanningOther => reverseDictionaries == null ? zoomOffset : biddingInformation.ControlsScanning.Value.zoomOffset, + Fase.ScanningOther => reverseDictionaries == null ? zoomOffset : HasSkippedControlScanningFase ? 0 : biddingInformation.ControlsScanning.Value.zoomOffset, _ => 0, }; // Check if controls and their positions are correctly evaluated. - if (nextfase == Fase.ScanningOther && reverseDictionaries != null) + if (nextfase == Fase.ScanningOther && reverseDictionaries != null && !HasSkippedControlScanningFase) { var controlsInSuit = Util.GetHandWithOnlyControlsAs4333(handsString, "AK"); if (!biddingInformation.ControlsScanning.Value.controls.Contains(controlsInSuit)) diff --git a/BiddingLogic/BiddingInformation.cs b/BiddingLogic/BiddingInformation.cs index 9ba29ba..12562a8 100644 --- a/BiddingLogic/BiddingInformation.cs +++ b/BiddingLogic/BiddingInformation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -52,7 +53,7 @@ public SouthInformation GetInformationFromAuction(Auction auction, string northH var possibleControls = reverseDictionaries.ControlsOnlyAuctions[string.Join("", controls)]; southInformation.Controls = new MinMax(possibleControls.First(), possibleControls.Last()); // Special case if relayer is able figure out the position of controls - if (southInformation.ControlsScanningBidCount == 0) + if (southInformation.ControlsScanningBidCount == 0 && possibleControls.Distinct().Count() == 1) { var matches = GetMatchesWithNorthHand(Shape.Value.shapes, possibleControls.First(), northHand); if (matches.Count() == 1) @@ -68,9 +69,10 @@ public SouthInformation GetInformationFromAuction(Auction auction, string northH throw new InvalidOperationException($"No matches found. NorthHand:{northHand}"); southInformation.SpecificControls = matches.Select(match => match.Split(',').Select(x => Regex.Replace(x, "[^AK]", "")).ToArray()); - southInformation.Queens = GetQueensFromAuction(auction, reverseDictionaries, biddingState); } + southInformation.Queens = GetQueensFromAuction(auction, reverseDictionaries, biddingState); + loggerBidding.Info($"SouthInformation. {JsonConvert.SerializeObject(southInformation)}"); return southInformation; } @@ -147,15 +149,15 @@ int GetOffsetRelayBid(Bid currentBid) public string GetQueensFromAuction(Auction auction, ReverseDictionaries reverseDictionaries, BiddingState biddingState) { // Because the last shape is the one with the highest numeric value generated in ReverseDictionaries - var shapeStr = Shape.Value.shapes.Last(); - var zoomOffset = ControlsScanning.Value.zoomOffset; - var lastBidScanningControl = biddingState.GetBids(Fase.ScanningControls).Last(); var queensBids = biddingState.GetBids(Fase.ScanningOther); + if (!queensBids.Any()) + return null; + var shapeStr = Shape.Value.shapes.Last(); + var zoomOffset = ControlsScanning.IsValueCreated ? ControlsScanning.Value.zoomOffset : 0; + var lastBidPreviousFase = auction.GetBids(Player.South).ToList().TakeWhile(bid => bid != queensBids.First()).Last(); var offsetBid = ReverseDictionaries.GetOffsetBidForQueens(shapeStr); - var queensBidsResult = GetBidsForFaseWithOffset(queensBids, offsetBid, lastBidScanningControl, zoomOffset, GetOffsetRelayBid); - if (!queensBidsResult.Any()) - return null; + var queensBidsResult = GetBidsForFaseWithOffset(queensBids, offsetBid, lastBidPreviousFase, zoomOffset, GetOffsetRelayBid).ToList(); var queensAuctions = reverseDictionaries.GetQueensDictionary(shapeStr); var bidsForFaseQueens = string.Join("", queensBidsResult); diff --git a/TosrIntegration.Test/DirectlyAskForQueensTest.cs b/TosrIntegration.Test/DirectlyAskForQueensTest.cs new file mode 100644 index 0000000..cf94f1e --- /dev/null +++ b/TosrIntegration.Test/DirectlyAskForQueensTest.cs @@ -0,0 +1,44 @@ +using BiddingLogic; +using Common.Test; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace TosrIntegration.Test +{ + [Collection("Sequential")] + + public class DirectlyAskForQueensTest : IClassFixture + { + private BaseTestFixture Fixture { get; } + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + + + public DirectlyAskForQueensTest(BaseTestFixture fixture) + { + Fixture = fixture; + } + + public static IEnumerable TestCases() + { + yield return new object[] { "OneMatchFound", "AK85,K,AQ42,QJT2", "QT642,AJ54,K7,AK", "1♣1♠2♣3♦4♥5♣5♥Pass", "1♥1NT3♣4♣4NT5♦5♠" }; + yield return new object[] { "MultipleMatchesFound", "KQJT43,AQ,KJ,KQJ", "A6,8752,AQ83,A64", "1♣1NT2♥3♣4♣4♥5♥6♣Pass", "1♠2♦2NT3NT4♦5♦5NT6♦" }; + yield return new object[] { "OneMatchFoundPull4Di", "T3,AK532,Q2,AK85", "AKQ954,,AKJ4,Q62", "1♣1♠2♦3♣4♦5♠6♦Pass", "1♥2♣2NT3♠5♦6♣6♠" }; + yield return new object[] { "MultipleMatchesFoundPull4Di", "J86,KT,AQT95,AQT", "AQ7,AJ98654,K,K4", "1♣2♣3♣4♦5♥6♥Pass", "1NT2NT3NT5♦6♦6NT" }; + } + + [Theory] + [MemberData(nameof(TestCases))] + public void TestAuctionsQueens(string testName, string northHand, string southHand, string expectedBidsNorth, string expectedBidsSouth) + { + SetupTest.setupTest(testName, logger); + var bidManager = new BidManager(new BidGenerator(), Fixture.fasesWithOffset, Fixture.reverseDictionaries, false); + var auction = bidManager.GetAuction(northHand, southHand); + AssertMethods.AssertAuction(expectedBidsNorth, expectedBidsSouth, auction); + } + } +} diff --git a/Wpf.Tosr/BatchBidding.cs b/Wpf.Tosr/BatchBidding.cs index 54278e5..60a6d08 100644 --- a/Wpf.Tosr/BatchBidding.cs +++ b/Wpf.Tosr/BatchBidding.cs @@ -180,7 +180,7 @@ private void AddHandAndAuction(string[] board, Auction auction, int boardNumber, AddHandPerAuction(str, strAuction); // Start calculating hand - if (!auction.responderHasSignedOff) + if (!auction.responderHasSignedOff && !bidManager.HasSkippedControlScanningFase) expectedSouthHands.AppendLine($"Board:{boardNumber} { bidManager.ConstructSouthHandSafe(board, auction)}"); var longestSuit = Util.GetLongestSuit(board[(int)Player.North], board[(int)Player.South]); diff --git a/Wpf.Tosr/MainWindow.xaml.cs b/Wpf.Tosr/MainWindow.xaml.cs index bdd2b47..e4fd7e1 100644 --- a/Wpf.Tosr/MainWindow.xaml.cs +++ b/Wpf.Tosr/MainWindow.xaml.cs @@ -278,7 +278,6 @@ private async void ButtonBatchBiddingClick(object sender, EventArgs e) { resetEvent.WaitOne(); panelNorth.Visibility = Visibility.Hidden; - var batchBidding = new BatchBidding(reverseDictionaries, fasesWithOffset, toolStripMenuItemUseSolver.IsChecked); toolStripStatusLabel1.Content = "Batch bidding hands..."; cancelBatchbidding.Dispose(); cancelBatchbidding = new CancellationTokenSource(); @@ -287,6 +286,7 @@ private async void ButtonBatchBiddingClick(object sender, EventArgs e) try { Cursor = Cursors.Wait; + var batchBidding = new BatchBidding(reverseDictionaries, fasesWithOffset, toolStripMenuItemUseSolver.IsChecked); await Task.Run(() => { var progress = new Progress(report => Dispatcher.Invoke(() => toolStripStatusLabel1.Content = $"Hands done: {report}"));