manasimu 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|