コード例 #1
0
        // Manages every possible moves for the current opponent after his pick.
        private bool OpponentAfterPick(ref Tuple <int, TilePivot, int?> kanInProgress)
        {
            if (_game.Round.IaManager.TsumoDecision(kanInProgress != null))
            {
                InvokeOverlay("Tsumo", _game.Round.CurrentPlayerIndex);
                return(true);
            }

            Tuple <int, TilePivot> opponentWithKanTilePick = _game.Round.IaManager.KanDecision(true);

            if (opponentWithKanTilePick != null)
            {
                TilePivot compensationTile = OpponentBeginCallKan(_game.Round.CurrentPlayerIndex, opponentWithKanTilePick.Item2, true, kanInProgress != null);
                kanInProgress = new Tuple <int, TilePivot, int?>(_game.Round.CurrentPlayerIndex, compensationTile, null);
                return(false);
            }

            kanInProgress = null;

            TilePivot riichiTile = _game.Round.IaManager.RiichiDecision();

            if (riichiTile != null)
            {
                CallRiichi(riichiTile);
                return(false);
            }

            Discard(_game.Round.IaManager.DiscardDecision());
            return(false);
        }
コード例 #2
0
        // Clears and refills the hand panel of the specified player index.
        private void FillHandPanel(int pIndex, TilePivot pickTile = null)
        {
            bool isHuman = pIndex == GamePivot.HUMAN_INDEX;

            Panel panel = this.FindPanel("StpHandP", pIndex);

            this.FindPanel("StpPickP", pIndex).Children.Clear();

            panel.Children.Clear();
            foreach (TilePivot tile in _game.Round.GetHand(pIndex).ConcealedTiles)
            {
                if (pickTile == null || !ReferenceEquals(pickTile, tile))
                {
                    panel.Children.Add(tile.GenerateTileButton(isHuman && !_game.Round.IsRiichi(pIndex) ?
                                                               BtnDiscard_Click : (RoutedEventHandler)null, (AnglePivot)pIndex, !isHuman && !Properties.Settings.Default.DebugMode));
                }
            }

            if (pickTile != null)
            {
                this.FindPanel("StpPickP", pIndex).Children.Add(
                    pickTile.GenerateTileButton(
                        _game.Round.IsHumanPlayer ? BtnDiscard_Click : (RoutedEventHandler)null,
                        (AnglePivot)pIndex,
                        !_game.Round.IsHumanPlayer && !Properties.Settings.Default.DebugMode
                        )
                    );
            }
        }
コード例 #3
0
ファイル: GraphicTools.cs プロジェクト: thelpi/Gnoj-Ham
        /// <summary>
        /// Extension; generates a button which represents a tile.
        /// </summary>
        /// <param name="tile">The tile to display.</param>
        /// <param name="handler">Optionnal; event on click on the button; default value is <c>Null</c>.</param>
        /// <param name="angle">Optionnal; rotation angle; default is <c>0°</c>.</param>
        /// <param name="concealed">Optionnal; set <c>True</c> to display a concealed tile; default is <c>False</c>.</param>
        /// <returns>A button representing the tile.</returns>
        internal static Button GenerateTileButton(this TilePivot tile, RoutedEventHandler handler = null, AnglePivot angle = AnglePivot.A0, bool concealed = false)
        {
            string rscName = concealed ? CONCEALED_TILE_RSC_NAME : tile.ToString();

            Bitmap tileBitmap = Properties.Resources.ResourceManager.GetObject(rscName) as Bitmap;

            var button = new Button
            {
                Height  = angle == AnglePivot.A0 || angle == AnglePivot.A180 ? TILE_HEIGHT : TILE_WIDTH,
                Width   = angle == AnglePivot.A0 || angle == AnglePivot.A180 ? TILE_WIDTH : TILE_HEIGHT,
                Content = new System.Windows.Controls.Image
                {
                    Source          = tileBitmap.ToBitmapImage(),
                    LayoutTransform = new RotateTransform(Convert.ToDouble(angle.ToString().Replace("A", string.Empty)))
                },
                Tag = tile
            };

            if (handler != null)
            {
                button.Click += handler;
            }

            return(button);
        }
