質問編集履歴
1
C#は扱ったことがないので躊躇っていましたが、ちょっとやってみました。それと、扱っているデータについてお話しし忘れていましたので追記しました。
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
|
-
|
15
|
+
namespace ConsoleApp2
|
12
|
-
|
16
|
+
{
|
13
|
-
|
17
|
+
class Program
|
18
|
+
{
|
19
|
+
static void Main(string[] args)
|
20
|
+
{
|
21
|
+
var sw = new System.Diagnostics.Stopwatch();
|
14
|
-
|
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
|
-
|
39
|
+
class Goods
|
40
|
+
{
|
17
|
-
|
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
|
-
|
50
|
+
public Company()
|
51
|
+
{
|
52
|
+
using (var sr = new StreamReader(@"company.json", System.Text.Encoding.UTF8))
|
53
|
+
{
|
23
|
-
|
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
|
-
|
66
|
+
public double share_price { get; set; }
|
25
|
-
print("elapsed_time:{0}".format(elapsed_time) + "[sec]")
|
26
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
112
|
+
double money = popItem.size * popItem.money;
|
37
|
-
companies = []
|
38
113
|
|
39
|
-
def __init__(self):
|
40
|
-
|
114
|
+
for (int i = 0; i < companyItems.Count; i++)
|
41
|
-
|
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
|
-
|
161
|
+
else
|
45
|
-
|
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
|
-
|
170
|
+
public int size { get; set; }
|
48
|
-
|
171
|
+
public double money { get; set; }
|
49
|
-
|
172
|
+
public List<Dictionary<string,double>> share { get; set; }
|
173
|
+
}
|
174
|
+
}
|
50
175
|
|
51
|
-
def action(self):
|
52
|
-
for pop in self.pops:
|
53
|
-
|
176
|
+
public class ChanceOfExcution
|
177
|
+
{
|
54
|
-
|
178
|
+
public bool calc(int chance)
|
179
|
+
{
|
55
|
-
|
180
|
+
var ob = new Random();
|
56
|
-
pop['money'] = comsumption['money']
|
57
|
-
if (comsumption['fulfilled'] == 'luxury'):
|
58
|
-
|
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ではこの状況に非常によく似た問題の対処が行われています。全く想像つきません。一緒に考えてもらえませんか?
|