battlesnake 0.1.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.
@@ -0,0 +1,142 @@
1
+ require 'json'
2
+
3
+ module Battlesnake
4
+ ##
5
+ # Represents a pair of (x,y) coordinates, and provides helper methods
6
+ # for managing distance and direction.
7
+ class Location
8
+ # @return [Integer] a positive integer representing the distance from the
9
+ # left side of the board.
10
+ attr_reader :x
11
+
12
+ # @return [Integer] a positive integer representing the distance from the
13
+ # bottom of the board.
14
+ attr_reader :y
15
+
16
+ # @return [Hash] coordinates as a hash, for integration with other objects.
17
+ attr_reader :as_json
18
+
19
+ # Valid directions.
20
+ DIRECTIONS = ['up', 'down', 'right', 'left']
21
+
22
+ ##
23
+ # Instantiates with the given (x,y) coordinates. Coordinates can be:
24
+ # * a hash containing "x" and "y" keys
25
+ # * a JSON string that parses to such a hash
26
+ # * an array containing (x,y) coordinates
27
+ # * two separate (x,y) parameters
28
+ #
29
+ # @param coordinates [Hash, Array, String] the coordinates
30
+ #
31
+ # @return [Location] a new location object with (x,y) coordinates set.
32
+ def initialize(*coordinates)
33
+ set_xy(*coordinates)
34
+
35
+ @as_json = {'x' => x, 'y' => y}
36
+ end
37
+
38
+ ##
39
+ # Convenience method to return (x,y) coordinates as an array.
40
+ #
41
+ # @return [Array]
42
+ def coords
43
+ return @coords if defined?(@coords)
44
+ @coords = [x, y]
45
+ end
46
+
47
+ ##
48
+ # Calculate the distance from this instance to another.
49
+ #
50
+ # @param location [Location] another Location instance.
51
+ #
52
+ # @return [Integer] the number of blocks away, in "manhattan distance".
53
+ def distance(location)
54
+ [delta_x(location).abs, delta_y(location).abs].reduce(:+)
55
+ end
56
+
57
+ ##
58
+ # Determine the most prominent orthoganal direction [see DIRECTIONS]
59
+ # toward another location.
60
+ #
61
+ # @note Returns _nil_ if the locations are the same. Favors "up" or "down"
62
+ # if horizontal and vertical distances are the same.
63
+ #
64
+ # @param location [Location] another location instance.
65
+ #
66
+ # @return [one of DIRECTIONS]
67
+ def direction(location)
68
+ return nil if distance(location) == 0
69
+
70
+ dx = delta_x(location)
71
+ dy = delta_y(location)
72
+
73
+ if dx.abs <= dy.abs
74
+ dy > 0 ? 'up' : 'down'
75
+ elsif dx.abs > dy.abs
76
+ dx > 0 ? 'right' : 'left'
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Return a new location instance with coordinates moved one step in the requested direction.
82
+ #
83
+ # @note Returns _nil_ if the requested direction is not recognized.
84
+ #
85
+ # @param requested_direction [one of DIRECTIONS]
86
+ #
87
+ # @return [Location] a new location instance.
88
+ def move(requested_direction)
89
+ return nil unless DIRECTIONS.include?(requested_direction)
90
+
91
+ new_x = x
92
+ new_y = y
93
+
94
+ case requested_direction
95
+ when 'right'
96
+ new_x += 1
97
+ when 'left'
98
+ new_x -= 1
99
+ when 'up'
100
+ new_y += 1
101
+ when 'down'
102
+ new_y -= 1
103
+ end
104
+
105
+ self.class.new(new_x, new_y)
106
+ end
107
+
108
+ private
109
+
110
+ def set_xy(*coordinates)
111
+ unless coordinates.is_a?(Array) && coordinates.size == 2
112
+ coordinates = coordinates.first
113
+ end
114
+
115
+ case coordinates
116
+ when Hash
117
+ hash_to_xy(coordinates)
118
+ when String
119
+ hash_to_xy(JSON.parse(coordinates))
120
+ when Array
121
+ array_to_xy(coordinates)
122
+ end
123
+ end
124
+
125
+ def hash_to_xy(coordinates)
126
+ @x = coordinates['x']
127
+ @y = coordinates['y']
128
+ end
129
+
130
+ def array_to_xy(coordinates)
131
+ @x, @y = coordinates
132
+ end
133
+
134
+ def delta_x(location)
135
+ location.x - x
136
+ end
137
+
138
+ def delta_y(location)
139
+ location.y - y
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,74 @@
1
+ require 'json'
2
+
3
+ module Battlesnake
4
+ ##
5
+ # Represents a single Battlesnake player.
6
+ class Snake
7
+ # @return [Hash] snake as a data structure usable by other objects.
8
+ attr_reader :as_json
9
+
10
+ # @return [String] unique string which identifies the player.
11
+ attr_reader :id
12
+
13
+ # @return [String] name of the player.
14
+ attr_reader :name
15
+
16
+ # @return [Array<Location>] locations occupied by the body of the snake.
17
+ attr_reader :body
18
+
19
+ # @return [Integer] latency of given player's API, _nil_ if not provided.
20
+ attr_reader :latency
21
+
22
+ # @return [Integer] health value between 0 and 100.
23
+ attr_reader :health
24
+
25
+ # @return [Location] location of snake head. Should be the same as body[0].
26
+ attr_reader :head
27
+
28
+ # @return [Integer] number of locations occupied by snake body.
29
+ attr_reader :length
30
+
31
+ # @return [String] message to other players.
32
+ attr_reader :shout
33
+
34
+ # @return [String] squad identifer for games played with teams.
35
+ attr_reader :squad
36
+
37
+ # @return [Hash] display customizations.
38
+ attr_reader :customizations
39
+
40
+ ##
41
+ # Returns a new instance of Snake.
42
+ #
43
+ # @param json_or_hash [String,Hash] can be a hash of attributes, or a JSON string which
44
+ # represents such a structure.
45
+ #
46
+ # @return [Snake]
47
+ def initialize(json_or_hash)
48
+ @as_json = json_or_hash.is_a?(String) ? JSON.parse(json_or_hash) : json_or_hash
49
+
50
+ @id = @as_json['id']
51
+ @name = @as_json['name']
52
+ @latency = @as_json['latency'].empty? ? nil : @as_json['latency'].to_i
53
+ @health = @as_json['health']
54
+ @length = @as_json['length']
55
+ @shout = @as_json['shout']
56
+ @squad = @as_json['squad']
57
+ @customizations = @as_json['customizations']
58
+
59
+ @body = @as_json['body'].map{ |coords| Location.new(coords) }
60
+ @head = Location.new(@as_json['head'])
61
+ end
62
+
63
+ ##
64
+ # The current direction the snake is facing, based on the first two segments
65
+ # of the body. If snake only has a head, no direction can be determined, so
66
+ # _nil_ is returned.
67
+ #
68
+ # @return [String] one of (up, down, left, right)
69
+ def direction
70
+ return @direction if defined?(@direction)
71
+ @direction = length > 1 ? body[1].direction(head) : nil
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,4 @@
1
+ module Battlesnake
2
+ # The current version of the driver.
3
+ VERSION = "0.1.0"
4
+ end
@@ -0,0 +1,11 @@
1
+ require "battlesnake/version"
2
+ require 'battlesnake/location'
3
+ require 'battlesnake/snake'
4
+
5
+ ##
6
+ # Primary namespace for the battlesnake gem.
7
+ module Battlesnake
8
+ ##
9
+ # Default error class for Battlesnake.
10
+ class Error < StandardError; end
11
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: battlesnake
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jaime Bellmyer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.12.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.12.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: guard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.18.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.18.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 4.7.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 4.7.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.28
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.28
69
+ - !ruby/object:Gem::Dependency
70
+ name: fabrication
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.30.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.30.0
83
+ description: Focus on strategy, rather than the low-level mapping of JSON objects.
84
+ email:
85
+ - ruby@bellmyer.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".yardopts"
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - Gemfile.lock
96
+ - Guardfile
97
+ - README.md
98
+ - Rakefile
99
+ - battlesnake.gemspec
100
+ - bin/console
101
+ - bin/setup
102
+ - docs/Battlesnake.html
103
+ - docs/Battlesnake/Error.html
104
+ - docs/Battlesnake/Location.html
105
+ - docs/Battlesnake/Snake.html
106
+ - docs/_index.html
107
+ - docs/class_list.html
108
+ - docs/css/common.css
109
+ - docs/css/full_list.css
110
+ - docs/css/style.css
111
+ - docs/file.README.html
112
+ - docs/file_list.html
113
+ - docs/frames.html
114
+ - docs/index.html
115
+ - docs/js/app.js
116
+ - docs/js/full_list.js
117
+ - docs/js/jquery.js
118
+ - docs/method_list.html
119
+ - docs/top-level-namespace.html
120
+ - lib/battlesnake.rb
121
+ - lib/battlesnake/location.rb
122
+ - lib/battlesnake/snake.rb
123
+ - lib/battlesnake/version.rb
124
+ homepage: https://github.com/bellmyer/battlesnake
125
+ licenses: []
126
+ metadata:
127
+ homepage_uri: https://github.com/bellmyer/battlesnake
128
+ source_code_uri: https://github.com/bellmyer/battlesnake
129
+ changelog_uri: https://github.com/bellmyer/battlesnake/CHANGELOG.md
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.3.0
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubygems_version: 3.1.4
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Object modeling and helpful methods for building Battlesnake players.
149
+ test_files: []