static void ParseLog(string FileName, List<Argument> ArgList) { string Dir = LogDir; string[] MjlogDir = null; string Mjlog = null; bool Forced = false; bool Rewrited; foreach (Argument A in ArgList) { switch (A.Name) { case "dir": Dir = A.Value + "/" + LogDir; if (!Directory.Exists(Dir)) Directory.CreateDirectory(Dir); break; case "force": Forced = true; break; case "mjlog": { Mjlog = A.Value; if(Directory.Exists(Mjlog)) MjlogDir = Directory.GetFiles(Mjlog, "*.mjlog"); } break; } } Console.WriteLine("Parsing games from log: " + FileName); if (!File.Exists(FileName)) { Console.Write("Error: Log file " + FileName + " not found!"); return; } Tenhou.LogParser Log = new Tenhou.LogParser(FileName); List<string> Hashes = Log.HashList.Hashes; for (int i = 0; i < Hashes.Count; i++) { string Hash = Hashes[i]; string ReplayFileName = Tenhou.LogParser.GetFileName(Hash, Dir); Console.Title = String.Format("Parsing {0:d}/{1:d}: {2:s}", i + 1, Hashes.Count, Hash); Console.Write(Hash); Rewrited = false; if (Mahjong.Replay.IsReplayExist(Hash)) { if (!Forced) { Console.WriteLine(" - exists, skip!"); continue; } else { Rewrited = true; } } string MjLogFile = GetMjlogFilename(MjlogDir, Hash); Tenhou.ReplayDecoder R = new Tenhou.ReplayDecoder(); if (MjLogFile != null) { R.OpenGZ(MjLogFile, Hash); } else { if (!File.Exists(ReplayFileName)) { Console.WriteLine(" - file not found!"); continue; } if (new FileInfo(ReplayFileName).Length == 0) { File.Delete(ReplayFileName); Console.WriteLine(" - zero size, removed!"); continue; } R.OpenPlainText(ReplayFileName, Hash); } // replay (calc shanten, waitings and other) and save result Mahjong.Replay Replay = R.R; Replay.ReplayGame(); Replay.Save(); Console.WriteLine(Rewrited ? " - replaced, ok!" : " - ok!"); } }
static List<Search.Result> Find(string FileName, List<Argument> ArgList, List<Search.Result> Results) { Search.GameFinder Finder; if ((Results != null) && (FileName.CompareTo("") == 0)) { Console.WriteLine("Finding games from previous search result."); Finder = new Search.GameFinder(Results); } else { if (!File.Exists(FileName)) { Console.WriteLine("Error: Log file " + FileName + " not found!"); return null; } Console.WriteLine("Finding games from log: " + FileName + "."); Tenhou.LogParser Log = new Tenhou.LogParser(FileName); Finder = new Search.GameFinder(Log.HashList); } // Parse options foreach (Argument A in ArgList) { switch (A.Name) { case "reset": Finder.ResetFlags(); break; } } for (int i = 0; i < ArgList.Count; i++) { string Param = ArgList[i].Name; string Value = ArgList[i].Value; int TempValue; switch (Param) { case "shanten": TempValue = ParseIntArg(Value, 0, 6, "shanten"); if (TempValue != -1) { Finder.ShantenMax = TempValue; Finder.ShantenMin = TempValue; } Console.WriteLine(String.Format("Filter: only hands, which started with shanten {0:d};", TempValue)); break; case "shantenmin": TempValue = ParseIntArg(Value, 0, 6, "shantenmin"); if (TempValue != -1) Finder.ShantenMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which started with shanten greater (or equal) than {0:d};", TempValue)); break; case "shantenmax": TempValue = ParseIntArg(Value, 0, 6, "shantenmax"); if (TempValue != -1) Finder.ShantenMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which started with shanten less (or equal) than {0:d};", TempValue)); break; case "ratingmin": TempValue = ParseIntArg(Value, 1000, 3000, "ratingmin"); if (TempValue != -1) Finder.RatingMin = TempValue; Console.WriteLine(String.Format("Filter: only players, who has rating greater (or equal) than {0:d};", TempValue)); break; case "ratingmax": TempValue = ParseIntArg(Value, 1000, 3000, "ratingmax"); if (TempValue != -1) Finder.RatingMax = TempValue; Console.WriteLine(String.Format("Filter: only players, who has rating less (or equal) than {0:d};", TempValue)); break; case "paymentmin": TempValue = ParseIntArg(Value, -1000000, 1000000, "paymentmin"); if (TempValue != -1) Finder.PaymentMin = TempValue; Console.WriteLine(String.Format("Filter: only players, who pay(-) or receive(+) greater (or equal) than {0:d} points;", TempValue)); break; case "paymentmax": TempValue = ParseIntArg(Value, -1000000, 1000000, "paymentmax"); if (TempValue != -1) Finder.PaymentMax = TempValue; Console.WriteLine(String.Format("Filter: only players, who pay(-) or receive(+) less (or equal) than {0:d} points;", TempValue)); break; case "waitmin": TempValue = ParseIntArg(Value, 1, 13, "waitmin"); if (TempValue != -1) Finder.WaitingCountMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has {0:d}-sided wait and greater;", TempValue)); break; case "waitmax": TempValue = ParseIntArg(Value, 1, 13, "waitmax"); if (TempValue != -1) Finder.WaitingCountMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has {0:d}-sided wait and less;", TempValue)); break; case "hanmin": TempValue = ParseIntArg(Value, 0, 13, "hanmin"); if (TempValue != -1) Finder.HanMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has han count greater (or equal) than {0:d};", TempValue)); break; case "hanmax": TempValue = ParseIntArg(Value, 0, 13, "hanmax"); if (TempValue != -1) Finder.HanMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has han count less (or equal) than {0:d};", TempValue)); break; case "fumin": TempValue = ParseIntArg(Value, 0, 120, "fumin"); if (TempValue != -1) Finder.FuMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has fu count greater (or equal) than {0:d};", TempValue)); break; case "fumax": TempValue = ParseIntArg(Value, 0, 120, "fumax"); if (TempValue != -1) Finder.FuMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has fu count less (or equal) than {0:d};", TempValue)); break; case "dangermin": TempValue = ParseIntArg(Value, 0, 14, "dangermin"); if (TempValue != -1) Finder.DangerMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has danger tiles count greater (or equal) than {0:d};", TempValue)); break; case "dangermax": TempValue = ParseIntArg(Value, 0, 14, "dangermax"); if (TempValue != -1) Finder.DangerMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has has danger tiles count less (or equal) than {0:d};", TempValue)); break; case "doramin": TempValue = ParseIntArg(Value, 0, 35, "doramin"); if (TempValue != -1) Finder.DoraMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has dora count greater (or equal) than {0:d};", TempValue)); break; case "doramax": TempValue = ParseIntArg(Value, 0, 35, "doramax"); if (TempValue != -1) Finder.DoraMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has dora count less (or equal) than {0:d};", TempValue)); break; case "deadoutsmin": TempValue = ParseIntArg(Value, 0, 14, "deadoutsmin"); if (TempValue != -1) Finder.DeadOutsMin = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has count of outs in dead wall greater (or equal) than {0:d};", TempValue)); break; case "deadoutsmax": TempValue = ParseIntArg(Value, 0, 14, "deadoutsmax"); if (TempValue != -1) Finder.DeadOutsMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which has count of outs in dead wall less (or equal) than {0:d};", TempValue)); break; case "rankmin": TempValue = ParseIntArg(Value, 0, 20, "rankmin"); if (TempValue != -1) Finder.RankMin = TempValue; Console.WriteLine(String.Format("Filter: only players, who has rank greater or equal that '{0:d}';", Tenhou.Rank.GetName(TempValue))); break; case "rankmax": TempValue = ParseIntArg(Value, 0, 20, "rankmax"); if (TempValue != -1) Finder.RankMax = TempValue; Console.WriteLine(String.Format("Filter: only players, who has rank less or equal that '{0:d}';", Tenhou.Rank.GetName(TempValue))); break; case "furiten": Finder.Furiten = ParseBoolArg(Value, "furiten"); Console.WriteLine(String.Format("Filter: only hands, which has {0:s} furiten;", (Finder.Furiten == 0) ? "no" : "")); break; case "riichi": Finder.Riichi = ParseBoolArg(Value, "riichi"); Console.WriteLine(String.Format("Filter: only hands {0:s} riichi;", (Finder.Riichi == 0) ? "without" : "with")); break; case "firstriichi": Finder.FirstRiichi = ParseBoolArg(Value, "firstriichi"); Console.WriteLine(String.Format("Filter: only players who declared riichi {0:s}first;", (Finder.FirstRiichi == 0) ? "not " : "")); break; case "ron": Finder.Ron = ParseBoolArg(Value, "ron"); Console.WriteLine(String.Format("Filter: only rounds, which ended {0:s} ron agari;", (Finder.Ron == 0) ? "without" : "with")); break; case "rononriichi": Finder.RonOnRiichi = ParseBoolArg(Value, "rononriichi"); Console.WriteLine(String.Format("Filter: only rounds, which ended {0:s} ron on riichi agari;", (Finder.RonOnRiichi == 0) ? "without" : "with")); break; case "dorawait": Finder.DoraWait = ParseBoolArg(Value, "dorawait"); Console.WriteLine(String.Format("Filter: only hands, which has {0:s}dora in waiting;", (Finder.DoraWait == 0) ? "not " : "")); break; case "tsumo": Finder.Tsumo = ParseBoolArg(Value, "tsumo"); Console.WriteLine(String.Format("Filter: only rounds, which ended {0:s} tsumo agari;", (Finder.Tsumo == 0) ? "without" : "with")); break; case "oneside": Finder.Oneside = ParseBoolArg(Value, "oneside"); Console.WriteLine(String.Format("Filter: only players who was{0:s} won all rounds (except draws);", (Finder.Oneside == 0) ? " not" : "")); break; case "riichicount": TempValue = ParseIntArg(Value, 0, 4, "riichicount"); if (TempValue != -1) Finder.RiichiCount = TempValue; Console.WriteLine(String.Format("Filter: only rounds with {0:d} declared riichi;", Finder.RiichiCount)); break; case "nakicount": TempValue = ParseIntArg(Value, 0, 12, "nakicount"); if (TempValue != -1) Finder.NakiCount = TempValue; Console.WriteLine(String.Format("Filter: only hands with {0:d} declared nakies;", Finder.NakiCount)); break; case "openedsets": TempValue = ParseIntArg(Value, 0, 4, "openedsets"); if (TempValue != -1) Finder.OpenedSets = TempValue; Console.WriteLine(String.Format("Filter: only hands with {0:d} opened sets;", Finder.OpenedSets)); break; case "renchanstick": TempValue = ParseIntArg(Value, 0, 15, "renchanstick"); if (TempValue != -1) Finder.RenchanStick = TempValue; Console.WriteLine(String.Format("Filter: only games with {0:d} renchan sticks;", Tenhou.Wind.GetText(TempValue))); break; case "lobby": TempValue = ParseIntArg(Value, 0, 9999, "lobby"); if (TempValue != -1) Finder.Lobby = TempValue; Console.WriteLine(String.Format("Filter: only games from {0:d} lobby;", TempValue)); break; case "aka": TempValue = ParseIntArg(Value, 0, 1, "aka"); if (TempValue != -1) Finder.Aka = TempValue; Console.WriteLine(String.Format("Filter: only games with aka-dora {0:s};", (TempValue == 0) ? "nashi" : "ari")); break; case "kuitan": TempValue = ParseIntArg(Value, 0, 1, "kuitan"); if (TempValue != -1) Finder.Kuitan = TempValue; Console.WriteLine(String.Format("Filter: only games with kuitan {0:s};", (TempValue == 0) ? "nashi" : "ari")); break; case "south": TempValue = ParseIntArg(Value, 0, 1, "south"); if (TempValue != -1) Finder.Kuitan = TempValue; Console.WriteLine(String.Format("Filter: only {0:s} games;", (TempValue == 0) ? "tonpuusen" : "hanchan")); break; case "speedy": TempValue = ParseIntArg(Value, 0, 1, "speedy"); if (TempValue != -1) Finder.Saku = TempValue; Console.WriteLine(String.Format("Filter: only {0:s} speed games;", (TempValue == 0) ? "normal" : "high")); break; case "dan": Finder.High = 1; Console.WriteLine(String.Format("Filter: only games from 1+dan lobby;")); break; case "upperdan": Finder.Toku = 1; Console.WriteLine(String.Format("Filter: only games from upper dan lobby;")); break; case "place": TempValue = ParseIntArg(Value, 1, 4, "place"); if (TempValue != -1) Finder.Place = TempValue; Console.WriteLine(String.Format("Filter: only players, who took {0:d} place;", TempValue)); break; case "steps": TempValue = ParseIntArg(Value, 0, 60, "steps"); if (TempValue != -1) Finder.StepsMax = TempValue; Console.WriteLine(String.Format("Filter: only hands, which exists less (or equal) than '{0:d}' steps;", TempValue)); break; case "yaku": Finder.YakuList = DecompositeIntList(Value); if(Finder.YakuList != null) { for (int j = 0; j < Finder.YakuList.Length; j++) { Console.WriteLine(String.Format("Filter: only hands with yaku '{0:s}';", Mahjong.YakuName.GetYakuName("en", Finder.YakuList[j]))); } } break; case "anyyaku": string[] TempYakuList = DecompositeStringList(Value); Finder.AnyYakuList = Tenhou.YakuNameParser.Parse(TempYakuList); if (Finder.AnyYakuList != null) { for (int j = 0; j < Finder.AnyYakuList.Length; j++) { Console.WriteLine(String.Format("Filter: only hands with yaku '{0:s}';", Mahjong.YakuName.GetYakuName("en", Finder.AnyYakuList[j]))); } } break; case "wait": Finder.Waitings = ParseTilesList(Value); if (Finder.Waitings != null) { Console.WriteLine(String.Format("Filter: only hands, which has at least one waiting from list: '{0:s}';", GetTilesListString(Finder.Waitings))); } break; case "nickname": Finder.NickName = Value; Console.WriteLine(String.Format("Filter: only player with nickname '{0:s}';", Value)); break; case "hash": Finder.Hash = Value; Console.WriteLine(String.Format("Filter: only rounds from game with hash '{0:s}';", Value)); break; case "dealer": Finder.Dealer = ParseBoolArg(Value, "dealer"); Console.WriteLine(String.Format("Filter: only {0:s} dealer hands;", (Finder.Dealer == 0) ? "not" : "")); break; case "loser": Finder.Loser = ParseBoolArg(Value, "loser"); Console.WriteLine(String.Format("Filter: only players, who {0:s} dealt into ron;", (Finder.Loser == 0) ? "not" : "")); break; case "winner": Finder.Winner = ParseBoolArg(Value, "winner"); Console.WriteLine(String.Format("Filter: only players, who {0:s} completed hand;", (Finder.Winner == 0) ? "not" : "")); break; case "tempai": Finder.Tempai = ParseBoolArg(Value, "tempai"); Console.WriteLine(String.Format("Filter: only hands, which {0:s} had tempai;", (Finder.Tempai == 0) ? "not" : "")); break; case "chiitoi": Finder.Chiitoi = ParseBoolArg(Value, "chiitoi"); Console.WriteLine(String.Format("Filter: only hands, which {0:s} had tempai on chiitoi;", (Finder.Chiitoi == 0) ? "not" : "")); break; case "omotesuji": Finder.OmoteSujiWait = ParseBoolArg(Value, "omotesuji"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s}omote-suji wait to discarded tile;", (Finder.OmoteSujiWait == 0) ? "not " : "")); break; case "suji": Finder.OmoteSujiWait = ParseBoolArg(Value, "suji"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s}(omote)suji wait to discarded tile;", (Finder.OmoteSujiWait == 0) ? "not " : "")); break; case "senkisuji": Finder.SenkiSujiWait = ParseBoolArg(Value, "senkisuji"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s}senki-suji wait to discarded tile;", (Finder.SenkiSujiWait == 0) ? "not " : "")); break; case "urasuji": Finder.UraSujiWait = ParseBoolArg(Value, "urasuji"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s}ura-suji wait to discarded tile;", (Finder.UraSujiWait == 0) ? "not " : "")); break; case "matagisuji": Finder.MatagiSujiWait = ParseBoolArg(Value, "matagisuji"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s}matagi-suji wait to discarded tile;", (Finder.MatagiSujiWait == 0) ? "not " : "")); break; case "karatennoten": Finder.KaratenNoten = ParseBoolArg(Value, "karatennoten"); Console.WriteLine(String.Format("Filter: only hands, which had {0:s} only waiting, all tiles of that type already in hand;", (Finder.KaratenNoten == 0) ? "not" : "")); break; case "players": TempValue = ParseIntArg(Value, 3, 4, "players"); if (TempValue != -1) Finder.PlayerCount = TempValue; Console.WriteLine(String.Format("Filter: only games with {0:d} players;", TempValue)); break; case "roundwind": TempValue = ParseIntArg(Value, 0, 3, "roundwind"); if (TempValue != -1) Finder.RoundWind = TempValue; Console.WriteLine(String.Format("Filter: only games with round wind {0:s};", Tenhou.Wind.GetText(TempValue))); break; case "playerwind": TempValue = ParseIntArg(Value, 0, 3, "playerwind"); if (TempValue != -1) Finder.PlayerWind = TempValue; Console.WriteLine(String.Format("Filter: only hands with player wind {0:s};", Tenhou.Wind.GetText(TempValue))); break; case "round": TempValue = ParseIntArg(Value, 0, 15, "round"); if (TempValue != -1) Finder.RoundIndex = TempValue; Console.WriteLine(String.Format("Filter: only games with round index {0:s};", Tenhou.Wind.GetText(TempValue))); break; case "draw": { string Comment; Finder.Draw = true; switch (Value) { case "yao9": Finder.DrawReason = 1; Comment = "only games which ended in a draw because of kyushu kyuhai"; break; case "reach4": Finder.DrawReason = 2; Comment = "only games which ended in a draw because of 4 reach"; break; case "ron3": Finder.DrawReason = 3; Comment = "only games which ended in a draw because of triple ron"; break; case "kan4": Finder.DrawReason = 4; Comment = "only games which ended in a draw because of 4 kans"; break; case "kaze4": Finder.DrawReason = 5; Comment = "only games which ended in a draw because of 4 winds"; break; case "nm": Finder.DrawReason = 6; Comment = "only games which ended in a draw with nagashi mangan"; break; case "normal": Finder.DrawReason = 0; Comment = "only games which ended in a draw (no agari)"; break; default: Finder.DrawReason = -1; Comment = "only games ended in a draw with any reason"; break; } Console.WriteLine(String.Format("Filter: {0:s} ;", Comment)); } break; case "form": Finder.Form = ParseForm(Value); Console.WriteLine(String.Format("Filter: only hands with form '{0:s}';", Value)); break; case "naki": int N = ParseIntArg(Value, 1, 6, "naki"); if ((N >= 1) && (N <= 6)) { Finder.NakiType = N; Console.WriteLine(String.Format("Filter: only hands with naki {0:d}: '{1:s}';", N, ((NakiType)N).ToString())); } break; case "drowntiles": Finder.DrownTiles = ParseTilesList(Value); if(Finder.DrownTiles != null) { Console.WriteLine(String.Format("Filter: only hands with drown tiles '{0:s}';", GetTilesListString(Finder.DrownTiles))); } break; case "sex": { string Comment = ""; bool Skip = false; switch (Value) { case "f": Finder.Sex = Mahjong.Sex.Female; Comment = "only female players"; break; case "m": Finder.Sex = Mahjong.Sex.Male; Comment = "only male players"; break; case "c": Finder.Sex = Mahjong.Sex.Computer; Comment = "only bot players (computer)"; break; default: Console.WriteLine("Invalid 'sex' query - skipped, should be 'f', 'm' or 'c';"); Skip = true; break; } if(!Skip) Console.WriteLine(String.Format("Filter: {0:s} ;", Comment)); } break; case "color": { string Comment = ""; switch (Value) { case "m": Finder.Colored = 1; Finder.ColoredSuit = 0; Comment = "only man-colored hands"; break; case "p": Finder.Colored = 1; Finder.ColoredSuit = 1; Comment = "only pin-colored hands"; break; case "s": Finder.Colored = 1; Finder.ColoredSuit = 2; Comment = "only sou-colored hands"; break; case "M": Finder.Colored = 1; Finder.ColoredSuit = 0; Finder.ColoredForced = 1; Comment = "only man-colored hands (without other suits)"; break; case "P": Finder.Colored = 1; Finder.ColoredSuit = 1; Finder.ColoredForced = 1; Comment = "only pin-colored hands (without other suits)"; break; case "S": Finder.Colored = 1; Finder.ColoredSuit = 2; Finder.ColoredForced = 1; Comment = "only sou-colored hands (without other suits)"; break; case "0": Finder.Colored = 0; Comment = "only not colored hands"; break; default: Finder.Colored = 1; Comment = "only colored hands"; break; } Console.WriteLine(String.Format("Filter: {0:s} ;", Comment)); } break; case "last": TempValue = ParseIntArg(Value, 0, 10000000, "last"); if (TempValue != -1) Finder.Last = TempValue; Console.WriteLine(String.Format("Filter: only in {0:d} last games;", TempValue)); break; case "limit": TempValue = ParseIntArg(Value, 0, 10000000, "limit"); if (TempValue != -1) Finder.Limit = TempValue; Console.WriteLine(String.Format("Filter: return maximum {0:d} games;", TempValue)); break; } } return Finder.Find(); }
static void DownloadLog(string FileName, List<Argument> ArgList) { string Dir = LogDir; string Mjlog = null; string[] MjlogDir = null; foreach (Argument A in ArgList) { switch (A.Name) { case "dir": Dir = A.Value + "/" + LogDir; if (!Directory.Exists(Dir)) Directory.CreateDirectory(Dir); break; case "mjlog": { Mjlog = A.Value; if (Directory.Exists(Mjlog)) MjlogDir = Directory.GetFiles(Mjlog, "*.mjlog"); } break; } } Console.WriteLine("Downloading games from log: " + FileName); if (!File.Exists(FileName)) { Console.Write("Error: Log file " + FileName + " not found!"); return; } Tenhou.LogParser Log = new Tenhou.LogParser(FileName); if (Mjlog != null) Log.DownloadAllFromMjlog(Dir, MjlogDir); else Log.DownloadAll(Dir); }