manasimu 0.0.1
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 +7 -0
- data/db/AllPrintings.sqlite +0 -0
- data/ext/ford_fulkerson.so +0 -0
- data/lib/manasimu/card.rb +297 -0
- data/lib/manasimu/data.rb +117 -0
- data/lib/manasimu/game.rb +47 -0
- data/lib/manasimu/hello.rb +3 -0
- data/lib/manasimu/mana_type.rb +7 -0
- data/lib/manasimu/planner.rb +162 -0
- data/lib/manasimu/simulator.rb +20 -0
- data/lib/manasimu.rb +9 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3f5c5bf36d69150a34c30b6d1bd1304499bb5b7ffe36b6ef37640907803e0926
|
4
|
+
data.tar.gz: 24aad739622210bd7b24cf59d1c7db77c98db3da7cfa2c34f219598aaad6d4d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e796dbaf5cec8317086d4e72e6ce3b521996f39bdee0ee3261c97f6f2590ada27c6eb211227f54b49eaa1226244d94707e903a85abaa847f8f4253f1764e5812
|
7
|
+
data.tar.gz: 58f72bbf05f2842e2a70a14b21bdddf87a3ddf59da921c0db460fcb5d7c7720bb15f61102c31f72c94066aecdf128197f51d6db48ef5a709850d6fe2610227df
|
Binary file
|
Binary file
|
@@ -0,0 +1,297 @@
|
|
1
|
+
class Card
|
2
|
+
attr_accessor :id, :card_type
|
3
|
+
|
4
|
+
def initialize(card_type)
|
5
|
+
@card_type = card_type
|
6
|
+
end
|
7
|
+
|
8
|
+
def step(turn)
|
9
|
+
end
|
10
|
+
|
11
|
+
def drawed(turn)
|
12
|
+
@drawed = turn
|
13
|
+
@card_type.drawed(turn)
|
14
|
+
end
|
15
|
+
|
16
|
+
def played(turn)
|
17
|
+
@played = turn
|
18
|
+
@card_type.played(turn)
|
19
|
+
end
|
20
|
+
def played?
|
21
|
+
@played.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def tapped?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def mana_source?
|
29
|
+
@card_type.mana_source?
|
30
|
+
end
|
31
|
+
|
32
|
+
def playable?(lands)
|
33
|
+
@card_type.playable?(lands)
|
34
|
+
end
|
35
|
+
|
36
|
+
def types
|
37
|
+
@card_type.types
|
38
|
+
end
|
39
|
+
|
40
|
+
def mana
|
41
|
+
@card_type.mana
|
42
|
+
end
|
43
|
+
|
44
|
+
def color_identity
|
45
|
+
@card_type.color_identity
|
46
|
+
end
|
47
|
+
|
48
|
+
def converted_mana_cost
|
49
|
+
@card_type.converted_mana_cost
|
50
|
+
end
|
51
|
+
|
52
|
+
def color_identity_size
|
53
|
+
@card_type.color_identity_size
|
54
|
+
end
|
55
|
+
|
56
|
+
def mana_cost
|
57
|
+
@card_type.mana_cost
|
58
|
+
end
|
59
|
+
|
60
|
+
def price
|
61
|
+
@card_type.price
|
62
|
+
end
|
63
|
+
|
64
|
+
def max_flow(lands)
|
65
|
+
@card_type.max_flow(lands)
|
66
|
+
end
|
67
|
+
|
68
|
+
def edges(lands)
|
69
|
+
@card_type.edges(lands)
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
@card_type.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class CardType
|
78
|
+
attr_accessor :contents
|
79
|
+
|
80
|
+
def initialize(contents)
|
81
|
+
return if not contents
|
82
|
+
@contents = contents.map {|c| Content.new(c)}
|
83
|
+
end
|
84
|
+
|
85
|
+
def name
|
86
|
+
@name ||= @contents[0].name
|
87
|
+
end
|
88
|
+
|
89
|
+
def played(turn)
|
90
|
+
@played ||= {}
|
91
|
+
@played[turn] ||= 0
|
92
|
+
@played[turn] += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
def drawed(turn)
|
96
|
+
@drawed ||= {}
|
97
|
+
@drawed[turn] ||= 0
|
98
|
+
@drawed[turn] += 1
|
99
|
+
end
|
100
|
+
|
101
|
+
def mana_source?
|
102
|
+
@mana_source ||= @contents.any? {|content| content.mana_source?}
|
103
|
+
end
|
104
|
+
|
105
|
+
def types
|
106
|
+
@types ||= @contents.map {|c| c.types}
|
107
|
+
end
|
108
|
+
|
109
|
+
def mana
|
110
|
+
@mana ||= @contents.map {|content| content.color_identity }.flatten
|
111
|
+
end
|
112
|
+
|
113
|
+
def color_identity
|
114
|
+
return @memo_colors if @memo_colors
|
115
|
+
@memo_colors ||= []
|
116
|
+
@contents.each do |c|
|
117
|
+
c.color_identity.split(",").each do |color|
|
118
|
+
@memo_colors << color if not @memo_colors.include? color
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@memo_colors
|
122
|
+
end
|
123
|
+
|
124
|
+
def converted_mana_cost
|
125
|
+
@converted_mana_cost ||= @contents.map {|c| c.converted_mana_cost}.min
|
126
|
+
end
|
127
|
+
|
128
|
+
def color_identity_size
|
129
|
+
color_identity.length
|
130
|
+
end
|
131
|
+
|
132
|
+
def mana_cost
|
133
|
+
@mana_cost ||= @contents.select {|c| c.types != "Land"}.first.mana_cost
|
134
|
+
end
|
135
|
+
|
136
|
+
def price
|
137
|
+
converted_mana_cost
|
138
|
+
end
|
139
|
+
|
140
|
+
def playable?(lands)
|
141
|
+
return [false, []] if lands.empty?
|
142
|
+
return [false, []] if converted_mana_cost > lands.length
|
143
|
+
mf, used = max_flow(lands)
|
144
|
+
[mf == converted_mana_cost, used.to_a[1..lands.length]]
|
145
|
+
end
|
146
|
+
|
147
|
+
def max_flow(lands)
|
148
|
+
obj = FordFulkersonSingleton.instance.obj
|
149
|
+
# Graph has x+y+2 nodes
|
150
|
+
# source : 0
|
151
|
+
# lands : 1 - x
|
152
|
+
# mana_cost : x+1 - x+y+1
|
153
|
+
# destination : x+y+2
|
154
|
+
#
|
155
|
+
# image
|
156
|
+
# - land1 - mana4
|
157
|
+
# source0 - land2 - mana5 - destination6
|
158
|
+
# - land3
|
159
|
+
#
|
160
|
+
|
161
|
+
# create edge
|
162
|
+
x, y, e = edges(lands)
|
163
|
+
g = Graph.new(x + y + 2)
|
164
|
+
e.each do |s, d|
|
165
|
+
g.add_edge(s, d, 1)
|
166
|
+
end
|
167
|
+
|
168
|
+
ret = obj.max_flow(g, 0, x + y + 1)
|
169
|
+
[ret, obj.used]
|
170
|
+
end
|
171
|
+
|
172
|
+
def edges(lands)
|
173
|
+
result = []
|
174
|
+
x = lands.length
|
175
|
+
i_src = 0
|
176
|
+
# source connect to lands
|
177
|
+
x.times do |i|
|
178
|
+
result << [i_src, i + 1]
|
179
|
+
end
|
180
|
+
|
181
|
+
# create symbol
|
182
|
+
symbols = []
|
183
|
+
mana_cost[1..-2].split('}{').each_with_index do |mana, j|
|
184
|
+
spell_colors = mana.split('/')
|
185
|
+
if spell_colors.length == 1
|
186
|
+
spell_color = spell_colors[0]
|
187
|
+
if spell_color.to_i.to_s == spell_color
|
188
|
+
# numeric symbol
|
189
|
+
spell_color.to_i.times do |k|
|
190
|
+
symbols << "1"
|
191
|
+
end
|
192
|
+
else
|
193
|
+
# color symbol
|
194
|
+
symbols << spell_color
|
195
|
+
end
|
196
|
+
else
|
197
|
+
# multi symbol
|
198
|
+
throw Exception.new('unprogramed exception')
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# lands and mana_cost connect to each symbols
|
203
|
+
lands.each_with_index do |land, i|
|
204
|
+
land_colors = land.color_identity
|
205
|
+
symbols.each_with_index do |symbol, j|
|
206
|
+
if symbol == "1" or land_colors.include? symbol
|
207
|
+
result << [i + 1, x + 1 + j]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
y = symbols.length
|
213
|
+
i_dst = x + y + 1
|
214
|
+
|
215
|
+
# mana_cost connect to destination
|
216
|
+
y.times do |i|
|
217
|
+
result << [x + 1 + i, i_dst]
|
218
|
+
end
|
219
|
+
|
220
|
+
[x, y, result]
|
221
|
+
end
|
222
|
+
|
223
|
+
def count(turn = nil)
|
224
|
+
turn ||= converted_mana_cost
|
225
|
+
played = @played ? @played [turn] : 0
|
226
|
+
drawed = 0
|
227
|
+
if (@drawed)
|
228
|
+
(turn+1).times do |i|
|
229
|
+
next if not @drawed[i]
|
230
|
+
drawed += @drawed[i]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
[played, drawed]
|
234
|
+
end
|
235
|
+
|
236
|
+
def to_s
|
237
|
+
@contents.map {|c| c.to_s}.join(",")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class CardTypeAggregate
|
242
|
+
|
243
|
+
def find(card_type)
|
244
|
+
@memo ||= []
|
245
|
+
return nil if not card_type
|
246
|
+
singleton = @memo.find do |c|
|
247
|
+
a = c.contents[0]
|
248
|
+
b = card_type.contents[0]
|
249
|
+
a and b and a.name == b.name
|
250
|
+
end
|
251
|
+
if singleton
|
252
|
+
singleton
|
253
|
+
else
|
254
|
+
@memo << card_type
|
255
|
+
card_type
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def each
|
260
|
+
return if not @memo
|
261
|
+
@memo.each do |item|
|
262
|
+
yield item
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
class Content
|
269
|
+
attr_accessor :name, :number, :side, :set_code, :mana_cost, :types, :color_identity, :converted_mana_cost, :text
|
270
|
+
|
271
|
+
def initialize(hash)
|
272
|
+
@name = hash[:name]
|
273
|
+
@number = hash[:number]
|
274
|
+
@side = hash[:side]
|
275
|
+
@set_code = hash[:set_code]
|
276
|
+
@mana_cost = hash[:mana_cost]
|
277
|
+
@types = hash[:types]
|
278
|
+
@text = hash[:text]
|
279
|
+
@color_identity = hash[:color_identity]
|
280
|
+
@converted_mana_cost = hash[:converted_mana_cost].to_i
|
281
|
+
end
|
282
|
+
|
283
|
+
def mana_source?
|
284
|
+
return @types == "Land"
|
285
|
+
end
|
286
|
+
|
287
|
+
def to_s
|
288
|
+
"[#{@name}] [#{@types}] [#{@color_identity}] [#{@mana_cost}]"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class FordFulkersonSingleton
|
293
|
+
include Singleton
|
294
|
+
def obj
|
295
|
+
@memo_obj ||= FordFulkerson.new
|
296
|
+
end
|
297
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class Deck
|
2
|
+
|
3
|
+
def self.create(lines)
|
4
|
+
items = Deck.input_to_card_hash(lines)
|
5
|
+
Deck.get_card_details(items)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.input_to_card_hash(lines)
|
9
|
+
result = []
|
10
|
+
looking_for_deck_line = false
|
11
|
+
for line in lines do
|
12
|
+
trimmed = line.chomp
|
13
|
+
trimmed_lower = trimmed.downcase
|
14
|
+
|
15
|
+
# Ignore reserved words
|
16
|
+
if trimmed_lower == "deck"
|
17
|
+
looking_for_deck_line = false
|
18
|
+
next
|
19
|
+
end
|
20
|
+
|
21
|
+
if trimmed_lower == "commander"
|
22
|
+
looking_for_deck_line = true
|
23
|
+
next
|
24
|
+
end
|
25
|
+
if trimmed_lower == "companion"
|
26
|
+
looking_for_deck_line = true
|
27
|
+
next
|
28
|
+
end
|
29
|
+
#Assumes sideboard comes after deck
|
30
|
+
if trimmed_lower == "sideboard"
|
31
|
+
break
|
32
|
+
end
|
33
|
+
if trimmed_lower == "maybeboard"
|
34
|
+
# Assumes maybeboard comes after deck
|
35
|
+
break
|
36
|
+
end
|
37
|
+
# Ignore line comments
|
38
|
+
if trimmed.start_with? ('#')
|
39
|
+
next
|
40
|
+
end
|
41
|
+
if looking_for_deck_line
|
42
|
+
next
|
43
|
+
end
|
44
|
+
# An empty line divides the main board cards from the side board cards
|
45
|
+
if trimmed.empty?
|
46
|
+
break
|
47
|
+
end
|
48
|
+
|
49
|
+
if !(trimmed =~ /\s*(\d+)\s+([^\(#\n\r]+)(?:\s*\((\w+)\)\s+(\d+))?\s*/)
|
50
|
+
next
|
51
|
+
end
|
52
|
+
|
53
|
+
deck_item = {}
|
54
|
+
deck_item[:amount] = $1.strip
|
55
|
+
deck_item[:name] = $2.strip
|
56
|
+
deck_item[:set] = $3.strip
|
57
|
+
deck_item[:setnum] = $4.strip
|
58
|
+
result << deck_item
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.get_card_details(deck_items)
|
64
|
+
path = File.expand_path( '../../../db/AllPrintings.sqlite', __FILE__ )
|
65
|
+
db = SQLite3::Database.new(path)
|
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
|
82
|
+
cards = []
|
83
|
+
card_id = 0
|
84
|
+
card_types = CardTypeAggregate.new
|
85
|
+
deck_items.each do |deck_item|
|
86
|
+
rows = db.execute(sql, deck_item[:setnum], deck_item[:set])
|
87
|
+
if rows.empty?
|
88
|
+
puts deck_item[:name]
|
89
|
+
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
|
+
deck_item[:amount].to_i.times do
|
109
|
+
card_clone = card.dup
|
110
|
+
card_clone.id = card_id
|
111
|
+
card_id += 1
|
112
|
+
cards << card_clone
|
113
|
+
end
|
114
|
+
end
|
115
|
+
[cards, card_types]
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Game
|
2
|
+
attr_accessor :hands, :plays, :deck
|
3
|
+
|
4
|
+
def initialize(deck)
|
5
|
+
@deck = deck.shuffle(random: Random.new)
|
6
|
+
@hands = []
|
7
|
+
@plays = []
|
8
|
+
@planner = Planner.new
|
9
|
+
7.times { draw(0) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def step(turn)
|
13
|
+
# puts "turn #{turn}"
|
14
|
+
# puts "played"
|
15
|
+
# @plays.each do |card| puts " #{card}" end
|
16
|
+
# puts "hands"
|
17
|
+
# @hands.each do |card| puts " #{card}" end
|
18
|
+
|
19
|
+
upkeep(turn)
|
20
|
+
draw(turn)
|
21
|
+
plan.each do |card|
|
22
|
+
play(card, turn)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def upkeep(turn)
|
27
|
+
@plays.each { |card| card.step(turn) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def draw(turn)
|
31
|
+
card = @deck.pop
|
32
|
+
# puts "draw #{card}"
|
33
|
+
card.drawed(turn)
|
34
|
+
@hands << card
|
35
|
+
end
|
36
|
+
|
37
|
+
def plan
|
38
|
+
@planner.plan(@hands, @plays)
|
39
|
+
end
|
40
|
+
|
41
|
+
def play(card, turn)
|
42
|
+
# puts "play #{card}"
|
43
|
+
card.played(turn)
|
44
|
+
@plays << card
|
45
|
+
@hands.delete card
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
class Planner
|
2
|
+
|
3
|
+
def plan(hands, fields)
|
4
|
+
lands_in_hand = lands(hands)
|
5
|
+
|
6
|
+
max_price = 0
|
7
|
+
max_spells = nil
|
8
|
+
max_land = nil
|
9
|
+
|
10
|
+
if not lands_in_hand.empty?
|
11
|
+
lands_in_hand.each do |play_land|
|
12
|
+
# dup
|
13
|
+
current_hands = hands.dup
|
14
|
+
current_fields = fields.dup
|
15
|
+
|
16
|
+
# play the land
|
17
|
+
current_hands.delete play_land
|
18
|
+
current_fields << play_land
|
19
|
+
|
20
|
+
# search_opt_spells
|
21
|
+
price, spells =
|
22
|
+
search_opt_spells(current_hands, current_fields)
|
23
|
+
if price >= max_price and not spells.empty?
|
24
|
+
max_price = price
|
25
|
+
max_spells = spells
|
26
|
+
max_land = play_land
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
# search_opt_spells
|
31
|
+
max_price, max_spells = search_opt_spells(hands, fields)
|
32
|
+
end
|
33
|
+
|
34
|
+
if not max_spells and not lands_in_hand.empty?
|
35
|
+
max_land = lands_in_hand[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
[max_land, max_spells].select {|a| a}.flatten
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# on conditional playing land, search most
|
43
|
+
# high price spells combinations
|
44
|
+
# return price, spells
|
45
|
+
#
|
46
|
+
def search_opt_spells(hands, fields)
|
47
|
+
spells = spells(hands)
|
48
|
+
lands = lands(fields)
|
49
|
+
|
50
|
+
# sort spells desc converted_mana_cost
|
51
|
+
spells.sort! do |a, b|
|
52
|
+
b.converted_mana_cost <=> a.converted_mana_cost
|
53
|
+
end
|
54
|
+
|
55
|
+
lands.sort! do |a, b|
|
56
|
+
b.color_identity_size <=> a.color_identity_size
|
57
|
+
end
|
58
|
+
|
59
|
+
price = 0
|
60
|
+
bit_lands = 0
|
61
|
+
bit_spells = 0
|
62
|
+
# 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)]
|
66
|
+
end
|
67
|
+
|
68
|
+
def dfs(n, spells, lands, bit_spells, bit_lands, price)
|
69
|
+
index = n - 1
|
70
|
+
|
71
|
+
# exit
|
72
|
+
return [price, bit_spells, bit_lands] if n > spells.length
|
73
|
+
|
74
|
+
spell = spells[index]
|
75
|
+
# ex) lands [a,b,c,d]
|
76
|
+
# bit_lands is 3 ( = 0011)
|
77
|
+
# then left_lands to be [c, d]
|
78
|
+
left_lands = bit_select(lands, reverse_bit(bit_lands, lands.length))
|
79
|
+
|
80
|
+
# cast case
|
81
|
+
is_playable, used_lands = spell.playable?(left_lands)
|
82
|
+
a_price, a_bit_spells, a_bit_lands =
|
83
|
+
if is_playable
|
84
|
+
bit_spells = bit_spells | 1 << ( n - 1 )
|
85
|
+
# ex) lands [a,b,c,d]
|
86
|
+
# bit_lands 3 ( = 0011)
|
87
|
+
# used_lands [d]
|
88
|
+
# then used_lands to be [0,0,0,d]
|
89
|
+
used_lands = fill_used_lands(used_lands, bit_lands, lands)
|
90
|
+
# ex) used_lands [0,0,0,d]
|
91
|
+
# bit_lands 3 ( = 0011)
|
92
|
+
# then bit_lands to be 11 ( = 1011)
|
93
|
+
bit_lands = update_bit(used_lands, bit_lands)
|
94
|
+
# dfs
|
95
|
+
dfs(n + 1 , spells, lands, bit_spells, bit_lands, price + spell.price)
|
96
|
+
else
|
97
|
+
[nil, nil, nil]
|
98
|
+
end
|
99
|
+
|
100
|
+
# not cast case
|
101
|
+
b_price, b_bit_spells, b_bit_lands =
|
102
|
+
dfs(n + 1 , spells, lands, bit_spells, bit_lands, price)
|
103
|
+
|
104
|
+
if (a_price and a_price >= b_price)
|
105
|
+
[a_price, a_bit_spells, a_bit_lands]
|
106
|
+
else
|
107
|
+
[b_price, b_bit_spells, b_bit_lands]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
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
|
+
def bit_select(cards, bit)
|
123
|
+
cards.length.times
|
124
|
+
.map { |i| cards[i] if (bit & (1 << i) > 0) }
|
125
|
+
.select { |o| o }
|
126
|
+
end
|
127
|
+
|
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
|
+
def lands(list)
|
152
|
+
list.select do |card|
|
153
|
+
card.types.include? "Land"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def spells(list)
|
158
|
+
list.select do |card|
|
159
|
+
not card.types.include? "Land"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Simulator
|
2
|
+
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
@config.simulations.times do
|
9
|
+
game = Game.new(@config.deck)
|
10
|
+
@config.turns.times do |i|
|
11
|
+
turn = i + 1
|
12
|
+
game.step turn
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class SimulatorConfig
|
19
|
+
attr_accessor :simulations, :turns, :deck
|
20
|
+
end
|
data/lib/manasimu.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
|
4
|
+
require_relative './manasimu/card.rb'
|
5
|
+
require_relative './manasimu/planner.rb'
|
6
|
+
require_relative './manasimu/game.rb'
|
7
|
+
require_relative './manasimu/simulator.rb'
|
8
|
+
require_relative './manasimu/data.rb'
|
9
|
+
require_relative '../ext/ford_fulkerson.so'
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: manasimu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- so1itaryrove
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: mtg arrena mana curve simulator
|
14
|
+
email: so1itaryrove@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- db/AllPrintings.sqlite
|
20
|
+
- ext/ford_fulkerson.so
|
21
|
+
- lib/manasimu.rb
|
22
|
+
- lib/manasimu/card.rb
|
23
|
+
- lib/manasimu/data.rb
|
24
|
+
- lib/manasimu/game.rb
|
25
|
+
- lib/manasimu/hello.rb
|
26
|
+
- lib/manasimu/mana_type.rb
|
27
|
+
- lib/manasimu/planner.rb
|
28
|
+
- lib/manasimu/simulator.rb
|
29
|
+
homepage:
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.1.2
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: mtg arrena mana curve simulator
|
52
|
+
test_files: []
|