manasimu 0.0.5 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/db/card_type_aggregate +0 -0
- data/ext/ford_fulkerson.so +0 -0
- data/lib/manasimu/card.rb +86 -50
- data/lib/manasimu/data.rb +10 -40
- data/lib/manasimu/game.rb +1 -0
- data/lib/manasimu/planner.rb +68 -62
- data/lib/manasimu.rb +1 -0
- metadata +4 -4
- data/db/AllPrintings.sqlite +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fcf4ab765b75c28a6f58a74bfda7d269c7e5cfc5e70428134ae1180d10808c8
|
4
|
+
data.tar.gz: 24cf80041b275bfb6319281a4690de274c53bbf84d7b346ed09db349554da192
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36302a7575cf1f9816745c859da77b2f5cf1e10b2aa8bc5491819560740a5dbde3b121379ce6d89b906637cddab44f34853d49f9128d03f67ba547370dfb0d1c
|
7
|
+
data.tar.gz: 514f55d99c0bf4a6969a1ed7b00a10e043e8c84afa7341151892d425dd2ac722547093e01feb3eacae91ebe23dc4b97521afe75d1c16e0dca9430b7f5ff9b610
|
Binary file
|
data/ext/ford_fulkerson.so
CHANGED
Binary file
|
data/lib/manasimu/card.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Card
|
2
|
-
attr_accessor :id, :card_type
|
2
|
+
attr_accessor :id, :card_type, :side
|
3
3
|
|
4
4
|
def initialize(card_type)
|
5
5
|
@card_type = card_type
|
@@ -13,10 +13,12 @@ class Card
|
|
13
13
|
@card_type.drawed(turn)
|
14
14
|
end
|
15
15
|
|
16
|
-
def played(turn)
|
16
|
+
def played(turn, side = "a")
|
17
17
|
@played = turn
|
18
|
+
@side = side
|
18
19
|
@card_type.played(turn)
|
19
20
|
end
|
21
|
+
|
20
22
|
def played?
|
21
23
|
@played.nil?
|
22
24
|
end
|
@@ -29,8 +31,8 @@ class Card
|
|
29
31
|
@card_type.mana_source?
|
30
32
|
end
|
31
33
|
|
32
|
-
def playable?(lands)
|
33
|
-
@card_type.playable?(lands)
|
34
|
+
def playable?(lands, capas)
|
35
|
+
@card_type.playable?(lands, capas)
|
34
36
|
end
|
35
37
|
|
36
38
|
def types
|
@@ -61,12 +63,23 @@ class Card
|
|
61
63
|
@card_type.price
|
62
64
|
end
|
63
65
|
|
64
|
-
def
|
65
|
-
@
|
66
|
+
def reset
|
67
|
+
@side = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def max_flow(lands, capas)
|
71
|
+
@card_type.max_flow(lands, capas)
|
72
|
+
end
|
73
|
+
|
74
|
+
def edges(lands, capas)
|
75
|
+
@card_type.edges(lands, capas)
|
76
|
+
end
|
77
|
+
|
78
|
+
def mana_produced?
|
79
|
+
@side
|
66
80
|
end
|
67
81
|
|
68
|
-
def
|
69
|
-
@card_type.edges(lands)
|
82
|
+
def first_produce_symbol=(symbol)
|
70
83
|
end
|
71
84
|
|
72
85
|
def to_s
|
@@ -75,7 +88,16 @@ class Card
|
|
75
88
|
end
|
76
89
|
|
77
90
|
class CardType
|
78
|
-
attr_accessor :contents
|
91
|
+
attr_accessor :contents, :played, :drawed, :name
|
92
|
+
|
93
|
+
def self.create(card_type, name)
|
94
|
+
ret = card_type.dup
|
95
|
+
ret.contents = card_type.contents
|
96
|
+
ret.played = nil
|
97
|
+
ret.drawed = nil
|
98
|
+
ret.name = name
|
99
|
+
ret
|
100
|
+
end
|
79
101
|
|
80
102
|
def initialize(contents)
|
81
103
|
return if not contents
|
@@ -139,18 +161,42 @@ class CardType
|
|
139
161
|
end
|
140
162
|
end
|
141
163
|
|
164
|
+
def symbols
|
165
|
+
return @symbols if @symbols
|
166
|
+
@symbols = []
|
167
|
+
mana_cost[1..-2].split('}{').each_with_index do |mana, j|
|
168
|
+
spell_colors = mana.split('/')
|
169
|
+
if spell_colors.length == 1
|
170
|
+
spell_color = spell_colors[0]
|
171
|
+
if spell_color.to_i.to_s == spell_color
|
172
|
+
# numeric symbol
|
173
|
+
spell_color.to_i.times do |k|
|
174
|
+
@symbols << "1"
|
175
|
+
end
|
176
|
+
else
|
177
|
+
# color symbol
|
178
|
+
@symbols << spell_color
|
179
|
+
end
|
180
|
+
else
|
181
|
+
# multi symbol
|
182
|
+
throw Exception.new('unprogramed exception')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
@symbols
|
186
|
+
end
|
187
|
+
|
142
188
|
def price
|
143
189
|
converted_mana_cost
|
144
190
|
end
|
145
191
|
|
146
|
-
def playable?(lands)
|
147
|
-
return [false, []] if lands.empty?
|
148
|
-
return [false, []] if converted_mana_cost > lands.length
|
149
|
-
mf, used = max_flow(lands)
|
150
|
-
[mf == converted_mana_cost, used.to_a[1..lands.length]]
|
192
|
+
def playable?(lands, capas)
|
193
|
+
return [false, [], []] if lands.empty?
|
194
|
+
return [false, [], []] if converted_mana_cost > lands.length
|
195
|
+
mf, used, land_symbols = max_flow(lands, capas)
|
196
|
+
[mf == converted_mana_cost, used.to_a[1..lands.length], land_symbols]
|
151
197
|
end
|
152
198
|
|
153
|
-
def max_flow(lands)
|
199
|
+
def max_flow(lands, capas)
|
154
200
|
obj = FordFulkersonSingleton.instance.obj
|
155
201
|
# Graph has x+y+2 nodes
|
156
202
|
# source : 0
|
@@ -165,17 +211,29 @@ class CardType
|
|
165
211
|
#
|
166
212
|
|
167
213
|
# create edge
|
168
|
-
x, y, e = edges(lands)
|
214
|
+
x, y, e = edges(lands, capas)
|
169
215
|
g = Graph.new(x + y + 2)
|
170
216
|
e.each do |s, d|
|
171
217
|
g.add_edge(s, d, 1)
|
172
218
|
end
|
173
219
|
|
174
220
|
ret = obj.max_flow(g, 0, x + y + 1)
|
175
|
-
|
221
|
+
|
222
|
+
land_symbols = Array.new(lands.length)
|
223
|
+
for edges in g.G do
|
224
|
+
for edge in edges do
|
225
|
+
if edge.cap == 0 and edge.from.between?(1, x) and edge.to.between?(x+1, x+y)
|
226
|
+
land_index = edge.from - 1
|
227
|
+
spell_index = edge.to - x - 1
|
228
|
+
land_symbols[land_index] = symbols[spell_index]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
[ret, obj.used, land_symbols]
|
176
234
|
end
|
177
235
|
|
178
|
-
def edges(lands)
|
236
|
+
def edges(lands, capas)
|
179
237
|
result = []
|
180
238
|
x = lands.length
|
181
239
|
i_src = 0
|
@@ -184,29 +242,9 @@ class CardType
|
|
184
242
|
result << [i_src, i + 1]
|
185
243
|
end
|
186
244
|
|
187
|
-
# create symbol
|
188
|
-
symbols = []
|
189
|
-
mana_cost[1..-2].split('}{').each_with_index do |mana, j|
|
190
|
-
spell_colors = mana.split('/')
|
191
|
-
if spell_colors.length == 1
|
192
|
-
spell_color = spell_colors[0]
|
193
|
-
if spell_color.to_i.to_s == spell_color
|
194
|
-
# numeric symbol
|
195
|
-
spell_color.to_i.times do |k|
|
196
|
-
symbols << "1"
|
197
|
-
end
|
198
|
-
else
|
199
|
-
# color symbol
|
200
|
-
symbols << spell_color
|
201
|
-
end
|
202
|
-
else
|
203
|
-
# multi symbol
|
204
|
-
throw Exception.new('unprogramed exception')
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
245
|
# lands and mana_cost connect to each symbols
|
209
246
|
lands.each_with_index do |land, i|
|
247
|
+
next if capas[i].to_i == 0
|
210
248
|
land_colors = land.color_identity
|
211
249
|
symbols.each_with_index do |symbol, j|
|
212
250
|
if symbol == "1" or land_colors.include? symbol
|
@@ -246,22 +284,19 @@ end
|
|
246
284
|
|
247
285
|
class CardTypeAggregate
|
248
286
|
|
249
|
-
def find(
|
287
|
+
def find(set_code, number)
|
250
288
|
@memo ||= []
|
251
|
-
|
252
|
-
singleton = @memo.find do |c|
|
289
|
+
@memo.find do |c|
|
253
290
|
a = c.contents[0]
|
254
|
-
|
255
|
-
a and b and a.name == b.name
|
256
|
-
end
|
257
|
-
if singleton
|
258
|
-
singleton
|
259
|
-
else
|
260
|
-
@memo << card_type
|
261
|
-
card_type
|
291
|
+
a and a.set_code == set_code and a.number == number
|
262
292
|
end
|
263
293
|
end
|
264
294
|
|
295
|
+
def add(card_type)
|
296
|
+
@memo ||= []
|
297
|
+
@memo << card_type
|
298
|
+
end
|
299
|
+
|
265
300
|
def each
|
266
301
|
return if not @memo
|
267
302
|
@memo.each do |item|
|
@@ -293,6 +328,7 @@ class Content
|
|
293
328
|
def to_s
|
294
329
|
"[#{@name}] [#{@types}] [#{@color_identity}] [#{@mana_cost}]"
|
295
330
|
end
|
331
|
+
|
296
332
|
end
|
297
333
|
|
298
334
|
class FordFulkersonSingleton
|
data/lib/manasimu/data.rb
CHANGED
@@ -61,50 +61,20 @@ class Deck
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def self.get_card_details(deck_items)
|
64
|
-
path = File.expand_path( '../../../db/
|
65
|
-
|
66
|
-
sql = <<DOC
|
67
|
-
select distinct
|
68
|
-
name
|
69
|
-
,number
|
70
|
-
,colorIdentity
|
71
|
-
,side
|
72
|
-
,setCode
|
73
|
-
,manaCost
|
74
|
-
,types
|
75
|
-
,text
|
76
|
-
,convertedManaCost
|
77
|
-
from cards
|
78
|
-
where
|
79
|
-
number = ? and
|
80
|
-
setCode = ?
|
81
|
-
DOC
|
64
|
+
path = File.expand_path( '../../../db/card_type_aggregate', __FILE__ )
|
65
|
+
@@card_types ||= Marshal.load(File.open(path, 'r'))
|
82
66
|
cards = []
|
83
67
|
card_id = 0
|
84
|
-
card_types =
|
68
|
+
card_types = []
|
85
69
|
deck_items.each do |deck_item|
|
86
|
-
|
87
|
-
|
88
|
-
|
70
|
+
card_type = @@card_types.find(deck_item[:set], deck_item[:setnum])
|
71
|
+
clone = CardType.create(card_type, deck_item[:name])
|
72
|
+
card_types << clone
|
73
|
+
if clone.name =~ /.*Pathway$/ and clone.mana_source?
|
74
|
+
card = PathwayCard.new(clone)
|
75
|
+
else
|
76
|
+
card = Card.new(clone)
|
89
77
|
end
|
90
|
-
|
91
|
-
card_type = card_types.find(
|
92
|
-
CardType.new(rows.map { |row|
|
93
|
-
{
|
94
|
-
name: row[0],
|
95
|
-
number: row[1],
|
96
|
-
color_identity: row[2],
|
97
|
-
side: row[3],
|
98
|
-
set_code: row[4],
|
99
|
-
mana_cost: row[5],
|
100
|
-
types: row[6],
|
101
|
-
text: row[7],
|
102
|
-
converted_mana_cost: row[8]
|
103
|
-
}
|
104
|
-
})
|
105
|
-
)
|
106
|
-
card = Card.new(card_type)
|
107
|
-
|
108
78
|
deck_item[:amount].to_i.times do
|
109
79
|
card_clone = card.dup
|
110
80
|
card_clone.id = card_id
|
data/lib/manasimu/game.rb
CHANGED
data/lib/manasimu/planner.rb
CHANGED
@@ -6,6 +6,8 @@ class Planner
|
|
6
6
|
max_price = 0
|
7
7
|
max_spells = nil
|
8
8
|
max_land = nil
|
9
|
+
max_symbols = nil
|
10
|
+
max_lands = nil
|
9
11
|
|
10
12
|
if not lands_in_hand.empty?
|
11
13
|
lands_in_hand.each do |play_land|
|
@@ -18,23 +20,33 @@ class Planner
|
|
18
20
|
current_fields << play_land
|
19
21
|
|
20
22
|
# search_opt_spells
|
21
|
-
price, spells =
|
23
|
+
price, spells, symbols, lands =
|
22
24
|
search_opt_spells(current_hands, current_fields)
|
23
25
|
if price >= max_price and not spells.empty?
|
24
26
|
max_price = price
|
25
27
|
max_spells = spells
|
26
28
|
max_land = play_land
|
29
|
+
max_symbols = symbols
|
30
|
+
max_lands = lands
|
27
31
|
end
|
28
32
|
end
|
29
33
|
else
|
30
34
|
# search_opt_spells
|
31
|
-
max_price, max_spells = search_opt_spells(hands, fields)
|
35
|
+
max_price, max_spells, max_symbols, max_lands = search_opt_spells(hands, fields)
|
32
36
|
end
|
33
37
|
|
34
38
|
if not max_spells and not lands_in_hand.empty?
|
35
39
|
max_land = lands_in_hand[0]
|
36
40
|
end
|
37
41
|
|
42
|
+
if max_lands
|
43
|
+
max_lands.each_with_index do |land, i|
|
44
|
+
if not land.mana_produced?
|
45
|
+
land.first_produce_symbol = max_symbols[i]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
38
50
|
[max_land, max_spells].select {|a| a}.flatten
|
39
51
|
end
|
40
52
|
|
@@ -60,94 +72,88 @@ class Planner
|
|
60
72
|
bit_lands = 0
|
61
73
|
bit_spells = 0
|
62
74
|
# search playable spell comibantion
|
63
|
-
cost, bit_spells, bit_lands =
|
64
|
-
dfs(1, spells, lands, bit_spells, bit_lands, price)
|
65
|
-
[price, bit_select(spells, bit_spells)]
|
75
|
+
cost, bit_spells, bit_lands, land_symbols =
|
76
|
+
dfs(1, spells, lands, bit_spells, bit_lands, price, [])
|
77
|
+
[price, bit_select(spells, bit_spells), land_symbols, lands]
|
66
78
|
end
|
67
79
|
|
68
|
-
def dfs(n, spells, lands, bit_spells, bit_lands, price)
|
80
|
+
def dfs(n, spells, lands, bit_spells, bit_lands, price, total_land_symbols)
|
69
81
|
index = n - 1
|
70
82
|
|
71
83
|
# exit
|
72
|
-
return [price, bit_spells, bit_lands] if n > spells.length
|
84
|
+
return [price, bit_spells, bit_lands, total_land_symbols] if n > spells.length
|
73
85
|
|
74
86
|
spell = spells[index]
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
87
|
+
used_lands = bit_lands.to_s(2).chars
|
88
|
+
capas = lands.length.times.to_a.map do |i|
|
89
|
+
used_lands[i] == "1" ? "0" : "1"
|
90
|
+
end
|
91
|
+
|
92
|
+
# shrink
|
93
|
+
# lands_available = []
|
94
|
+
# lands.length.times do |i|
|
95
|
+
# next if used_lands[i] == "1"
|
96
|
+
# lands_available << lands[i]
|
97
|
+
# end
|
98
|
+
# capas = ("1" * lands_available.length).chars
|
79
99
|
|
80
100
|
# cast case
|
81
|
-
is_playable,
|
82
|
-
|
101
|
+
is_playable, casted_lands, land_symbols =
|
102
|
+
spell.playable?(lands, capas)
|
103
|
+
|
104
|
+
# expand
|
105
|
+
# used_lands_ = []
|
106
|
+
# land_symbols_ = []
|
107
|
+
# j = 0
|
108
|
+
# lands.length.times do |i|
|
109
|
+
# if used_lands[i] == "1" or not casted_lands
|
110
|
+
# used_lands_ << "1"
|
111
|
+
# land_symbols_ << total_land_symbols[i]
|
112
|
+
# else
|
113
|
+
# used_lands_ << casted_lands[j]
|
114
|
+
# land_symbols_ << land_symbols[j]
|
115
|
+
# j += 1
|
116
|
+
# end
|
117
|
+
# end if lands
|
118
|
+
|
119
|
+
a_price, a_bit_spells, a_bit_lands, a_land_symbols =
|
83
120
|
if is_playable
|
121
|
+
|
84
122
|
bit_spells = bit_spells | 1 << ( n - 1 )
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
123
|
+
bit_lands_ = casted_lands
|
124
|
+
.reverse
|
125
|
+
.map {|i| i.to_s}
|
126
|
+
.join('')
|
127
|
+
.to_i(2)
|
128
|
+
|
129
|
+
land_symbols_ = lands.length.times.to_a.map do |i|
|
130
|
+
land_symbols[i] ? land_symbols[i] : total_land_symbols[i]
|
131
|
+
end
|
132
|
+
|
94
133
|
# dfs
|
95
|
-
dfs(n + 1 , spells, lands, bit_spells,
|
134
|
+
dfs(n + 1 , spells, lands, bit_spells, bit_lands_,
|
135
|
+
price + spell.price, land_symbols_)
|
96
136
|
else
|
97
|
-
[nil, nil, nil]
|
137
|
+
[nil, nil, nil, nil]
|
98
138
|
end
|
99
139
|
|
100
140
|
# not cast case
|
101
|
-
b_price, b_bit_spells, b_bit_lands =
|
102
|
-
dfs(n + 1 , spells, lands, bit_spells, bit_lands, price)
|
141
|
+
b_price, b_bit_spells, b_bit_lands, b_land_symbols =
|
142
|
+
dfs(n + 1 , spells, lands, bit_spells, bit_lands, price, total_land_symbols)
|
103
143
|
|
104
144
|
if (a_price and a_price >= b_price)
|
105
|
-
[a_price, a_bit_spells, a_bit_lands]
|
145
|
+
[a_price, a_bit_spells, a_bit_lands, a_land_symbols]
|
106
146
|
else
|
107
|
-
[b_price, b_bit_spells, b_bit_lands]
|
147
|
+
[b_price, b_bit_spells, b_bit_lands, b_land_symbols]
|
108
148
|
end
|
109
149
|
end
|
110
150
|
|
111
|
-
def reverse_bit(bit, length)
|
112
|
-
s = bit.to_s(2)
|
113
|
-
length.times.to_a.map do |i|
|
114
|
-
if s[i] and s[i] == "1"
|
115
|
-
"0"
|
116
|
-
else
|
117
|
-
"1"
|
118
|
-
end
|
119
|
-
end.join.to_i(2)
|
120
|
-
end
|
121
|
-
|
122
151
|
def bit_select(cards, bit)
|
123
152
|
cards.length.times
|
124
153
|
.map { |i| cards[i] if (bit & (1 << i) > 0) }
|
125
154
|
.select { |o| o }
|
126
155
|
end
|
127
156
|
|
128
|
-
def update_bit(used_lands, bit_lands)
|
129
|
-
used_lands.each_with_index do |flg, i|
|
130
|
-
bit_lands = bit_lands | ( 1 << i ) if flg == 1
|
131
|
-
end
|
132
|
-
bit_lands
|
133
|
-
end
|
134
|
-
|
135
|
-
def fill_used_lands(used_lands, bit_lands, lands)
|
136
|
-
result = []
|
137
|
-
j = 0
|
138
|
-
lands.length.times do |i|
|
139
|
-
if (bit_lands & 1 << i) == 1
|
140
|
-
# used before dfs
|
141
|
-
result << 1
|
142
|
-
else
|
143
|
-
# used after dfs
|
144
|
-
result << used_lands[j]
|
145
|
-
j += 1
|
146
|
-
end
|
147
|
-
end
|
148
|
-
result
|
149
|
-
end
|
150
|
-
|
151
157
|
def lands(list)
|
152
158
|
list.select do |card|
|
153
159
|
card.types.include? "Land"
|
data/lib/manasimu.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manasimu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- so1itaryrove
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: mtg arrena mana curve simulator
|
14
14
|
email: so1itaryrove@gmail.com
|
@@ -16,7 +16,7 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
-
- db/
|
19
|
+
- db/card_type_aggregate
|
20
20
|
- ext/ford_fulkerson.so
|
21
21
|
- lib/manasimu.rb
|
22
22
|
- lib/manasimu/card.rb
|
@@ -45,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
47
|
requirements: []
|
48
|
-
rubygems_version: 3.
|
48
|
+
rubygems_version: 3.2.3
|
49
49
|
signing_key:
|
50
50
|
specification_version: 4
|
51
51
|
summary: mtg arrena mana curve simulator
|
data/db/AllPrintings.sqlite
DELETED
Binary file
|