sc2ai 0.6.5 → 0.8.0

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.
@@ -39,9 +39,50 @@ module Api
39
39
  new_unit = @bot.all_units[tag]
40
40
  return false if new_unit.nil? || new_unit == self
41
41
 
42
- method(:initialize).parameters.each do |_, entry|
43
- send(:"#{entry.name}=", new_unit.send(entry))
44
- end
42
+ self.display_type = new_unit.display_type
43
+ self.alliance = new_unit.alliance
44
+ self.tag = new_unit.tag
45
+ self.unit_type = new_unit.unit_type
46
+ self.owner = new_unit.owner
47
+ self.pos = new_unit.pos
48
+ self.facing = new_unit.facing
49
+ self.radius = new_unit.radius
50
+ self.build_progress = new_unit.build_progress
51
+ self.cloak = new_unit.cloak
52
+ self.buff_ids = new_unit.buff_ids
53
+ self.detect_range = new_unit.detect_range
54
+ self.radar_range = new_unit.radar_range
55
+ self.is_selected = new_unit.is_selected
56
+ self.is_on_screen = new_unit.is_on_screen
57
+ self.is_blip = new_unit.is_blip
58
+ self.is_powered = new_unit.is_powered
59
+ self.is_active = new_unit.is_active
60
+ self.attack_upgrade_level = new_unit.attack_upgrade_level
61
+ self.armor_upgrade_level = new_unit.armor_upgrade_level
62
+ self.shield_upgrade_level = new_unit.shield_upgrade_level
63
+ self.health = new_unit.health
64
+ self.health_max = new_unit.health_max
65
+ self.shield = new_unit.shield
66
+ self.shield_max = new_unit.shield_max
67
+ self.energy = new_unit.energy
68
+ self.energy_max = new_unit.energy_max
69
+ self.mineral_contents = new_unit.mineral_contents
70
+ self.vespene_contents = new_unit.vespene_contents
71
+ self.is_flying = new_unit.is_flying
72
+ self.is_burrowed = new_unit.is_burrowed
73
+ self.is_hallucination = new_unit.is_hallucination
74
+ self.orders = new_unit.orders
75
+ self.add_on_tag = new_unit.add_on_tag
76
+ self.passengers = new_unit.passengers
77
+ self.cargo_space_taken = new_unit.cargo_space_taken
78
+ self.cargo_space_max = new_unit.cargo_space_max
79
+ self.assigned_harvesters = new_unit.assigned_harvesters
80
+ self.ideal_harvesters = new_unit.ideal_harvesters
81
+ self.weapon_cooldown = new_unit.weapon_cooldown
82
+ self.engaged_target_tag = new_unit.engaged_target_tag
83
+ self.buff_duration_remain = new_unit.buff_duration_remain
84
+ self.buff_duration_max = new_unit.buff_duration_max
85
+ self.rally_targets = new_unit.rally_targets
45
86
 
46
87
  true
47
88
  end
@@ -157,6 +198,24 @@ module Api
157
198
  energy == energy_max
158
199
  end
159
200
 
201
+ # Returns whether this is a melee (non-ranged) attacker
202
+ # Archon isn't melee; 3 range
203
+ # Hellbat is melee, but Hellion isn't melee; 5 range
204
+ # Roach isn't melee; just an attack animation when nearby
205
+ # @!attribute [r] is_melee?
206
+ # @return [Boolean] melee unit (non-ranged attacker)
207
+ def is_melee?
208
+ Sc2::UnitGroup::TYPE_MELEE.include?(unit_type)
209
+ end
210
+
211
+ # Returns ranged attack units
212
+ # @see Sc2::UnitGroup::TYPE_RANGE
213
+ # @!attribute [r] is_ranged?
214
+ # @return [Boolean] if reasonably considered a ranged attacker
215
+ def is_ranged?
216
+ Sc2::UnitGroup::TYPE_RANGE.include?(unit_type)
217
+ end
218
+
160
219
  # Some overrides to allow question mark references to boolean properties
161
220
 