コード例 #4
0
 internal Substitution(TilePivot subbed, TilePivot subber, IEnumerable <TilePivot> subSource)
 {
     Subbed      = subbed;
     Subber      = subber;
     SubSource   = subSource.ToList();
     Probability = SubSource.Count(t => t.Equals(Subber)) / (double)SubSource.Count;
 }
コード例 #5
0
ファイル: IsComplete_Tests.cs プロジェクト: thelpi/Gnoj-Ham
        public void IsComplete_WithDeclaredKan_ComplexMultiplePatterns()
        {
            List <TilePivot> tilesSet = TilePivot.GetCompleteSet(false);

            var concealedTiles = new List <TilePivot>
            {
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 1),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 1),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 2),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 2),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 3),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 3),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 4),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 4),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 4),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 5),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 6)
            };

            concealedTiles = concealedTiles.OrderBy(t => GlobalTools.Randomizer.NextDouble()).ToList();

            List <List <TileComboPivot> > result = HandPivot.IsCompleteBasic(concealedTiles, new List <TileComboPivot>
            {
                TileComboPivot.BuildSquare(TilePivot.GetTile(tilesSet, FamilyPivot.Dragon, dragon: DragonPivot.White))
            });

            Assert.IsNotNull(result);
            Assert.AreEqual(2, result.Count);
            result.ForEach(cg => AssertFiveCombinationsIncludingOnePair(cg));
        }
コード例 #6
0
ファイル: IsComplete_Tests.cs プロジェクト: thelpi/Gnoj-Ham
        public void IsComplete_FullyConcealed_AverageSinglePattern()
        {
            List <TilePivot> tilesSet = TilePivot.GetCompleteSet(false);

            var concealedTiles = new List <TilePivot>
            {
                TilePivot.GetTile(tilesSet, FamilyPivot.Wind, wind: WindPivot.North),
                TilePivot.GetTile(tilesSet, FamilyPivot.Wind, wind: WindPivot.North),
                TilePivot.GetTile(tilesSet, FamilyPivot.Dragon, dragon: DragonPivot.Red),
                TilePivot.GetTile(tilesSet, FamilyPivot.Dragon, dragon: DragonPivot.Red),
                TilePivot.GetTile(tilesSet, FamilyPivot.Dragon, dragon: DragonPivot.Red),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 1),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 1),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 1),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 2),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 2),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 3),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 3),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 4),
                TilePivot.GetTile(tilesSet, FamilyPivot.Circle, number: 4)
            };

            concealedTiles = concealedTiles.OrderBy(t => GlobalTools.Randomizer.NextDouble()).ToList();

            List <List <TileComboPivot> > result = HandPivot.IsCompleteBasic(concealedTiles, new List <TileComboPivot>());

            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.Count);
            AssertFiveCombinationsIncludingOnePair(result[0]);
        }
コード例 #7
0
 // Common trunk of the kan call process.
 private void CommonCallKan(int?previousPlayerIndex, TilePivot compensationTile)
 {
     Dispatcher.Invoke(() =>
     {
         if (previousPlayerIndex.HasValue)
         {
             FillDiscardPanel(previousPlayerIndex.Value);
         }
         FillCombinationStack(_game.Round.CurrentPlayerIndex);
         SetActionButtonsVisibility(cpuPlay: !_game.Round.IsHumanPlayer, preDiscard: _game.Round.IsHumanPlayer);
         StpDoras.SetDorasPanel(_game.Round.DoraIndicatorTiles, _game.Round.VisibleDorasCount);
     });
 }
コード例 #8
0
        // Pick action (human or CPU).
        private void Pick()
        {
            TilePivot pick = _game.Round.Pick();

            Dispatcher.Invoke(() =>
            {
                SetPlayersLed();
                if (_game.Round.IsHumanPlayer)
                {
                    SetActionButtonsVisibility(preDiscard: true);
                }
            });
        }
