Module: Sc2::Position

Included in:
Api::Point, Api::Point2D, Api::PointI, Api::PowerSourceExtension, Api::Size2DI
Defined in:
lib/sc2ai/protocol/extensions/position.rb

Overview

A unified construct that tames Api::* messages which contain location data Items which are of type Sc2::Position will have #x and #y property at the least.

Constant Summary collapse

TOLERANCE =

Tolerance for floating-point comparisons.

1e-9

Instance Method Summary collapse

Instance Method Details

#==(other) ⇒ Object

Loose equality matches on floats x and y. We never check z-axis, because the map is single-level. TODO: We should almost certainly introduce TOLERANCE here, but verify it’s cost first.



13
14
15
16
17
18
19
# File 'lib/sc2ai/protocol/extensions/position.rb', line 13

def ==(other)
  if other.is_a? Position
    x == other.x && y == other.y
  else
    false
  end
end

#add(other) ⇒ Api::Point2D Also known as: +

A new point representing the sum of this point and the other point.

Parameters:

  • other (Api::Point2D, Numeric)

    The other point/number to add.

Returns:



24
25
26
27
28
29
30
# File 'lib/sc2ai/protocol/extensions/position.rb', line 24

def add(other)
  if other.is_a? Numeric
    Api::Point2D[x + other, y + other]
  else
    Api::Point2D[x + other.x, y + other.y]
  end
end

#angle_to(other) ⇒ Float

The angle between this vector and the other vector, in radians.

Parameters:

  • other (Api::Point2D)

    The other vector to calculate the angle to.

Returns:

  • (Float)


152
153
154
# File 'lib/sc2ai/protocol/extensions/position.rb', line 152

def angle_to(other)
  Math.acos(dot(other) / (magnitude * other.magnitude))
end

#away_from(other, distance) ⇒ Api::Point2D

Moves in direction away from the other point by distance

Parameters:

  • other (Api::Point2D)

    The target point to move away from

  • distance (Float)

    The distance to move.

Returns:



228
229
230
# File 'lib/sc2ai/protocol/extensions/position.rb', line 228

def away_from(other, distance)
  towards(other, -distance)
end

#cross_product(other) ⇒ Float

The cross product of this vector and the other vector.

Parameters:

  • other (Api::Point2D)

    The other vector to calculate the cross product with.

Returns:

  • (Float)


145
146
147
# File 'lib/sc2ai/protocol/extensions/position.rb', line 145

def cross_product(other)
  x * other.y - y * other.x
end

#distance_squared_to(other) ⇒ Float

The squared distance between this point and the other point.

Parameters:

  • other (Point2D)

    The other point to calculate the squared distance to.

Returns:

  • (Float)


187
188
189
190
191
192
# File 'lib/sc2ai/protocol/extensions/position.rb', line 187

def distance_squared_to(other)
  if other.nil? || other == self
    return 0.0
  end
  (x - other.x) * (y - other.y)
end

#distance_to(other) ⇒ Float

Calculates the distance between self and other

Parameters:

Returns:

  • (Float)


177
178
179
180
181
182
# File 'lib/sc2ai/protocol/extensions/position.rb', line 177

def distance_to(other)
  if other.nil? || other == self
    return 0.0
  end
  Math.hypot(self.x - other.x, self.y - other.y)
end

#distance_to_circle(center, radius) ⇒ Float

The distance from this point to the circle.

Parameters:

  • center (Point2D)

    The center of the circle.

  • radius (Float)

    The radius of the circle.

Returns:

  • (Float)


204
205
206
207
208
209
210
211
# File 'lib/sc2ai/protocol/extensions/position.rb', line 204

def distance_to_circle(center, radius)
  distance_to_center = distance_to(center)
  if distance_to_center <= radius
    0.0 # Point is inside the circle
  else
    distance_to_center - radius
  end
end

#distance_to_coordinate(x:, y:) ⇒ Float

Distance between this point and coordinate of x and y

Returns:

  • (Float)


196
197
198
# File 'lib/sc2ai/protocol/extensions/position.rb', line 196

def distance_to_coordinate(x:, y:)
  Math.hypot(self.x - x, self.y - y)
end

#divide(scalar) ⇒ Api::Point2D Also known as: /

Returns A new point representing this point divided by the scalar.

Parameters:

  • scalar (Float)

    The scalar to divide by.

Returns:

  • (Api::Point2D)

    A new point representing this point divided by the scalar.

Raises:

  • (ZeroDivisionError)

    if the scalar is zero.



57
58
59
60
# File 'lib/sc2ai/protocol/extensions/position.rb', line 57

def divide(scalar)
  raise ZeroDivisionError if scalar.zero?
  Api::Point2D[x / scalar, y / scalar]
end

#dot(other) ⇒ Float

The dot product of this vector and the other vector.

Parameters:

  • other (Api::Point2D)

    The other vector to calculate the dot product with.

Returns:

  • (Float)