162
221
  # @!attribute [r] is_flying?
@@ -593,7 +652,7 @@ module Api
593
652
  Api::UnitTypeId::STARPORTREACTOR
594
653
  end
595
654
 
596
- build(unit_type_id: unit_type_id, target: target_for_addon_placement, queue_command:)
655
+ build(unit_type_id: unit_type_id, target:, queue_command:)
597
656
  end
598
657
 
599
658
  # For Terran builds a tech lab add-on on the current structure
@@ -607,21 +666,7 @@ module Api
607
666
  when Api::UnitTypeId::STARPORT, Api::UnitTypeId::STARPORTFLYING
608
667
  Api::UnitTypeId::STARPORTTECHLAB
609
668
  end
610
- build(unit_type_id: unit_type_id, target: target_for_addon_placement, queue_command:)
611
- end
612
-
613
- private def target_for_addon_placement
614
- # Attempts to auto-move left if not placeable
615
- x = pos.x.floor
616
- y = pos.y.floor
617
- if !bot.geo.placeable?(x: x + 3, y: y - 1) ||
618
- !bot.geo.placeable?(x: x + 3, y: y) ||
619
- !bot.geo.placeable?(x: x + 2, y: y - 1) ||
620
- !bot.geo.placeable?(x: x + 2, y: y)
621
- return Api::Point2D[pos.x - 1, pos.y]
622
- end
623
-
624
- nil
669
+ build(unit_type_id: unit_type_id, target:, queue_command:)
625
670
  end
626
671
 
627
672
  # PROTOSS Convenience functions ---
