はじめに
こんにちは。いわゆるパラドゲーというものをご存知でしょうか。今回はその中でもVictoria 2の内部処理を想像して参考にしながら、自分のシステムを作り上げてみました。しかし、一番最初のテストの段階で既に処理が重すぎます。これの改善方法に知恵をお貸しいただけますと幸いです。
システムを簡潔に説明
Victoria 2をご存知でしたら想像に容易いのですが、知らない前提で説明いたします。
まず、プレイヤーが操作するものは国家です。国家には人口がおり、様々な職業や人種に分かれています。その人口が株式投資したり、会社を興したり、経済活動をすることで自国経済が動きます。プレイヤーが国家として市場に介入することはあれど、直接手を下すということはありません。そんなものを表現したいと思っています。
コード
C#
1using System; 2using System.IO; 3using System.Collections.Generic; 4using Newtonsoft.Json; 5 6namespace ConsoleApp2 7{ 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var sw = new System.Diagnostics.Stopwatch(); 13 sw.Start(); 14 int chanceOfPopExcution = 1; 15 int chanceOfCompanyExcution = 1; 16 var pop = new Pop(chanceOfPopExcution, chanceOfCompanyExcution); 17 var company = new Company(); 18 Console.WriteLine(pop.popItems.Count); 19 Console.WriteLine(company.companyItems.Count); 20 pop.action(); 21 sw.Stop(); 22 Console.WriteLine("■処理Aにかかった時間"); 23 TimeSpan ts = sw.Elapsed; 24 Console.WriteLine($" {ts}"); 25 Console.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒"); 26 Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒"); 27 } 28 } 29 30 class Goods 31 { 32 public double life = 0.2; 33 public double everyday = 0.4; 34 public double luxury = 1.1; 35 } 36 37 public class Company 38 { 39 public List<CompanyItem> companyItems; 40 41 public Company() 42 { 43 using (var sr = new StreamReader(@"company.json", System.Text.Encoding.UTF8)) 44 { 45 var jsonData = sr.ReadToEnd(); 46 companyItems = JsonConvert.DeserializeObject<List<CompanyItem>>(jsonData); 47 } 48 } 49 public class CompanyItem 50 { 51 public int code { get; set; } 52 public double capital { get; set; } 53 public double asset { get; set; } 54 public double revenue { get; set; } 55 public double issued { get; set; } 56 public double apprprt_price { get; set; } 57 public double share_price { get; set; } 58 } 59 } 60 61 public class Pop 62 { 63 public List<PopItem> popItems; 64 public int chanceOfPopExcution; 65 public int chanceOfCompanyExcution; 66 public Pop(int _chanceOfPopExcution, int _chanceOfCompanyExcution) 67 { 68 chanceOfPopExcution = _chanceOfPopExcution; 69 chanceOfCompanyExcution = _chanceOfCompanyExcution; 70 using (var sr = new StreamReader(@"pop.json", System.Text.Encoding.UTF8)) 71 { 72 var jsonData = sr.ReadToEnd(); 73 popItems = JsonConvert.DeserializeObject<List<PopItem>>(jsonData); 74 } 75 } 76 77 public void action() 78 { 79 for (int i = 0; i < popItems.Count; i++) 80 { 81 var ob = new ChanceOfExcution(); 82 if (ob.calc(chanceOfPopExcution)) 83 { 84 Dictionary<string,double> consumption = consume(popItems[i]); 85 popItems[i].money = consumption["money"]; 86 if (consumption["fulfilled"] == 3) 87 { 88 invest(popItems[i]); 89 } 90 } 91 } 92 return; 93 } 94 95 public List<Dictionary<string, double>> invest(PopItem popItem) 96 { 97 var returnList = new List<Dictionary<string, double>>(); 98 var ob = new ChanceOfExcution(); 99 if (ob.calc(chanceOfCompanyExcution)) 100 { 101 var companyItems = new Company().companyItems; 102 103 double money = popItem.size * popItem.money; 104 105 for (int i = 0; i < companyItems.Count; i++) 106 { 107 108 var companyItem = companyItems[i]; 109 if (popItem.size * popItem.money * 0.8 > money) break; 110 if (companyItem.share_price == 0 || companyItem.apprprt_price / companyItem.share_price >= 1) 111 { 112 var obj = new Random(); 113 double rand = obj.Next(9, 12) / 10; 114 double investingPrice; 115 if (companyItem.share_price == 0) 116 { 117 investingPrice = 0.5 * Math.Round(rand, 1, MidpointRounding.AwayFromZero); 118 } 119 else 120 { 121 investingPrice = 0.5 * Math.Round(companyItem.share_price * rand, 1, MidpointRounding.AwayFromZero); 122 } 123 if (popItem.money / 10 > investingPrice) 124 { 125 double rand2 = obj.Next(5, 15) / 10; 126 double investingVolume = Math.Floor(money / 100 * rand2 / investingPrice); 127 var dic = new Dictionary<string, double>() { { "pop_code", popItem.code }, { "company_code", companyItem.code }, { "price", investingPrice }, { "volume", investingVolume } }; 128 returnList.Add(dic); 129 } 130 } 131 } 132 } 133 return returnList; 134 } 135 136 public Dictionary<string, double> consume(PopItem pop_item) 137 { 138 var goods = new Goods(); 139 double money = pop_item.money; 140 double multiplyer = (100 / chanceOfPopExcution); 141 if (money - goods.life * multiplyer < 0) { 142 return new Dictionary<string, double>(){ {"fulfilled",0},{"money",money}}; 143 } 144 else if(money - (goods.life + goods.everyday) * multiplyer < 0) 145 { 146 return new Dictionary<string, double>() { { "fulfilled", 1 }, { "money", money - goods.life } }; 147 } 148 else if(money - (goods.life + goods.everyday + goods.luxury) * multiplyer < 0) 149 { 150 return new Dictionary<string, double>() { { "fulfilled", 2 }, { "money", money - (goods.life + goods.everyday) * multiplyer } }; 151 } 152 else 153 { 154 return new Dictionary<string, double>() { { "fulfilled", 3 }, { "money", money - (goods.life + goods.everyday + goods.luxury) * multiplyer } }; 155 } 156 } 157 158 public class PopItem 159 { 160 public int code { get; set; } 161 public int size { get; set; } 162 public double money { get; set; } 163 public List<Dictionary<string,double>> share { get; set; } 164 } 165 } 166 167 public class ChanceOfExcution 168 { 169 public bool calc(int chance) 170 { 171 var ob = new Random(); 172 int rand = ob.Next(1, 10000); 173 int num = chance * 100; 174 return num >= rand; 175 } 176 } 177} 178
さいごに
このテストはpythonで記述しましたが、最終的にはunityで作りたいのでC#でやり直します。ですが、本質的に動作が重すぎる点は言語のせいではないと思いますので、この時点で何かアドバイスをいただきたいと思い、質問させていただきました。
追記
pop.jsonは100,000件のデータを、company.jsonは500件のデータを持っています。これら合計して50,000,000件計算させるのは心が痛むので、確率でPopとCompanyが動くようにしました。どちらも1%の確率で処理させ、合計処理を5000件に抑えたのですが、それでも処理に1秒くらいかかってしまいます。
本番環境では、これよりもっと複雑な計算も行いますし、PopもCompanyも一桁多いくらいな想定です。今のままでは不可能ですが、前述のゲーム、Victoria 2ではこの状況に非常によく似た問題の対処が行われています。全く想像つきません。一緒に考えてもらえませんか?
あなたの回答
tips
プレビュー