Пример #1
0
        // 所持カードを取得する
        private List <string>[] GetOwnCards(string[] lines, string[] shortPlayerNames)
        {
            string[] get_strings  = new string[] { "受け取った。", "獲得した。", "購入・獲得した。", "廃棄置き場から獲得した。" };
            string[] lost_strings = new string[] { "廃棄した。", "戻した。" };
            string   give_string  = "渡した。";                                 // 仮面舞踏会
            var      ownCards     = new List <string>[2] {
                new List <string>(), new List <string>()
            };

            foreach (var line in lines)
            {
                var(name, action, cards, destination, inParentheses) = Extractor.Extract(line);
                for (int i = 0; i < 2; ++i)
                {
                    if (name == shortPlayerNames[i])
                    {
                        if (get_strings.Any(s => s == action))
                        {
                            ownCards[i].AddRange(cards);
                        }
                        if (lost_strings.Any(s => s == action))
                        {
                            foreach (var card in cards)
                            {
                                ownCards[i].Remove(card);
                            }
                        }
                        if (give_string == action)
                        {
                            foreach (var card in cards)
                            {
                                ownCards[i].Remove(card);
                            }
                            int opponent = (i + 1) % 2;
                            ownCards[opponent].AddRange(cards);
                        }
                    }
                }
            }
            return(ownCards);
        }
Пример #2
0
        private void SaveLog(string[] lines, string[] shortPlayerNames)
        {
            var extractedLog = new StringBuilder();

            foreach (var line in lines)
            {
                var(name, action, cards, destination, inParentheses) = Extractor.Extract(line);
                if (name != null && shortPlayerNames.Any(name.Equals) && action != null)
                {
                    extractedLog.Append(
                        "name = " + name
                        + "\taction = " + action
                        + "\tcards = " + string.Join(",", cards)
                        + "\tdestination = " + destination
                        + "\tinParentheses = " + inParentheses
                        + Environment.NewLine);
                }
            }
            using (var sw = new System.IO.StreamWriter("extracted_log.txt")) sw.Write(extractedLog);
            using (var sw = new System.IO.StreamWriter("game_log.txt")) sw.Write(string.Join(Environment.NewLine, lines));
        }