@@ -0,0 +1,134 @@
1
+ module Sc2
2
+ # Tracks various metrics about your step time performance.
3
+ class StepTimer
4
+ TRUNCATED_TIME_RANGE = 0..999.99
5
+ HEALTHY_STEP_TIME_MS = (1000.0 / 22.4)
6
+ private_constant :TRUNCATED_TIME_RANGE, :HEALTHY_STEP_TIME_MS
7
+
8
+ # @!attribute [r] avg_real_time
9
+ # @return [Float] Realtime average time per step in ms. Includes SC2 wait time
10
+ attr_reader :avg_real_time
11
+
12
+ # @!attribute [r] avg_step_time
13
+ # @return [Float] Total average time per step in ms. "Ladder Time" as measured by aiarena
14
+ attr_reader :avg_step_time
15
+
16
+ # @!attribute [r] recent_average
17
+ # @return [Float] Running average time per step in ms for recent couple of steps
18
+ attr_accessor :avg_recent_step_time
19
+
20
+ # @!attribute [r] previous_on_step_time
21
+ # @return [Float] Previous on_step took this amount of ms to run
22
+ attr_reader :previous_on_step_time
23
+
24
+ # @!attribute [r] previous_on_step_count
25
+ # @return [Integer] Number of frames which passed previous on_step
26
+ attr_reader :previous_on_step_count
27
+
28
+ # @private
29
+ private attr_accessor :bot
30
+ # @private
31
+ private attr_accessor :previous_external_time, :previous_update_time
32
+ # @private
33
+ private attr_accessor :recent_sum_time, :recent_sum_steps, :recent_update_counter
34
+
35
+ # @private
36
+ # @param bot [Sc2::Player]
37
+ def initialize(bot)
38
+ @bot = bot
39
+
40
+ # Tracking vars
41
+ @previous_external_time = @bot.api.external_time
42
+ @previous_update_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
43
+ @recent_update_counter = 0
44
+ @recent_sum_steps = 0
45
+ @recent_sum_time = 0.0
46
+ @total_step_time = 0.0
47
+ @total_real_time = 0.0
48
+
49
+ # Output vars
50
+ @avg_real_time = 0.0
51
+ @avg_step_time = 0.0
52
+ @avg_recent_step_time = 0.0
53
+ @previous_on_step_time = 0.0
54
+ @previous_on_step_count = 0
55
+ end
56
+
57
+ # How much time we have left in this step, to be healthy
58
+ def allowance
59
+ return 0.0 if @bot.realtime
60
+ time_passed = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @previous_update_time
61
+ external_delta = @bot.api.external_time - @previous_external_time
62
+ (HEALTHY_STEP_TIME_MS * @bot.step_count) - (time_passed - external_delta)
63
+ end
64
+
65
+ # A one-line string summary of all tracked times
66
+ # @return [String]
67
+ def summary
68
+ "AVG Real: #{format_time(@avg_real_time)} | " \
69
+ "AVG Total: #{format_time(@avg_step_time)} | " \
70
+ "AVG Recent: #{format_time(@avg_recent_step_time)} | " \
71
+ "Previous #{@previous_on_step_count} Step(s): #{format_time(@previous_on_step_time)} (ms)"
72
+ end
73
+
74
+ # A hash containing :avg_real_time, :avg_step_time, :avg_recent_step_time, :previous_on_step_count, :previous_on_step_time
75
+ # @return [Hash]
76
+ def to_h
77
+ {
78
+ avg_real_time: avg_real_time,
79
+ avg_step_time: avg_step_time,
80
+ avg_recent_step_time: avg_recent_step_time,
81
+ previous_on_step_count: previous_on_step_count,
82
+ previous_on_step_time: previous_on_step_time
83
+ }
84
+ end
85
+
86
+ def update
87
+ # Number of steps which have passed
88
+ step_delta = @bot.game_loop - @bot.previous.game_loop
89
+
90
+ # Time spent waiting for SC2 is not counted on ladder
91
+ external_time = @bot.api.external_time
92
+ external_delta = external_time - @previous_external_time
93
+ @previous_external_time = external_time
94
+
95
+ # Start calculating...
96
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
97
+
98
+ time_delta = now - @previous_update_time
99
+ @previous_update_time = now
100
+
101
+ # Update real time
102
+ @total_real_time += time_delta
103
+
104
+ # Update step time (excl external)
105
+ time_delta -= external_delta
106
+ @total_step_time += time_delta
107
+
108
+ # Write public values...
109
+ @previous_on_step_time = time_delta
110
+ @previous_on_step_count = step_delta
111
+ @avg_real_time = @total_real_time / (@bot.game_loop + 1)
112
+ @avg_step_time = @total_step_time / (@bot.game_loop + 1)
113
+
114
+ @recent_sum_time += time_delta
115
+ @recent_sum_steps += step_delta
116
+ if @recent_update_counter >= 11
117
+ @avg_recent_step_time = @recent_sum_time / @recent_sum_steps
118
+
119
+ @recent_sum_time = 0.0
120
+ @recent_sum_steps = 0
121
+ @recent_update_counter = 0
122
+ end
123
+ @recent_update_counter += 1
124
+ end
125
+
126
+ private
127
+
128
+ # @private
129
+ # @return [String] time with ansi colour coded
130
+ def format_time(time)
131
+ "%5.2f" % time.clamp(TRUNCATED_TIME_RANGE)
132
+ end
133
+ end
134
+ end
@@ -7,7 +7,7 @@ module Sc2
7
7
  # Returns nil if units are empty, so use safety operator bot&.method(...)
8
8
  # @return [Sc2::Player, nil] player with active connection
9
9
  def bot
10
- first&.bot
10
+ @bot ||= first&.bot
11
11
  end
12
12
 
13
13
  # Performs action on all units in this group
@@ -97,6 +97,145 @@ module Sc2
97
97
  Api::UnitTypeId::ADEPT
98
98
  ].freeze
99
99
 
