manasimu 0.0.5 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|