コード例 #9
0
        private bool ExtractFromForm(out List <TilePivot> tiles, out TilePivot latestPickTile, out WindPivot dominantWind, out WindPivot seatWind)
        {
            tiles          = new List <TilePivot>();
            latestPickTile = null;
            dominantWind   = WindPivot.East;
            seatWind       = WindPivot.East;

            for (int i = 1; i <= 14; i++)
            {
                if (GetCombo(i).SelectedItem == null)
                {
                    MessageBox.Show("Some slots are empty.", "LionelRiichiStats - Error");
                    return(false);
                }
                TilePivot tile = GetCombo(i).SelectedItem as TilePivot;
                if (GetRadio(i).IsChecked == true && latestPickTile == null)
                {
                    latestPickTile = tile;
                }
                else
                {
                    tiles.Add(tile);
                }
            }
            if (latestPickTile == null)
            {
                MessageBox.Show("The latest tile has not been selected.", "LionelRiichiStats - Error");
                return(false);
            }
            if (tiles.Concat(new List <TilePivot> {
                latestPickTile
            }).GroupBy(t => t).Any(tg => tg.Count() > 4))
            {
                MessageBox.Show("One tile is selected more than four times.", "LionelRiichiStats - Error");
                return(false);
            }
            if (CbbDominantWind.SelectedIndex == -1)
            {
                MessageBox.Show("The dominant wind has not been selected.", "LionelRiichiStats - Error");
                return(false);
            }
            if (CbbSeatWind.SelectedIndex == -1)
            {
                MessageBox.Show("The seat wind has not been selected.", "LionelRiichiStats - Error");
                return(false);
            }
            dominantWind = (WindPivot)CbbDominantWind.SelectedItem;
            seatWind     = (WindPivot)CbbSeatWind.SelectedItem;

            return(true);
        }
コード例 #10
0
        // Inner process kan call.
        private void HumanKanCallProcess(TilePivot tile, int?previousPlayerIndex)
        {
            TilePivot compensationTile = _game.Round.CallKan(GamePivot.HUMAN_INDEX, tile);

            InvokeOverlay("Kan", GamePivot.HUMAN_INDEX);
            if (CheckOpponensRonCall(false))
            {
                _game.Round.UndoPickCompensationTile();
                NewRound(_game.Round.CurrentPlayerIndex);
            }
            else
            {
                CommonCallKan(previousPlayerIndex, compensationTile);

                if (_game.Round.CanCallTsumo(true))
                {
                    BtnTsumo.Visibility    = Visibility.Visible;
                    BtnSkipCall.Visibility = Visibility.Visible;
                    if (Properties.Settings.Default.AutoCallMahjong)
                    {
                        BtnTsumo.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
                    }
                    else
                    {
                        ActivateTimer(null);
                    }
                }
                else
                {
                    _riichiTiles = _game.Round.CanCallRiichi();
                    if (_riichiTiles.Count > 0)
                    {
                        BtnRiichi.Visibility   = Visibility.Visible;
                        BtnSkipCall.Visibility = Visibility.Visible;
                        ActivateTimer(null);
                    }
                    else if (Properties.Settings.Default.AutoDiscardAfterRiichi && _game.Round.HumanCanAutoDiscard())
                    {
                        // Auto discard if riichi and the compensation tile is not interesting
                        // Never tested!
                        RaiseButtonClickEvent(new PanelButton("StpPickP", 0));
                    }
                }
            }
        }
コード例 #11
0
        // Proceeds to call a kan for an opponent.
        private TilePivot OpponentBeginCallKan(int playerId, TilePivot kanTilePick, bool concealedKan, bool fromPreviousKan)
        {
            TilePivot compensationTile = _game.Round.CallKan(playerId, concealedKan ? kanTilePick : null);

            if (compensationTile != null)
            {
                InvokeOverlay("Kan", playerId);
                Thread.Sleep(((CpuSpeedPivot)Properties.Settings.Default.CpuSpeed).ParseSpeed());
                Dispatcher.Invoke(() =>
                {
                    if (!concealedKan)
                    {
                        SetPlayersLed();
                    }
                });
            }
            return(compensationTile);
        }
コード例 #12
0
        // Discard action (human or CPU).
        private void Discard(TilePivot tile)
        {
            if (_game.Round.Discard(tile))
            {
                if (!_game.Round.PreviousIsHumanPlayer)
                {
                    Thread.Sleep(((CpuSpeedPivot)Properties.Settings.Default.CpuSpeed).ParseSpeed());
                }

                Dispatcher.Invoke(() =>
                {
                    FillHandPanel(_game.Round.PreviousPlayerIndex);
                    FillDiscardPanel(_game.Round.PreviousPlayerIndex);
                    SetActionButtonsVisibility(cpuPlay: !_game.Round.PreviousIsHumanPlayer);
                });

                if (_game.Round.PreviousIsHumanPlayer)
                {
                    RunAutoPlay();
                }
            }
        }