100
+ # An array of all melee units
101
+ # @return [Array<Integer>]
102
+ TYPE_MELEE = [
103
+ Api::UnitTypeId::SCV,
104
+ Api::UnitTypeId::HELLIONTANK,
105
+ Api::UnitTypeId::PROBE,
106
+ Api::UnitTypeId::DARKTEMPLAR,
107
+ Api::UnitTypeId::ZEALOT,
108
+ Api::UnitTypeId::DRONE,
109
+ Api::UnitTypeId::DRONEBURROWED,
110
+ Api::UnitTypeId::ZERGLING,
111
+ Api::UnitTypeId::ZERGLINGBURROWED,
112
+ Api::UnitTypeId::BANELING,
113
+ Api::UnitTypeId::BANELINGBURROWED,
114
+ Api::UnitTypeId::ULTRALISK,
115
+ Api::UnitTypeId::ULTRALISKBURROWED,
116
+ Api::UnitTypeId::BROODLING
117
+ ].freeze
118
+
119
+ # Typical units you would consider to be Ranged Units
120
+ # Includes: BROODLORD and CARRIER even though they spawn units
121
+ # and don't attack by themselves. ORACLE. and all BURROWED variants of units.
122
+ # Excludes strict spellcasters: MEDIVAC, RAVEN, INFESTOR, SWARMHOSTMP, DISRUPTOR
123
+ TYPE_RANGE = [
124
+ # Terran
125
+ Api::UnitTypeId::MARINE,
126
+ Api::UnitTypeId::MARAUDER,
127
+ Api::UnitTypeId::REAPER,
128
+ Api::UnitTypeId::GHOST,
129
+ Api::UnitTypeId::HELLION,
130
+ Api::UnitTypeId::WIDOWMINE,
131
+ Api::UnitTypeId::WIDOWMINEBURROWED,
132
+ Api::UnitTypeId::SIEGETANK,
133
+ Api::UnitTypeId::SIEGETANKSIEGED,
134
+ Api::UnitTypeId::CYCLONE,
135
+ Api::UnitTypeId::THOR,
136
+ Api::UnitTypeId::THORAP,
137
+ Api::UnitTypeId::VIKINGASSAULT,
138
+ Api::UnitTypeId::VIKINGFIGHTER,
139
+ Api::UnitTypeId::AUTOTURRET,
140
+ Api::UnitTypeId::BANSHEE,
141
+ Api::UnitTypeId::BATTLECRUISER,
142
+ Api::UnitTypeId::LIBERATOR,
143
+ Api::UnitTypeId::LIBERATORAG,
144
+ Api::UnitTypeId::MISSILETURRET,
145
+
146
+ # Zerg
147
+ Api::UnitTypeId::ROACH,
148
+ Api::UnitTypeId::ROACHBURROWED,
149
+ Api::UnitTypeId::RAVAGER,
150
+ Api::UnitTypeId::RAVAGERBURROWED,
151
+ Api::UnitTypeId::HYDRALISK,
152
+ Api::UnitTypeId::HYDRALISKBURROWED,
153
+ Api::UnitTypeId::MUTALISK,
154
+ Api::UnitTypeId::CORRUPTOR,
155
+ Api::UnitTypeId::BROODLORD,
156
+ Api::UnitTypeId::QUEEN,
157
+ Api::UnitTypeId::QUEENBURROWED,
158
+ Api::UnitTypeId::LURKERMP,
159
+ Api::UnitTypeId::LURKERMPBURROWED,
160
+ Api::UnitTypeId::LOCUSTMP,
161
+ Api::UnitTypeId::SPINECRAWLER,
162
+ Api::UnitTypeId::SPINECRAWLERUPROOTED,
163
+ Api::UnitTypeId::SPORECRAWLER,
164
+ Api::UnitTypeId::SPORECRAWLERUPROOTED,
165
+
166
+ # Protoss
167
+ Api::UnitTypeId::SENTRY,
168
+ Api::UnitTypeId::STALKER,
169
+ Api::UnitTypeId::IMMORTAL,
170
+ Api::UnitTypeId::ARCHON,
171
+ Api::UnitTypeId::HIGHTEMPLAR,
172
+ Api::UnitTypeId::ADEPT,
173
+ Api::UnitTypeId::ORACLE,
174
+ Api::UnitTypeId::PHOENIX,
175
+ Api::UnitTypeId::VOIDRAY,
176
+ Api::UnitTypeId::TEMPEST,
177
+ Api::UnitTypeId::INTERCEPTOR,
178
+ Api::UnitTypeId::CARRIER,
179
+ Api::UnitTypeId::MOTHERSHIP,
180
+ Api::UnitTypeId::PHOTONCANNON
181
+ ].freeze
182
+
183
+ # Terran: An array if infantry (Barracks) unit types
184
+ # @return [Array<Integer>]
185
+ TYPE_TERRAN_INFANTRY = [
186
+ Api::UnitTypeId::REAPER,
187
+ Api::UnitTypeId::MARINE,
188
+ Api::UnitTypeId::MARAUDER,
189
+ Api::UnitTypeId::GHOST
190
+ ].freeze
191
+
192
+ # Terran: An array if vehicle (Factory) unit types
193
+ # @return [Array<Integer>]
194
+ TYPE_TERRAN_VEHICLE = [
195
+ Api::UnitTypeId::HELLION,
196
+ Api::UnitTypeId::HELLIONTANK,
197
+ Api::UnitTypeId::WIDOWMINE,
198
+ Api::UnitTypeId::WIDOWMINEBURROWED,
199
+ Api::UnitTypeId::SIEGETANK,
200
+ Api::UnitTypeId::SIEGETANKSIEGED,
201
+ Api::UnitTypeId::THOR,
202
+ Api::UnitTypeId::THORAP
203
+ ].freeze
204
+
205
+ # Zerg: An array unit types which are Melee and benefit from Melee upgrades
206
+ # @return [Array<Integer>]
207
+ TYPE_ZERG_MELEE = [
208
+ Api::UnitTypeId::DRONE,
209
+ Api::UnitTypeId::DRONEBURROWED,
210
+ Api::UnitTypeId::ZERGLING,
211
+ Api::UnitTypeId::ZERGLINGBURROWED,
212
+ Api::UnitTypeId::BANELING,
213
+ Api::UnitTypeId::BANELINGBURROWED,
214
+ Api::UnitTypeId::ULTRALISK,
215
+ Api::UnitTypeId::ULTRALISKBURROWED,
216
+ Api::UnitTypeId::BROODLING
217
+ ].freeze
218
+
219
+ # Zerg: An array of unit types which use missile attacks and upgrades
220
+ # @return [Array<Integer>]
221
+ TYPE_ZERG_MISSILE = [
222
+ Api::UnitTypeId::ROACH,
223
+ Api::UnitTypeId::ROACHBURROWED,
224
+ Api::UnitTypeId::RAVAGER,
225
+ Api::UnitTypeId::RAVAGERBURROWED,
226
+ Api::UnitTypeId::HYDRALISK,
227
+ Api::UnitTypeId::HYDRALISKBURROWED,
228
+ Api::UnitTypeId::QUEEN,
229
+ Api::UnitTypeId::QUEENBURROWED,
230
+ Api::UnitTypeId::LURKERMP,
231
+ Api::UnitTypeId::LURKERMPBURROWED,
232
+ Api::UnitTypeId::LOCUSTMP,
233
+ Api::UnitTypeId::SPINECRAWLER,
234
+ Api::UnitTypeId::SPINECRAWLERUPROOTED,
235
+ Api::UnitTypeId::SPORECRAWLER,
236
+ Api::UnitTypeId::SPORECRAWLERUPROOTED
237
+ ].freeze
238
+
100
239
  # Returns a new UnitGroup containing all units matching unit type id(s)