Пример #3
0
        /// <summary>1行を処理する</summary>
        /// <param name="line">行</param>
        public void Transact(string line)
        {
            var myName       = shortPlayerNames[myTurnNumber];
            var opponentName = shortPlayerNames[(myTurnNumber + 1) % 2];

            if (line.Contains("前哨地は不発となる。"))
            {
                myHand.Add("前哨地");
                Remove(ref myDuration, new List <string> {
                    "前哨地"
                }, "持続場に前哨地がありません");
                return;
            }
            if (line.Contains("女魔術師により") && line.Contains("無効化された。"))
            {
                current_state       = state.normal;
                myArchive           = new List <string>(previousMyCards.myArchive);
                myBar               = new List <string>(previousMyCards.myBar);
                myCrypt             = new List <string>(previousMyCards.myCrypt);
                myDeck              = new List <string>(previousMyCards.myDeck);
                myDiscard           = new List <string>(previousMyCards.myDiscard);
                myDuration          = new List <string>(previousMyCards.myDuration);
                myHand              = new List <string>(previousMyCards.myHand);
                myPermanentDuration = new List <string>(previousMyCards.myPermanentDuration);
                return;
            }
            var(name, action, cards, destination, inParentheses) = Extractor.Extract(line);
            if (current_state.HasFlag(state.readyToReturn)) // 取り替え子対応のため、「戻した。」は次の行で処理する。
            {
                if (name == myName && action == "受け取った。" && cards[0] == "取り替え子")
                {
                    myDiscard.Add(cards[0]);
                    if (myDiscard.Contains(returnedCards[0]))
                    {
                        myDiscard.Remove(returnedCards[0]);
                    }
                    else
                    {
                        throw new Exception("戻すカードが捨て札にありません。");
                    }
                }
                else
                {
                    Remove(ref myHand, returnedCards, "戻すカードが手札にありません。");
                }
                current_state ^= state.readyToReturn;
            }
            if (name == myName)
            {
                switch (action)
                {
                case "購入した。":       // 購入するが獲得しない。獲得ログはこの後発生する。
                    current_state             = state.normal;
                    current_nonVolatileState |= nonVolatileState.duringBuy;
                    // 伝令官の購入時効果:2019年10月20日現在、この効果で山札に行くカード名が匿名の「カード」となる不具合があるため正常動作しない。
                    if (cards[0] == "伝令官")
                    {
                        current_state |= state.discard_to_deck;
                    }
                    if (cards[0] == "医者")
                    {
                        current_state |= state.look_to_draw;
                    }
                    if (cards[0] == "召喚")
                    {
                        current_state |= state.getting_in_hand;
                    }
                    if (cards[0] == "義賊")
                    {
                        current_state |= state.open_to_draw;
                    }
                    if (cards[0] == "保存")
                    {
                        current_nonVolatileState |= nonVolatileState.save;
                    }
                    if (cards[0] == "偵察隊")
                    {
                        current_state |= state.look_to_draw;
                    }
                    if (cards[0] == "寄付")
                    {
                        current_nonVolatileState |= nonVolatileState.donate;
                    }
                    if (cards[0] == "技術革新")
                    {
                        current_nonVolatileState |= nonVolatileState.innovation;
                    }
                    if (cards[0] == "回廊")
                    {
                        current_nonVolatileState |= nonVolatileState.piazza;
                    }
                    if (cards[0] == "大地への塩まき")
                    {
                        current_state |= state.no_trash;
                    }
                    if (cards[0] == "併合")
                    {
                        current_state            |= state.discard_to_deck;
                        current_nonVolatileState |= nonVolatileState.no_shuffle;
                    }
                    break;

                case "購入・獲得した。":
                    current_state             = state.normal;
                    current_nonVolatileState |= nonVolatileState.duringBuy;
                    if (cards[0] == "遊牧民の野営地")
                    {
                        myDeck.AddRange(cards);
                    }
                    else if (cards[0] == "悪人のアジト" || cards[0] == "ゴーストタウン" || cards[0] == "守護者")
                    {
                        myHand.AddRange(cards);
                    }
                    else
                    {
                        myDiscard.AddRange(cards);
                    }
                    if (cards[0] == "石")
                    {
                        current_state |= state.getting_on_deck;
                    }
                    if (cards[0] == "ヴィラ")
                    {
                        current_state |= state.discard_to_hand;
                    }
                    if (cards[0] == "宿屋")
                    {
                        current_state            |= state.discard_to_deck;
                        current_nonVolatileState |= nonVolatileState.no_shuffle;
                    }
                    gotCard = cards[0];
                    break;

                case "受け取った。":
                case "獲得した。":
                case "廃棄置き場から獲得した。":
                    if (current_state.HasFlag(state.getting_in_hand))
                    {
                        myHand.AddRange(cards);
                    }
                    else if (current_state.HasFlag(state.getting_on_deck) || cards[0] == "遊牧民の野営地" || destination == "山札の上")
                    {
                        myDeck.AddRange(cards);
                    }
                    else if (cards[0] == "悪人のアジト" || cards[0] == "ゴーストタウン" || cards[0] == "守護者" || cards[0] == "夜警")
                    {
                        myHand.AddRange(cards);
                    }
                    else if (current_state.HasFlag(state.turn_start) && current_state.HasFlag(state.cobbler))
                    {
                        myHand.AddRange(cards);
                    }
                    else
                    {
                        myDiscard.AddRange(cards);
                    }
                    if (cards[0] == "宿屋")
                    {
                        current_state            |= state.discard_to_deck;
                        current_nonVolatileState |= nonVolatileState.no_shuffle;
                    }
                    if (cards[0] == "石")
                    {
                        if (current_nonVolatileState.HasFlag(nonVolatileState.duringBuy))
                        {
                            current_state |= state.getting_on_deck;
                        }
                        else
                        {
                            current_state |= state.getting_in_hand;
                        }
                    }
                    if (cards[0] == "ヴィラ")
                    {
                        current_state |= state.discard_to_hand;
                    }
                    gotCard = cards[0];
                    break;

                case "シャッフルした。":
                    if (current_nonVolatileState.HasFlag(nonVolatileState.no_shuffle))
                    {
                        break;
                    }
                    numAtShuffle = myDeck.Count;
                    myDeck.AddRange(myDiscard);
                    myDiscard.Clear();
                    break;

                // 「〇を山札に混ぜシャッフルした。」は、直前に「山札をシャッフルした。」というログが現れるがこれは無視する。
                case "混ぜシャッフルした。":
                    if (destination != "山札")
                    {
                        throw new Exception("混ぜシャッフル失敗");
                    }
                    myDeck.AddRange(cards);
                    if (current_state.HasFlag(state.discard_to_deck))
                    {
                        Remove(ref myDiscard, cards, "混ぜるカードが捨て札にありません。");
                    }
                    else if (current_nonVolatileState.HasFlag(nonVolatileState.donate))
                    {
                        Remove(ref myDiscard, cards, "混ぜるカードが捨て札にありません。");
                        current_nonVolatileState ^= nonVolatileState.donate;
                    }
                    else
                    {
                        Remove(ref myHand, cards, "混ぜるカードが手札にありません。");
                    }
                    current_nonVolatileState ^= nonVolatileState.no_shuffle;
                    break;

                case "引いた。":
                case "指定し、的中した。":       // 願いの井戸、秘術師。的中しない場合のテキストは「Tを銅貨を指定したが、香辛料商人が公開された。」のように主語の後が「を」になっていて解析に失敗するが無視しても問題なし。
                    Remove(ref myDeck, cards, "引くカードが山札にありません。");
                    myHand.AddRange(cards);
                    if (current_nonVolatileState.HasFlag(nonVolatileState.donate))
                    {
                        myDeck.AddRange(myDiscard);
                        myDiscard.Clear();
                        current_nonVolatileState |= nonVolatileState.no_shuffle;
                    }
                    break;

                case "見た。":
                    if (current_state.HasFlag(state.look_to_draw))
                    {
                        Remove(ref myDeck, cards, "引くカードが山札にありません。");
                        myHand.AddRange(cards);
                    }
                    break;

                case "クリーンアップした。":
                    myDiscard.AddRange(myHand);
                    myHand.Clear();
                    current_state             = state.normal;
                    current_nonVolatileState ^= nonVolatileState.duringBuy;
                    break;

                case "捨て札にした。":
                    if (cards.Any() && (boons.Any(cards[0].Equals) || hexes.Any(cards[0].Equals)))
                    {
                        break;
                    }
                    if (current_state.HasFlag(state.deck_to_discard) || current_state.HasFlag(state.vassal))
                    {
                        myDiscard.AddRange(cards);
                        Remove(ref myDeck, cards, "捨てるカードが山札にありません。");
                        if (current_state == state.vassal)
                        {
                            vassalDiscard = cards[0];
                        }
                    }
                    else if (current_state.HasFlag(state.afterBuy) && cards.Contains("ワイン商"))
                    {
                        myDiscard.AddRange(cards);
                        Remove(ref myBar, cards, "捨てるカードが酒場マットにありません。");
                    }
                    else
                    {
                        myDiscard.AddRange(cards);
                        Remove(ref myHand, cards, "捨てるカードが手札にありません。");
                        if (current_state.HasFlag(state.secretCave) && cards.Count == 3)
                        {
                            myDuration.Add("秘密の洞窟");
                            myHand.Remove("秘密の洞窟");
                        }
                    }
                    break;

                case "廃棄した。":
                    if (current_state.HasFlag(state.no_trash))
                    {
                        break;
                    }
                    if (cards.Contains("城塞"))
                    {
                        current_state |= state.fortress;
                    }
                    if (current_state.HasFlag(state.deck_to_trash))
                    {
                        Remove(ref myDeck, cards, "廃棄するカードが山札にありません。");
                    }
                    else if (current_state.HasFlag(state.discard_to_trash))
                    {
                        Remove(ref myDiscard, cards, "廃棄するカードが捨て札にありません。");
                    }
                    else if (current_state.HasFlag(state.hermit))
                    {
                        if (myHand.Contains(cards[0]))
                        {
                            myHand.Remove(cards[0]);
                        }
                        else
                        {
                            Remove(ref myDiscard, cards, "廃棄するカードが捨て札にありません。");
                        }
                    }
                    else
                    {
                        Remove(ref myHand, cards, "廃棄するカードが手札にありません。");
                    }
                    if (cards.Contains("石"))
                    {
                        if (current_nonVolatileState.HasFlag(nonVolatileState.duringBuy))
                        {
                            current_state |= state.getting_on_deck;
                        }
                        else
                        {
                            current_state |= state.getting_in_hand;
                        }
                    }
                    break;

                case "終了した。":
                    if (cards[0] == "購入フェイズ")      // 購入フェイズを終了した。
                    {
                        current_state |= state.afterBuy;
                    }
                    break;

                case "呼び出した。":
                    myHand.AddRange(cards);
                    Remove(ref myBar, cards, "呼び出すカードが酒場にありません。");
                    if (cards.Contains("変容"))
                    {
                        current_state |= state.getting_in_hand;
                    }
                    if (cards.Contains("御料車"))
                    {
                        reusing = "御料車";
                    }
                    break;

                case "置いた。":
                    if (current_state.HasFlag(state.no_put))
                    {
                        break;
                    }
                    else if (cards.Any() && boons.Any(cards[0].Equals))
                    {
                        break;                                                      // 恵みの村対応
                    }
                    else if (current_state.HasFlag(state.discard_to_deck) && destination != "捨て札置き場")
                    {
                        if (cards.Any() && cards[0] == "カード")      // 玉璽対応
                        {
                            cards.Clear();
                            cards.Add(gotCard);
                        }
                        myDeck.AddRange(cards);
                        Remove(ref myDiscard, cards, "置くカードが捨て札にありません。");
                    }
                    else if (current_state.HasFlag(state.archive))
                    {
                        myArchive.AddRange(cards);
                        Remove(ref myDeck, cards, "置くカードが山札にありません。");
                    }
                    else if (current_state.HasFlag(state.crypt))
                    {
                        myCrypt.AddRange(cards);
                        Remove(ref myHand, cards, "置くカードが手札にありません。");
                    }
                    else if (current_state.HasFlag(state.hand_to_duration) || destination == "脇")
                    {
                        if (inParentheses == "貨物船")
                        {
                            myDuration.AddRange(cards);
                            Remove(ref myDiscard, cards, "置くカードが捨て札にありません。");
                            myDuration.Add("貨物船");
                            Remove(ref myHand, new List <string> {
                                "貨物船"
                            }, "貨物船が手札にありません。");                                                    // 貨物船は貨物を入れたときに持続場に入る
                        }
                        else if (inParentheses == "道具")
                        {
                            myDuration.AddRange(cards);
                            Remove(ref myHand, cards, "置くカードが手札にありません。");
                            myDuration.Add("道具");
                            Remove(ref myHand, new List <string> {
                                "道具"
                            }, "道具が手札にありません。");                                                   // 道具は1枚以上のカードを持続場に入れたときに持続場に入る
                        }
                        else if (current_state.HasFlag(state.research))
                        {
                            myDuration.AddRange(cards);
                            Remove(ref myDeck, cards, "置くカードが山札にありません。");
                            myDuration.Add("研究");
                            Remove(ref myHand, new List <string> {
                                "研究"
                            }, "研究が手札にありません。");                                                   // 研究は何かを持続場に入れたときにと一緒に持続場に入る
                        }
                        else if (inParentheses == "原住民の村")
                        {
                            myNativeVillage.AddRange(cards);
                            Remove(ref myDeck, cards, "置くカードが山札にありません。");
                        }
                        else if (current_nonVolatileState.HasFlag(nonVolatileState.innovation))
                        {
                            myHand.AddRange(cards);
                            Remove(ref myDiscard, cards, "置くカードが捨て札にありません。");
                        }
                        else
                        {
                            myDuration.AddRange(cards);
                            Remove(ref myHand, cards, "置くカードが手札にありません。");
                        }
                    }
                    else if (destination == "島マット")
                    {
                        myIsland.AddRange(cards);
                        Remove(ref myHand, cards, "置くカードが手札にありません。");
                    }
                    else if (destination == "酒場マット")
                    {
                        myBar.AddRange(cards);
                        Remove(ref myHand, cards, "置くカードが手札にありません。");
                    }
                    else if (destination == "山札の上")
                    {
                        myDeck.AddRange(cards);
                        Remove(ref myHand, cards, "置くカードが手札にありません。");
                    }
                    if (cards.Any() && cards[0] == "山札" && destination == "捨て札置き場")
                    {
                        myDiscard.AddRange(myDeck);
                        myDeck.Clear();
                    }
                    break;

                case "加えた。":
                    if (destination == "山札")
                    {
                        myDeck.AddRange(cards);
                        Remove(ref myHand, cards, "置くカードが手札にありません。");
                    }
                    else if (destination == "手札")
                    {
                        if (current_state.HasFlag(state.native_village))
                        {
                            myHand.AddRange(cards);
                            Remove(ref myNativeVillage, cards, "引くカードが原住民の村マットにありません。");
                        }
                        else if (current_state.HasFlag(state.discard_to_hand))
                        {
                            myHand.AddRange(cards);
                            Remove(ref myDiscard, cards, "引くカードが捨て札にありません。");
                        }
                        else if (current_state.HasFlag(state.turn_start))
                        {
                            if (myArchive.Any() && inParentheses == "資料庫")
                            {
                                myHand.AddRange(cards);
                                Remove(ref myArchive, cards, "引くカードが資料庫にありません。");
                                if (myArchive.FindIndex(m => m != "資料庫") == -1)
                                {
                                    myHand.AddRange(myArchive);
                                    myArchive.Clear();
                                }
                            }
                            if (myCrypt.Any() && inParentheses == "納骨堂")
                            {
                                myHand.AddRange(cards);
                                Remove(ref myCrypt, cards, "引くカードが納骨堂にありません。");
                                if (myCrypt.FindIndex(m => m != "納骨堂") == -1)
                                {
                                    myHand.AddRange(myCrypt);
                                    myCrypt.Clear();
                                }
                            }
                            break;        // ターン開始時に持続カードと同時に手札に加えているので無視する
                        }
                        else if (current_state.HasFlag(state.fortress))
                        {
                            myHand.AddRange(cards);                                                 // 城塞を手札に加える
                        }
                        else if (current_nonVolatileState.HasFlag(nonVolatileState.save))
                        {
                            myHand.AddRange(cards);
                            Remove(ref myDuration, cards, "保存したカードがありません。");
                            current_nonVolatileState ^= nonVolatileState.save;
                        }
                        else if (inParentheses == "ターン終了時" && cards.Contains("忠犬"))
                        {
                            myHand.AddRange(cards);
                            Remove(ref myDuration, cards, "忠犬がありません。");
                        }
                        else
                        {
                            myHand.AddRange(cards);
                            Remove(ref myDeck, cards, "引くカードが山札にありません。");
                        }
                    }
                    break;

                case "渡した。":
                    Remove(ref myHand, cards, "渡すカードが手札にありません。");
                    break;

                case "開始した。":
                    if (cards[0] == "ターン")        // ターンを開始した。
                    {
                        current_state |= state.turn_start;
                        if (myDuration.Contains("カブラー"))
                        {
                            current_state |= state.cobbler;
                        }
                        myHand.AddRange(myDuration);
                        myDuration.Clear();
                        if (current_nonVolatileState.HasFlag(nonVolatileState.piazza))
                        {
                            current_state |= state.open_to_draw;
                        }
                    }
                    break;

                case "リアクションした。":
                    if (cards[0] == "玉璽")
                    {
                        current_state |= state.discard_to_deck;
                    }
                    if (cards[0] == "望楼")
                    {
                        current_state |= state.discard_to_deck | state.discard_to_trash;
                    }
                    if (cards[0] == "馬商人")
                    {
                        current_state |= state.hand_to_duration;
                    }
                    if (cards[0] == "愚者の黄金")
                    {
                        current_state |= state.getting_on_deck;
                    }
                    if (cards[0] == "移動遊園地")
                    {
                        current_state |= state.discard_to_deck;
                    }
                    if (cards[0] == "忠犬")
                    {
                        myHand.AddRange(cards);
                        Remove(ref myDiscard, cards, "捨て札に忠犬がありません");
                    }
                    if (cards[0] == "追跡者" && !current_state.HasFlag(state.getting_in_hand))
                    {
                        current_state |= state.discard_to_deck;
                    }
                    break;

                case "公開した。":
                    if (current_state.HasFlag(state.open_to_draw))
                    {
                        if (current_state.HasFlag(state.famine))
                        {
                            current_nonVolatileState |= nonVolatileState.no_shuffle;
                        }
                        myHand.AddRange(cards);
                        Remove(ref myDeck, cards, "引くカードが山札にありません。");
                    }
                    else if (current_state.HasFlag(state.herald) && CardList.actionCards.Any(cards[0].Equals))
                    {
                        myHand.AddRange(cards);
                        Remove(ref myDeck, cards, "引くカードが山札にありません。");
                    }
                    break;

                case "戻した。":
                    if (states.Any(cards[0].Equals))
                    {
                        break;
                    }
                    if (cards[0].Contains("トークン"))
                    {
                        break;
                    }
                    if (cards.Contains("陣地") && destination == "陣地の山")
                    {
                        Remove(ref myDuration, cards, "戻すカードが脇にありません。");
                    }
                    else if (current_state.HasFlag(state.no_return) && destination == "山札")
                    {
                        break;
                    }
                    else
                    {
                        current_state |= state.readyToReturn;
                        returnedCards  = cards;
                    }
                    break;

                case "受けた。":
                    if (cards[0] == "月の恵み")
                    {
                        current_state |= state.discard_to_deck;
                    }
                    if (cards[0] == "太陽の恵み")
                    {
                        current_state |= state.look_to_draw;
                    }
                    if (cards[0] == "凶兆")
                    {
                        current_state |= state.discard_to_deck;
                    }
                    if (cards[0] == "貪欲")
                    {
                        current_state |= state.getting_on_deck;
                    }
                    if (cards[0] == "蝗害")
                    {
                        current_state |= state.deck_to_trash;
                    }
                    if (cards[0] == "疫病")
                    {
                        current_state |= state.getting_in_hand;
                    }
                    if (cards[0] == "戦争")
                    {
                        current_state |= state.open_to_draw;
                    }
                    if (cards[0] == "飢饉")
                    {
                        current_state |= state.open_to_draw;
                        current_state |= state.famine;
                    }
                    break;
                }
            }
            else if (name == opponentName)
            {
                if (action == "渡した。")
                {
                    myHand.AddRange(cards);
                }
                // 相手の隊商の護衛によるリアクションのカード使用でstateがリセットされないようにする
                if (action == "リアクションした。" && cards[0] == "隊商の護衛")
                {
                    current_state |= state.no_use;
                }
                // 相手の聖なる木立ちは相手が祝福受けるログでこちらが祝福効果を受ける
                if (current_state.HasFlag(state.sacredGrove) && action == "受けた。" && cards[0] == "月の恵み")
                {
                    current_state |= state.discard_to_deck;
                }
                if (current_state.HasFlag(state.sacredGrove) && action == "受けた。" && cards[0] == "太陽の恵み")
                {
                    current_state |= state.look_to_draw;
                }
            }
            if (action == "使用した。")
            {
                if (current_state.HasFlag(state.no_use))
                {
                    current_state ^= state.no_use;
                }
                else
                {
                    UseCard(cards[0], name == myName, false);
                }
            }
            if (action == "再使用した。" || action == "再々使用した。")
            {
                UseCard(cards[0], name == myName, true);
            }
        }