コード例 #13
0
        // Initializes a background worker which orchestrates the CPU actions.
        private void InitializeAutoPlayWorker()
        {
            _autoPlay = new BackgroundWorker
            {
                WorkerReportsProgress      = false,
                WorkerSupportsCancellation = false
            };
            _autoPlay.DoWork += delegate(object sender, DoWorkEventArgs evt)
            {
                object[] argumentsList     = evt.Argument as object[];
                bool     skipCurrentAction = (bool)argumentsList[0];
                bool     humanRonPending   = (bool)argumentsList[1];
                Tuple <int, TilePivot, int?> kanInProgress = null;
                AutoPlayResult result = new AutoPlayResult
                {
                    EndOfRound  = false,
                    PanelButton = null,
                    RonPlayerId = null
                };
                while (true && !_hardStopAutoplay)
                {
                    if (!skipCurrentAction && !humanRonPending && _game.Round.CanCallRon(GamePivot.HUMAN_INDEX))
                    {
                        Dispatcher.Invoke(() =>
                        {
                            BtnRon.Visibility      = Visibility.Visible;
                            BtnSkipCall.Visibility = Visibility.Visible;
                        });
                        ActivateTimer(null);
                        if (Properties.Settings.Default.AutoCallMahjong)
                        {
                            result.PanelButton = new PanelButton("BtnRon", -1);
                        }
                        break;
                    }

                    if (CheckOpponensRonCall(humanRonPending))
                    {
                        result.EndOfRound  = true;
                        result.RonPlayerId = kanInProgress != null ? kanInProgress.Item1 : _game.Round.PreviousPlayerIndex;
                        if (kanInProgress != null)
                        {
                            _game.Round.UndoPickCompensationTile();
                        }
                        break;
                    }

                    if (kanInProgress != null)
                    {
                        CommonCallKan(kanInProgress.Item3, kanInProgress.Item2);
                    }

                    if (!skipCurrentAction && _game.Round.CanCallPonOrKan(GamePivot.HUMAN_INDEX))
                    {
                        break;
                    }

                    Tuple <int, TilePivot> opponentWithKanTilePick = _game.Round.IaManager.KanDecision(false);
                    if (opponentWithKanTilePick != null)
                    {
                        int       previousPlayerIndex = _game.Round.PreviousPlayerIndex;
                        TilePivot compensationTile    = OpponentBeginCallKan(opponentWithKanTilePick.Item1, opponentWithKanTilePick.Item2, false, false);
                        kanInProgress = new Tuple <int, TilePivot, int?>(opponentWithKanTilePick.Item1, compensationTile, previousPlayerIndex);
                        continue;
                    }

                    int opponentPlayerId = _game.Round.IaManager.PonDecision();
                    if (opponentPlayerId > -1)
                    {
                        PonCall(opponentPlayerId);
                        continue;
                    }

                    if (!skipCurrentAction && _game.Round.IsHumanPlayer && _game.Round.CanCallChii().Count > 0)
                    {
                        break;
                    }

                    Tuple <TilePivot, bool> chiiTilePick = _game.Round.IaManager.ChiiDecision();
                    if (chiiTilePick != null)
                    {
                        ChiiCall(chiiTilePick);
                        continue;
                    }

                    if (kanInProgress != null)
                    {
                        if (OpponentAfterPick(ref kanInProgress))
                        {
                            break;
                        }
                        continue;
                    }

                    if (_game.Round.IsWallExhaustion)
                    {
                        result.EndOfRound = true;
                        break;
                    }

                    if (_game.Round.IsHumanPlayer)
                    {
                        result.PanelButton = HumanAutoPlay();
                        break;
                    }
                    else
                    {
                        Pick();
                        if (OpponentAfterPick(ref kanInProgress))
                        {
                            result.EndOfRound = true;
                            break;
                        }
                    }
                }

                evt.Result = result;
            };
            _autoPlay.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs evt)
            {
                if (!_hardStopAutoplay)
                {
                    AutoPlayResult autoPlayResult = evt.Result as AutoPlayResult;
                    if (autoPlayResult.EndOfRound)
                    {
                        NewRound(autoPlayResult.RonPlayerId);
                    }
                    else
                    {
                        RaiseButtonClickEvent(autoPlayResult.PanelButton);
                    }
                }
            };
        }