101
240
  # Multiple values work as an "OR" filter
102
241
  # @example
@@ -105,7 +244,7 @@ module Sc2
105
244
  # # Multiple - select space-men
106
245
  # ug.select_type([Api::UnitTypeId::MARINE, Api::UnitTypeId::REAPER]) #=> <UnitGroup: ...>
107
246
  # @param unit_type_ids [Integer, Array<Integer>] one or an array of unit Api::UnitTypeId
108
- # @return [UnitGroup]
247
+ # @return [Sc2::UnitGroup]
109
248
  def select_type(unit_type_ids)
110
249
  cached("#{__method__}:#{unit_type_ids.hash}") do
111
250
  if unit_type_ids.is_a? Array
@@ -123,7 +262,7 @@ module Sc2
123
262
  # # Multiple - reject immovable army
124
263
  # ug.reject_type([Api::UnitTypeId::SIEGETANKSIEGED, Api::UnitTypeId::WIDOWMINEBURROWED]) #=> <UnitGroup: ...>
125
264
  # @param unit_type_ids [Integer, Array<Integer>] one or an array of unit Api::UnitTypeId
126
- # @return [UnitGroup]
265
+ # @return [Sc2::UnitGroup]
127
266
  def reject_type(unit_type_ids)
128
267
  cached("#{__method__}:#{unit_type_ids.hash}") do