138
139
140
# File 'lib/sc2ai/protocol/extensions/position.rb', line 138

def dot(other)
  x * other.x + y * other.y
end

#lerp(other, scale) ⇒ Api::Point2D

Linear interpolation between this point and another for scale Finds a point on a line between two points at % along the way. 0.0 returns self, 1.0 returns other, 0.5 is halfway.

Parameters:

  • scale (Float)

    a value between 0.0..1.0

Returns:



168
169
170
# File 'lib/sc2ai/protocol/extensions/position.rb', line 168

def lerp(other, scale)
  Api::Point2D[x + (other.x - x) * scale, y + (other.y - y) * scale]
end

#magnitudeFloat

For vector returns the magnitude, synonymous with Math.hypot

Returns:

  • (Float)


131
132
133
# File 'lib/sc2ai/protocol/extensions/position.rb', line 131

def magnitude
  Math.hypot(x, y)
end

#multiply(scalar) ⇒ Api::Point2D Also known as: *

Returns this point multiplied by the scalar

Parameters:

  • scalar (Float)

    The scalar to multiply by.

Returns:



48
49
50
# File 'lib/sc2ai/protocol/extensions/position.rb', line 48

def multiply(scalar)
  Api::Point2D[x * scalar, y * scalar]
end

#normalizeApi::Point2D

A new point representing the normalized version of this vector (unit length).

Returns:



158
159
160
# File 'lib/sc2ai/protocol/extensions/position.rb', line 158

def normalize
  divide(magnitude)
end

#offset(x = 0, y = 0) ⇒ Sc2::Position

Creates a new point with x and y which is offset

Returns:



115
116
117
# File 'lib/sc2ai/protocol/extensions/position.rb', line 115

def offset(x = 0, y = 0)
  dup.offset!(x, y)
end

#offset!(x = 0, y = 0) ⇒ Sc2::Position

Changes this point’s x and y by the supplied offset

Returns:



121
122
123
124
125
# File 'lib/sc2ai/protocol/extensions/position.rb', line 121

def offset!(x = 0, y = 0)
  self.x += x
  self.y += y
  self
end

#random_offset(offset) ⇒ Sc2::Position

Randomly adjusts both x and y by a range of: -offset..offset

Parameters:

  • offset (Float)

Returns:



100
101
102
# File 'lib/sc2ai/protocol/extensions/position.rb', line 100

def random_offset(offset)
  dup.random_offset!(offset)
end

#random_offset!(offset) ⇒ Sc2::Position

Changes this point’s x and y by the supplied offset

Returns:



106
107
108
109
110
111
# File 'lib/sc2ai/protocol/extensions/position.rb', line 106

def random_offset!(offset)
  offset = offset.to_f
  range = -offset..offset
  offset!(rand(range), rand(range))
  self
end

#subtract(other) ⇒ Api::Point2D Also known as: -

Returns a new point representing the difference between this point and the other point/number.

Parameters:

Returns:



36
37
38
39
40
41
42
# File 'lib/sc2ai/protocol/extensions/position.rb', line 36

def subtract(other)
  if other.is_a? Numeric
    Api::Point2D[x - other, y - other]
  else
    Api::Point2D[x - other.x, y - other.y]
  end
end

#towards(other, distance) ⇒ Api::Point2D

Moves in direction towards other point by distance

Parameters:

  • other (Api::Point2D)

    The target point to move to.

  • distance (Float)

    The distance to move.

Returns:



219
220
221
222
# File 'lib/sc2ai/protocol/extensions/position.rb', line 219

def towards(other, distance)
  direction = other.subtract(self).normalize
  add(direction.multiply(distance))
end

#xFloat

Returns x coordinate

Returns:

  • (Float)


66
67
68
69
# File 'lib/sc2ai/protocol/extensions/position.rb', line 66

def x
  # Perf: Memoizing attributes which are hit hard, show gain
  @x ||= send(:method_missing, :x)
end

#x=(x) ⇒ Float

Sets x coordinate

Returns:

  • (Float)


73
74
75
76
# File 'lib/sc2ai/protocol/extensions/position.rb', line 73

def x=(x)
  send(:method_missing, :x=, x)
  @x = x
end

#yFloat

Returns y coordinate

Returns:

  • (Float)


80
81
82
83
84
85
86
87
88
# File 'lib/sc2ai/protocol/extensions/position.rb', line 80

def y
  # Bug: Psych implements method 'y' on Kernel, but protobuf uses method_missing to read AbstractMethod
  # We send method missing ourselves when y to fix this chain.
  # This is correct, but an unnecessary conditional:
  # raise NoMethodError unless location == self

  # Perf: Memoizing attributes which are hit hard, show gain
  @y ||= send(:method_missing, :y)
end

#y=(y) ⇒ Float

Sets y coordinate

Returns:

  • (Float)


92
93
94
95
# File 'lib/sc2ai/protocol/extensions/position.rb', line 92

def y=(y)
  send(:method_missing, :y=, y)
  @y = y
end