teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

C#は扱ったことがないので躊躇っていましたが、ちょっとやってみました。それと、扱っているデータについてお話しし忘れていましたので追記しました。

2021/08/26 10:59

投稿

holy_cow
holy_cow

スコア0

title CHANGED
File without changes
body CHANGED
@@ -6,114 +6,190 @@
6
6
  まず、プレイヤーが操作するものは国家です。国家には人口がおり、様々な職業や人種に分かれています。その人口が株式投資したり、会社を興したり、経済活動をすることで自国経済が動きます。プレイヤーが国家として市場に介入することはあれど、直接手を下すということはありません。そんなものを表現したいと思っています。
7
7
 
8
8
  ### コード
9
+ ```C#
10
+ using System;
11
+ using System.IO;
12
+ using System.Collections.Generic;
13
+ using Newtonsoft.Json;
9
14
 
10
- ```python
11
- import json
15
+ namespace ConsoleApp2
12
- import math
16
+ {
13
- import random
17
+ class Program
18
+ {
19
+ static void Main(string[] args)
20
+ {
21
+ var sw = new System.Diagnostics.Stopwatch();
14
- import time
22
+ sw.Start();
23
+ int chanceOfPopExcution = 1;
24
+ int chanceOfCompanyExcution = 1;
25
+ var pop = new Pop(chanceOfPopExcution, chanceOfCompanyExcution);
26
+ var company = new Company();
27
+ Console.WriteLine(pop.popItems.Count);
28
+ Console.WriteLine(company.companyItems.Count);
29
+ pop.action();
30
+ sw.Stop();
31
+ Console.WriteLine("■処理Aにかかった時間");
32
+ TimeSpan ts = sw.Elapsed;
33
+ Console.WriteLine($" {ts}");
34
+ Console.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒");
35
+ Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒");
36
+ }
37
+ }
15
38
 
16
- # 10%の確率で、POPが行動する。
39
+ class Goods
40
+ {
17
- pop_excution_rate = 10
41
+ public double life = 0.2;
42
+ public double everyday = 0.4;
43
+ public double luxury = 1.1;
44
+ }
18
45
 
46
+ public class Company
47
+ {
48
+ public List<CompanyItem> companyItems;
19
49
 
20
- def main():
21
- start = time.time()
22
- pops = Pop()
50
+ public Company()
51
+ {
52
+ using (var sr = new StreamReader(@"company.json", System.Text.Encoding.UTF8))
53
+ {
23
- pops.action()
54
+ var jsonData = sr.ReadToEnd();
55
+ companyItems = JsonConvert.DeserializeObject<List<CompanyItem>>(jsonData);
56
+ }
57
+ }
58
+ public class CompanyItem
59
+ {
60
+ public int code { get; set; }
61
+ public double capital { get; set; }
62
+ public double asset { get; set; }
63
+ public double revenue { get; set; }
64
+ public double issued { get; set; }
65
+ public double apprprt_price { get; set; }
24
- elapsed_time = time.time() - start
66
+ public double share_price { get; set; }
25
- print("elapsed_time:{0}".format(elapsed_time) + "[sec]")
26
- # 10秒もかかる
67
+ }
68
+ }
27
69
 
70
+ public class Pop
71
+ {
72
+ public List<PopItem> popItems;
73
+ public int chanceOfPopExcution;
74
+ public int chanceOfCompanyExcution;
75
+ public Pop(int _chanceOfPopExcution, int _chanceOfCompanyExcution)
76
+ {
77
+ chanceOfPopExcution = _chanceOfPopExcution;
78
+ chanceOfCompanyExcution = _chanceOfCompanyExcution;
79
+ using (var sr = new StreamReader(@"pop.json", System.Text.Encoding.UTF8))
80
+ {
81
+ var jsonData = sr.ReadToEnd();
82
+ popItems = JsonConvert.DeserializeObject<List<PopItem>>(jsonData);
83
+ }
84
+ }
28
85
 
29
- class Goods:
30
- # グッズの値段
31
- life = 0.2
32
- everyday = 0.4
86
+ public void action()
87
+ {
88
+ for (int i = 0; i < popItems.Count; i++)
89
+ {
90
+ var ob = new ChanceOfExcution();
91
+ if (ob.calc(chanceOfPopExcution))
92
+ {
93
+ Dictionary<string,double> consumption = consume(popItems[i]);
94
+ popItems[i].money = consumption["money"];
95
+ if (consumption["fulfilled"] == 3)
96
+ {
97
+ invest(popItems[i]);
98
+ }
99
+ }
100
+ }
33
- luxury = 1.1
101
+ return;
102
+ }
34
103
 
104
+ public List<Dictionary<string, double>> invest(PopItem popItem)
105
+ {
106
+ var returnList = new List<Dictionary<string, double>>();
107
+ var ob = new ChanceOfExcution();
108
+ if (ob.calc(chanceOfCompanyExcution))
109
+ {
110
+ var companyItems = new Company().companyItems;
35
111
 
36
- class Company:
112
+ double money = popItem.size * popItem.money;
37
- companies = []
38
113
 
39
- def __init__(self):
40
- self.companies = json.load(open('company.json', 'r'))
114
+ for (int i = 0; i < companyItems.Count; i++)
41
- # eg. company={"code":1,"capital":282,"asset":-2233,"revenue":1105,"issued":564,"apprprt_price":15.6,"share_price":10.9}
115
+ {
42
116
 
117
+ var companyItem = companyItems[i];
118
+ if (popItem.size * popItem.money * 0.8 > money) break;
119
+ if (companyItem.share_price == 0 || companyItem.apprprt_price / companyItem.share_price >= 1)
120
+ {
121
+ var obj = new Random();
122
+ double rand = obj.Next(9, 12) / 10;
123
+ double investingPrice;
124
+ if (companyItem.share_price == 0)
125
+ {
126
+ investingPrice = 0.5 * Math.Round(rand, 1, MidpointRounding.AwayFromZero);
127
+ }
128
+ else
129
+ {
130
+ investingPrice = 0.5 * Math.Round(companyItem.share_price * rand, 1, MidpointRounding.AwayFromZero);
131
+ }
132
+ if (popItem.money / 10 > investingPrice)
133
+ {
134
+ double rand2 = obj.Next(5, 15) / 10;
135
+ double investingVolume = Math.Floor(money / 100 * rand2 / investingPrice);
136
+ var dic = new Dictionary<string, double>() { { "pop_code", popItem.code }, { "company_code", companyItem.code }, { "price", investingPrice }, { "volume", investingVolume } };
137
+ returnList.Add(dic);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ return returnList;
143
+ }
43
144
 
145
+ public Dictionary<string, double> consume(PopItem pop_item)
146
+ {
147
+ var goods = new Goods();
148
+ double money = pop_item.money;
149
+ double multiplyer = (100 / chanceOfPopExcution);
150
+ if (money - goods.life * multiplyer < 0) {
151
+ return new Dictionary<string, double>(){ {"fulfilled",0},{"money",money}};
152
+ }
153
+ else if(money - (goods.life + goods.everyday) * multiplyer < 0)
154
+ {
155
+ return new Dictionary<string, double>() { { "fulfilled", 1 }, { "money", money - goods.life } };
156
+ }
157
+ else if(money - (goods.life + goods.everyday + goods.luxury) * multiplyer < 0)
158
+ {
159
+ return new Dictionary<string, double>() { { "fulfilled", 2 }, { "money", money - (goods.life + goods.everyday) * multiplyer } };
160
+ }
44
- class Pop:
161
+ else
45
- pops = []
162
+ {
163
+ return new Dictionary<string, double>() { { "fulfilled", 3 }, { "money", money - (goods.life + goods.everyday + goods.luxury) * multiplyer } };
164
+ }
165
+ }
46
166
 
167
+ public class PopItem
168
+ {
169
+ public int code { get; set; }
47
- def __init__(self):
170
+ public int size { get; set; }
48
- self.pops = json.load(open('pop.json', 'r'))
171
+ public double money { get; set; }
49
- # eg. pop={"code":1,"size":1241,"money":45,"shares":[]}
172
+ public List<Dictionary<string,double>> share { get; set; }
173
+ }
174
+ }
50
175
 
51
- def action(self):
52
- for pop in self.pops:
53
- chance = Chance_of_execution()
176
+ public class ChanceOfExcution
177
+ {
54
- if (chance.calc(pop_excution_rate)):
178
+ public bool calc(int chance)
179
+ {
55
- comsumption = self.consume(pop)
180
+ var ob = new Random();
56
- pop['money'] = comsumption['money']
57
- if (comsumption['fulfilled'] == 'luxury'):
58
- print(json.dumps(self.invest(pop)))
181
+ int rand = ob.Next(1, 10000);
182
+ int num = chance * 100;
183
+ return num >= rand;
184
+ }
185
+ }
186
+ }
59
187
 
60
- def invest(self, pop):
61
- companies = Company().companies
62
- array = []
63
- # size(人口) × money(平均した所持金) でこの団体の資金力を表現
64
- money = pop['money'] * pop['size']
65
- for index in range(len(companies)):
66
- company = companies[index]
67
- if (pop['money'] * pop['size'] * 0.8 > money):
68
- # 一日に所持金を使い果たさないように、ここでブレーキ
69
- break
70
- # apprprt_price(妥当な株価)と比較して、購入するか判断
71
- if (company['share_price'] == 0) or (company['apprprt_price'] / company['share_price'] >= 1):
72
- if (company['share_price'] == 0):
73
- # 株価が0の場合
74
- investing_price = 0.5 * (random.randint(9, 12) / 10)
75
- else:
76
- # 後に追加する株式市場のシステムのために、株の購入金額はばらつかせる
77
- investing_price = round(
78
- company['share_price'] * (random.randint(9, 12) / 10), 1)
79
- if (pop['money'] / 10 > investing_price):
80
- # 余裕資金で投資させるので、大体資金力の200~100分の1で取引
81
- investing_volume = math.floor(
82
- ((money / 100) * (random.randint(5, 111) / 10)) / investing_price)
83
- array.append({'pop_code': pop['code'], 'company_code': company['code'],
84
- 'volume': investing_volume, 'price': investing_price})
85
- money -= investing_price * investing_volume
86
- # この時点で売買は成立していないので、とりあえず記録を返す。この後の処理は未実装
87
- return array
88
-
89
- def consume(self, pop):
90
- # POPは株式投資以外にも、日々の生活を送るため、ここで日常品を消費し代金を支払う
91
- goods = Goods()
92
- money = pop['money']
93
- # multiplyerは実行しなかったときの消費活動を考慮した結果
94
- multiplyer = (100/pop_excution_rate)
95
- if (money - goods.life*multiplyer < 0):
96
- return {'fulfilled': 'no', 'money': money}
97
- elif (money - (goods.life + goods.everyday)*multiplyer < 0):
98
- return {'fulfilled': 'life', 'money': money - goods.life*multiplyer}
99
- elif (money - (goods.life + goods.everyday + goods.luxury)*multiplyer < 0):
100
- return {'fulfilled': 'everyday', 'money': money - (goods.life + goods.everyday)*multiplyer}
101
- else:
102
- return {'fulfilled': 'luxury', 'money': money - (goods.life + goods.everyday + goods.luxury)*multiplyer}
103
-
104
-
105
- class Chance_of_execution:
106
- # 実行確率
107
- def calc(self, chance):
108
- rand = random.randint(1, 10000)
109
- num = chance * 100
110
- return num >= rand
111
-
112
-
113
- if __name__ == '__main__':
114
- main()
115
-
116
188
  ```
117
189
 
118
190
  ### さいごに
119
- このテストはpythonで記述しましたが、最終的にはunityで作りたいのでC#でやり直します。ですが、本質的に動作が重すぎる点は言語のせいではないと思いますので、この時点で何かアドバイスをいただきたいと思い、質問させていただきました。
191
+ このテストはpythonで記述しましたが、最終的にはunityで作りたいのでC#でやり直します。ですが、本質的に動作が重すぎる点は言語のせいではないと思いますので、この時点で何かアドバイスをいただきたいと思い、質問させていただきました。
192
+
193
+ ### 追記
194
+ pop.jsonは100,000件のデータを、company.jsonは500件のデータを持っています。これら合計して50,000,000件計算させるのは心が痛むので、確率でPopとCompanyが動くようにしました。どちらも1%の確率で処理させ、合計処理を5000件に抑えたのですが、それでも処理に1秒くらいかかってしまいます。
195
+ 本番環境では、これよりもっと複雑な計算も行いますし、PopもCompanyも一桁多いくらいな想定です。今のままでは不可能ですが、前述のゲーム、Victoria 2ではこの状況に非常によく似た問題の対処が行われています。全く想像つきません。一緒に考えてもらえませんか?