129
268
  if unit_type_ids.is_a? Array
@@ -179,7 +318,7 @@ module Sc2
179
318
  # # Multiple - select mechanical flying units
180
319
  # ug.select_attribute([:MECHANICAL, :FLYING]) #=> <UnitGroup: ...>
181
320
  # @param attributes [Integer, Array<Integer>] one or an array of unit Api::UnitTypeId
182
- # @return [UnitGroup]
321
+ # @return [Sc2::UnitGroup]
183
322
  def select_attribute(attributes)
184
323
  cached("#{__method__}:#{attributes.hash}") do
185
324
  attributes = [attributes] unless attributes.is_a? Array
@@ -199,7 +338,7 @@ module Sc2
199
338
  # # Multiple - reject mechanical flying units
200
339
  # ug.reject_attribute(:Mechanical, :Flying) #=> <UnitGroup: ...>
201
340
  # @param attributes [Integer, Array<Integer>] one or an array of unit Api::UnitTypeId
202
- # @return [UnitGroup]
341
+ # @return [Sc2::UnitGroup]
203
342
  def reject_attribute(attributes)
204
343
  cached("#{__method__}:#{attributes.hash}") do
205
344
  attributes = [attributes] unless attributes.is_a? Array
@@ -269,7 +408,7 @@ module Sc2
269
408
  alias_method :townhalls, :bases # bad name
270
409
 
271
410
  # Selects gas structures (refinery/extractor/assimilator)
272
- # @return [UnitGroup] gas structures
411
+ # @return [Sc2::UnitGroup] gas structures
273
412
  def gas
274
413
  select_type(TYPE_GAS_STRUCTURE)
275
414
  end
@@ -278,24 +417,25 @@ module Sc2
278
417
  alias_method :assimilators, :gas
279
418
 
280
419
  # Selects units passively have Detection
281
- # @return [UnitGroup] gas structures
420
+ # @return [Sc2::UnitGroup] gas structures
282
421
  def detectors
283
422
  select_type(TYPE_DETECTORS)
284
423
  end
285
424
 
286
425
  # Selects only units which have finished constructing, i.o.w. build_progress == 1.0
287
- # @return [UnitGroup] complete unit group
426
+ # @return [Sc2::UnitGroup] complete unit group
288
427
  def completed
289
428
  select(&:is_completed?)
290
429
  end
291
430
 
292
431
  # Selects only units which have finished constructing, i.o.w. build_progress != 1.0
293
- # @return [UnitGroup] incomplete unit group
432
+ # @return [Sc2::UnitGroup] incomplete unit group
294
433
  def incomplete
295
434
  reject(&:is_completed?)
296
435
  end
297
436
 
298
437
  # Selects only units which do not have orders
438
+ # @return [Sc2::UnitGroup]
299
439
  def idle
300
440
  select(&:is_idle?)
301
441
  end
@@ -303,13 +443,14 @@ module Sc2
303
443
  # Selects units which have this ability available
304
444
  # Queries API if necessary
305
445
  # @param [Integer] ability_id
306
- # @return [UnitGroup] units which have the ability available
446
+ # @return [Sc2::UnitGroup] units which have the ability available
307
447
  def ability_available?(ability_id)
308
448
  select { |unit| unit.ability_available?(ability_id) }
309
449
  end
310
450
 
311
451
  # Checks whether any unit's first order matches these abilities
312
452
  # @param ability_ids [Integer, Array<Integer>] accepts one or an array of Api::AbilityId
453
+ # @return [Boolean]
313
454
  def is_performing_ability?(ability_ids)
314
455
  any? { |unit| unit.is_performing_ability?(ability_ids) }
315
456
  end
@@ -450,7 +591,7 @@ module Sc2
450
591
  return self if amount > @units.size
451
592
  end
452
593
 
453
- if use_kdtree
594
+ if use_kdtree || use_kdtree.nil?
454
595
  if amount.nil?
455
596
  index = kdtree.nearest(pos.x, pos.y)
456
597
  return @units.values[index]
@@ -472,6 +613,7 @@ module Sc2
472
613
  # Selects units which are in a particular circle
473
614
  # @param point [Api::Point2D, Api::Point] center of circle
474
615
  # @param radius [Float]
616
+ # @return [Sc2::UnitGroup] new unit group
475
617
  def select_in_circle(point:, radius:)
476
618
  select { |unit| unit.in_circle?(point:, radius:) }
477
619
  end
@@ -10,7 +10,7 @@ module Sc2
10
10
 
11
11
  # @!attribute units
12
12
  # A hash of units by tag.
13
- # @return [Hash<Integer, Api::Unit>] Api::Unit.tag => Api::Unit
13
+ # @return [Hash<Integer, Api::Unit>] Api::Unit.tag => Api::Unit
14
14
  attr_accessor :units
15
15
 
16
16
  # @param units [Api::Unit, Hash<Integer, Api::Unit>, Array<Api::Unit>, Sc2::UnitGroup, nil] default to be added.
@@ -177,9 +177,9 @@ module Sc2
177
177
 
178
178
  # Creates a new unit group which is the result of the two being subtracted
179
179
  # @param other_unit_group [UnitGroup]
180
- # @return [UnitGroup] new unit group
180
+ # @return [Sc2::UnitGroup] new unit group
181
181
  def subtract(other_unit_group)
182
- UnitGroup.new(@units.reject { |tag, _unit| other_unit_group.units.has_key?(tag) })
182
+ slice(*(tags - other_unit_group.tags))
183
183
  end
184
184
 
185
185
  alias_method :-, :subtract
@@ -237,7 +237,7 @@ module Sc2
237
237
 
238
238
  # Returns a new unit group containing each element found both in self and in all of the given other_arrays; duplicates are omitted; items are compared using eql? (items must also implement hash correctly):
239
239
  # @param other_unit_group [UnitGroup]
240
- # @return [UnitGroup] new unit group
240
+ # @return [Sc2::UnitGroup] new unit group
241
241
  def intersection(other_unit_group)
242
242
  slice(*other_unit_group.tags)
243
243
  end
data/lib/sc2ai/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Sc2
2
2
  # gem version
3
3
  # @return [String]
4
- VERSION = "0.6.5"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/sc2ai.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "logger"
4
+
3
5
  # In the event major runs, let it compact
4
6
  GC.auto_compact = true
5
7
 
@@ -74,12 +76,9 @@ module Sc2
74
76
  def logger
75
77
  return @logger if @logger
76
78
 
77
- require "logger"
78
-
79
79
  @logger = Logger.new($stdout)
80
80
  @logger.level = :debug
81
- @logger.datetime_format = "%H:%M:%S.%6N"
82
-
81
+ @logger.datetime_format = "%H:%M:%S.%3N"
83
82
  @logger
84
83
  end
85
84
 
@@ -10,5 +10,5 @@ Sc2::Match.new(
10
10
  $bot,
11
11
  Sc2::Player::Computer.new(race: Api::Race::RANDOM, difficulty: Api::Difficulty::VERY_EASY)
12
12
  ],
13
- map: "ThunderbirdAIE" # Or any of the downloaded map names
13
+ map: "PylonAIE_v4" # Or any of the downloaded map names
14
14
  ).run