software_challenge_client 20.2.2 → 21.0.2

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.ruby-version +1 -1
  4. data/.vscode/launch.json +41 -0
  5. data/.vscode/settings.json +10 -0
  6. data/Dockerfile +1 -1
  7. data/Gemfile +1 -0
  8. data/Guardfile +1 -0
  9. data/README.md +4 -3
  10. data/RELEASES.md +20 -0
  11. data/Rakefile +4 -4
  12. data/example/client.rb +6 -9
  13. data/example/main.rb +9 -9
  14. data/lib/software_challenge_client.rb +26 -23
  15. data/lib/software_challenge_client/board.rb +99 -34
  16. data/lib/software_challenge_client/client_interface.rb +1 -0
  17. data/lib/software_challenge_client/color.rb +16 -0
  18. data/lib/software_challenge_client/condition.rb +4 -1
  19. data/lib/software_challenge_client/coordinate_set.rb +92 -0
  20. data/lib/software_challenge_client/coordinates.rb +45 -0
  21. data/lib/software_challenge_client/debug_hint.rb +1 -0
  22. data/lib/software_challenge_client/field.rb +21 -53
  23. data/lib/software_challenge_client/game_rule_logic.rb +257 -332
  24. data/lib/software_challenge_client/game_state.rb +86 -68
  25. data/lib/software_challenge_client/has_hints.rb +1 -1
  26. data/lib/software_challenge_client/invalid_move_exception.rb +1 -0
  27. data/lib/software_challenge_client/logging.rb +1 -0
  28. data/lib/software_challenge_client/network.rb +1 -1
  29. data/lib/software_challenge_client/piece.rb +43 -14
  30. data/lib/software_challenge_client/piece_shape.rb +109 -0
  31. data/lib/software_challenge_client/player.rb +7 -6
  32. data/lib/software_challenge_client/player_type.rb +14 -0
  33. data/lib/software_challenge_client/protocol.rb +83 -75
  34. data/lib/software_challenge_client/rotation.rb +22 -0
  35. data/lib/software_challenge_client/runner.rb +2 -1
  36. data/lib/software_challenge_client/set_move.rb +13 -4
  37. data/lib/software_challenge_client/skip_move.rb +5 -0
  38. data/lib/software_challenge_client/util/constants.rb +3 -4
  39. data/lib/software_challenge_client/version.rb +2 -1
  40. data/lib/update_client_module.sh +15 -0
  41. data/software_challenge_client.gemspec +15 -13
  42. metadata +54 -36
  43. data/lib/software_challenge_client/cube_coordinates.rb +0 -23
  44. data/lib/software_challenge_client/direction.rb +0 -55
  45. data/lib/software_challenge_client/drag_move.rb +0 -19
  46. data/lib/software_challenge_client/line_direction.rb +0 -15
  47. data/lib/software_challenge_client/piece_type.rb +0 -18
  48. data/lib/software_challenge_client/player_color.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1fae378685b67cd4b5e9568aa6da7f59734266680819f15fa97297e2a532fa34
4
- data.tar.gz: 1d2592e9d328f2cc079a21aa6fcc5901395b1e18b9edf3505e06a7805623fcc4
3
+ metadata.gz: c65e973b488cf092e716716135e61c348b62d899a77c821aae0e44e340667888
4
+ data.tar.gz: 1d4511f7ba6c1dffc6344b523cc3cf04ef3e114a962d3edf2d0cc8dd9382190b
5
5
  SHA512:
6
- metadata.gz: 53b31ae3336f7cc0544de8099ddc39156a0d4e7ae7c118c1cff160072e4d7085ce6852b004c028404378ec4e0024b1ea5b8e58e6aad1ae096a629e79a349e35d
7
- data.tar.gz: ab4d43ca12dcc42969887613908b1e1f49b85148cb4324901e9afb74cfe6498acbca72865b8517553da4101384370950f018492c25a34c1c95497d3cc236b259
6
+ metadata.gz: 9e9416cc5a08cd30f7c969edc29a5a5f8c496cc3fa5a1b3c4c7222f4a1ecc653fb2777c1d64e4ac389801d2ad4288901b956366c500835bfc58f51b02d256aa3
7
+ data.tar.gz: d7aabbb618c88b80f8845e72199a4ccf377980aa82f7ed260de1cb9c6c52435d5d0ef4b985a2fff786737c40b6f8fea422dae08a4a906591bbe83daffa695a94
@@ -1,4 +1,5 @@
1
1
  AllCops:
2
+ NewCops: enable
2
3
  TargetRubyVersion: 2.4
3
4
  DefaultFormatter: fuubar
4
5
  DisplayStyleGuide: true
@@ -1 +1 @@
1
- 2.6.5
1
+ 2.5.5
@@ -0,0 +1,41 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Ruby - Main",
9
+ "type": "Ruby",
10
+ "request": "launch",
11
+ "program": "test/main.rb"
12
+ },
13
+ {
14
+ "name": "Ruby - Gem Main",
15
+ "type": "Ruby",
16
+ "request": "launch",
17
+ "program": "example/main.rb"
18
+ },
19
+ {
20
+ "name": "RSpec - Active spec File only",
21
+ "type": "Ruby",
22
+ "request": "launch",
23
+ "program": "C:/tools/ruby27/bin/rspec",
24
+ "args": [
25
+ "-I",
26
+ "${workspaceRoot}",
27
+ "${file}"
28
+ ]
29
+ },
30
+ {
31
+ "name": "RSpec - All",
32
+ "type": "Ruby",
33
+ "request": "launch",
34
+ "program": "C:/tools/ruby27/bin/rspec",
35
+ "args": [
36
+ "-I",
37
+ "${workspaceRoot}"
38
+ ]
39
+ },
40
+ ]
41
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "spellright.language": [
3
+ "de"
4
+ ],
5
+ "spellright.documentTypes": [
6
+ "markdown",
7
+ "latex",
8
+ "plaintext"
9
+ ]
10
+ }
data/Dockerfile CHANGED
@@ -1,3 +1,3 @@
1
- FROM ruby:2.4.2
1
+ FROM ruby:2.6.5
2
2
 
3
3
  RUN gem install --no-document software_challenge_client
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in SoftwareChallengeClient.gemspec
data/Guardfile CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
  # A sample Guardfile
3
4
  # More info at https://github.com/guard/guard#readme
4
5
 
data/README.md CHANGED
@@ -73,7 +73,7 @@ Computerspieler zu haben (`client.rb` im Beispielprojekt):
73
73
  end
74
74
 
75
75
  def best_move
76
- gamestate.possible_moves.sample
76
+ GameRuleLogic.possible_moves(gamestate).sample
77
77
  end
78
78
  end
79
79
 
@@ -109,8 +109,9 @@ dependencies. Then, run `rspec` to run the tests. You can also
109
109
  run `bin/console` for an interactive prompt that will allow you to
110
110
  experiment.
111
111
 
112
- To install this gem onto your local machine, run `bundle exec rake
113
- install`.
112
+ To install this gem onto your local machine, run `gem uninstall
113
+ software_challenge_client` to remove an existing gem and then `bundle exec rake
114
+ install` to install the current version.
114
115
 
115
116
  To develop inside a docker container, make sure you have Docker installed and execute
116
117
  `develop.sh`.
@@ -1,3 +1,23 @@
1
+ = 21.0.2
2
+
3
+ Fixed problem which caused `last_move` of a `GameState` always be `nil` (thanks to wollw!).
4
+
5
+ = 21.0.1
6
+
7
+ Improved performance and defined Ruby version 2.5.5 as minimum requirement
8
+
9
+ = 21.0.0
10
+
11
+ First version for game "Blokus"
12
+
13
+ = 20.2.4
14
+
15
+ Update game name in documentation
16
+
17
+ = 20.2.3
18
+
19
+ Improve method documentation
20
+
1
21
  = 20.2.1 & 20.2.2
2
22
 
3
23
  Bugfixes for performing moves on a gamestate
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
- require "bundler/gem_tasks"
2
- require "yard"
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+ require 'yard'
3
4
 
4
5
  YARD::Rake::YardocTask.new do |t|
5
- t.files = ['lib/**/*.rb'] # optional
6
- t.options = ['--any', '--extra', '--opts'] # optional
6
+ t.files = ['lib/**/*.rb'] # optional
7
7
  end
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
  require 'software_challenge_client'
3
4
 
4
5
  # This is an example of a client playing the game using the software challenge
@@ -16,21 +17,17 @@ class Client < ClientInterface
16
17
  # gets called, when it's your turn
17
18
  def move_requested
18
19
  logger.info "Spielstand: #{gamestate.points_for_player(gamestate.current_player)} - #{gamestate.points_for_player(gamestate.other_player)}"
19
- logger.debug "Board: #{gamestate.board.to_s}"
20
+ logger.debug "Board: #{gamestate.board}"
20
21
  move = best_move
21
22
  logger.debug "Zug gefunden: #{move}" unless move.nil?
22
23
  move
23
24
  end
24
25
 
25
26
  def best_move
26
- #gamestate.board.add_field(Field.new(5, 0))
27
- logger.debug "Berechne zuege fuer Board #{gamestate.board.to_s}"
28
- logger.debug "Felder"
29
- gamestate.board.field_list.each do |f|
30
- if !f.empty?
31
- logger.debug "Feld (#{f.x}, #{f.y}) #{f.obstructed ? 'OO' : f.pieces.last.to_s}"
32
- end
33
- end
27
+ # gamestate.board.add_field(Field.new(5, 0))
28
+ logger.debug "Berechne zuege fuer Board #{gamestate.board}"
29
+
30
+ # all possible moves can't be calculated in under two seconds
34
31
  possible_moves = GameRuleLogic.possible_moves(gamestate)
35
32
  logger.debug "#{possible_moves.size} moegliche Zuege gefunden"
36
33
  possible_moves.sample
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
+ # frozen_string_literal: true
3
4
  require 'software_challenge_client'
4
5
  require 'optparse'
5
6
  require 'ostruct'
@@ -8,31 +9,30 @@ require_relative 'client'
8
9
 
9
10
  options = OpenStruct.new
10
11
  options.host = '127.0.0.1'
11
- options.port = 13050
12
+ options.port = 13_050
12
13
  options.reservation = ''
13
14
 
14
15
  opt_parser = OptionParser.new do |opt|
15
- opt.banner = "Usage: main.rb [OPTIONS]"
16
- opt.separator ""
17
- opt.separator "Options"
16
+ opt.banner = 'Usage: main.rb [OPTIONS]'
17
+ opt.separator ''
18
+ opt.separator 'Options'
18
19
 
19
- opt.on("-p","--port PORT", Integer,"connect to the server at PORT (default #{options.port})") do |p|
20
+ opt.on('-p', '--port PORT', Integer, "connect to the server at PORT (default #{options.port})") do |p|
20
21
  options.port = p
21
22
  end
22
23
 
23
- opt.on("-h","--host HOST","the host's IP address (default #{options.host})") do |h|
24
+ opt.on('-h', '--host HOST', "the host's IP address (default #{options.host})") do |h|
24
25
  options.host = h
25
26
  end
26
27
 
27
- opt.on("-r","--reservation RESERVATION","the host's RESERVATION (default #{options.reservation})") do |r|
28
+ opt.on('-r', '--reservation RESERVATION', "the host's RESERVATION (default #{options.reservation})") do |r|
28
29
  options.reservation = r
29
30
  end
30
31
 
31
- opt.on_tail("-?", "--help", "Show this message") do
32
+ opt.on_tail('-?', '--help', 'Show this message') do
32
33
  puts opt
33
34
  exit
34
35
  end
35
-
36
36
  end
37
37
 
38
38
  opt_parser.parse!(ARGV)
@@ -1,25 +1,28 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module SoftwareChallengeClient
3
- require 'software_challenge_client/version'
4
- require 'software_challenge_client/logging'
5
- require 'software_challenge_client/invalid_move_exception'
6
- require 'software_challenge_client/board'
7
- require 'software_challenge_client/client_interface'
8
- require 'software_challenge_client/condition'
9
- require 'software_challenge_client/debug_hint'
10
- require 'software_challenge_client/field'
11
- require 'software_challenge_client/piece'
12
- require 'software_challenge_client/piece_type'
13
- require 'software_challenge_client/game_state'
14
- require 'software_challenge_client/set_move'
15
- require 'software_challenge_client/drag_move'
16
- require 'software_challenge_client/skip_move'
17
- require 'software_challenge_client/network'
18
- require 'software_challenge_client/player'
19
- require 'software_challenge_client/player_color'
20
- require 'software_challenge_client/protocol'
21
- require 'software_challenge_client/runner'
22
- require 'software_challenge_client/game_rule_logic'
23
- require 'software_challenge_client/direction'
24
- require 'software_challenge_client/cube_coordinates'
3
+ require 'software_challenge_client/board.rb'
4
+ require 'software_challenge_client/client_interface.rb'
5
+ require 'software_challenge_client/color.rb'
6
+ require 'software_challenge_client/condition.rb'
7
+ require 'software_challenge_client/coordinate_set.rb'
8
+ require 'software_challenge_client/coordinates.rb'
9
+ require 'software_challenge_client/debug_hint.rb'
10
+ require 'software_challenge_client/field.rb'
11
+ require 'software_challenge_client/game_rule_logic.rb'
12
+ require 'software_challenge_client/game_state.rb'
13
+ require 'software_challenge_client/has_hints.rb'
14
+ require 'software_challenge_client/invalid_move_exception.rb'
15
+ require 'software_challenge_client/logging.rb'
16
+ require 'software_challenge_client/network.rb'
17
+ require 'software_challenge_client/piece.rb'
18
+ require 'software_challenge_client/piece_shape.rb'
19
+ require 'software_challenge_client/player.rb'
20
+ require 'software_challenge_client/player_type.rb'
21
+ require 'software_challenge_client/protocol.rb'
22
+ require 'software_challenge_client/rotation.rb'
23
+ require 'software_challenge_client/runner.rb'
24
+ require 'software_challenge_client/set_move.rb'
25
+ require 'software_challenge_client/skip_move.rb'
26
+ require 'software_challenge_client/util/constants.rb'
27
+ require 'software_challenge_client/version.rb'
25
28
  end
@@ -5,46 +5,54 @@ require_relative './util/constants'
5
5
  require_relative 'game_state'
6
6
  require_relative 'field'
7
7
 
8
- # Ein Spielbrett fuer Hive
8
+ # Ein Spielbrett fuer Blokus
9
9
  class Board
10
-
11
10
  include Constants
12
11
  # @!attribute [r] fields
13
12
  # @note Besser über die {#field} Methode auf Felder zugreifen.
14
13
  # @return [Array<Array<Field>>] Ein Feld wird an der Position entsprechend
15
- # seiner x und y CubeCoordinates im Array gespeichert.
14
+ # seiner x und y Coordinates im Array gespeichert.
16
15
  attr_reader :fields
17
16
 
18
- def self.field_amount(radius)
19
- return 1 if radius == 1
20
- (radius - 1) * 6 + Board.field_amount(radius - 1)
21
- end
17
+ # @!attribute [r] deployed_blue_pieces
18
+ # @return [Array<PieceShape>] Die blauen, gesetzten Spielsteine
19
+ attr_accessor :deployed_blue_pieces
20
+
21
+ # @!attribute [r] deployed_yellow_pieces
22
+ # @return [Array<PieceShape>] Die gelben, gesetzten Spielsteine
23
+ attr_accessor :deployed_yellow_pieces
24
+
25
+ # @!attribute [r] deployed_red_pieces
26
+ # @return [Array<PieceShape>] Die roten, gesetzten Spielsteine
27
+ attr_accessor :deployed_red_pieces
22
28
 
23
- FIELD_AMOUNT = Board.field_amount((BOARD_SIZE + 1)/2)
29
+ # @!attribute [r] deployed_green_pieces
30
+ # @return [Array<PieceShape>] Die grünen, gesetzten Spielsteine
31
+ attr_accessor :deployed_green_pieces
24
32
 
25
33
  # Erstellt ein neues leeres Spielbrett.
26
34
  def initialize(fields = [])
27
35
  @fields = Board.empty_game_field
28
- fields.each{ |f| add_field(f) }
36
+ fields.each { |f| add_field(f) }
29
37
  end
30
38
 
39
+ # @return [Array] leere Felder entsprechend des Spielbrettes angeordnet
31
40
  def self.empty_game_field
32
- fields = []
33
- (-SHIFT..SHIFT).to_a.each do |x|
34
- fields[x + SHIFT] ||= []
35
- ([-SHIFT, -x-SHIFT].max..[SHIFT, -x+SHIFT].min).to_a.each do |y|
36
- fields[x + SHIFT][y + SHIFT] = Field.new(x, y)
41
+ (0...BOARD_SIZE).to_a.map do |x|
42
+ (0...BOARD_SIZE).to_a.map do |y|
43
+ Field.new(x, y)
37
44
  end
38
45
  end
39
- fields
40
46
  end
41
47
 
48
+ # Entfernt alle Felder des Spielfeldes
42
49
  def clear
43
50
  @fields = []
44
51
  end
45
52
 
53
+ # @return [Array] Liste aller Felder
46
54
  def field_list
47
- @fields.flatten.select{ |e| !e.nil? }
55
+ @fields.flatten.reject(&:nil?)
48
56
  end
49
57
 
50
58
  # Vergleicht zwei Spielbretter. Gleichheit besteht, wenn zwei Spielbretter die
@@ -53,26 +61,27 @@ class Board
53
61
  field_list == other.field_list
54
62
  end
55
63
 
56
- # Fügt ein Feld dem Spielbrett hinzu. Das übergebene Feld ersetzt das an den Koordinaten bestehende Feld.
64
+ # Fügt ein Feld dem Spielbrett hinzu. Das übergebene Feld ersetzt das an den
65
+ # Koordinaten bestehende Feld.
57
66
  #
58
67
  # @param field [Field] Das einzufügende Feld.
59
68
  def add_field(field)
60
- @fields[field.x + SHIFT][field.y + SHIFT] = field
69
+ @fields[field.x][field.y] = field
61
70
  end
62
71
 
63
72
  # Zugriff auf die Felder des Spielfeldes
64
73
  #
65
74
  # @param x [Integer] Die X-Koordinate des Feldes.
66
75
  # @param y [Integer] Die Y-Koordinate des Feldes.
67
- # @return [Field] Das Feld mit den gegebenen Koordinaten. Falls das Feld nicht exisitert, wird nil zurückgegeben.
76
+ # @return [Field] Das Feld mit den gegebenen Koordinaten. Falls das Feld nicht
77
+ # exisitert, wird nil zurückgegeben.
68
78
  def field(x, y)
69
- return nil if (x < -SHIFT) || (y < -SHIFT)
70
- fields.dig(x + SHIFT, y + SHIFT) # NOTE that #dig requires ruby 2.3+
79
+ fields.dig(x, y) # NOTE that #dig requires ruby 2.3+
71
80
  end
72
81
 
73
82
  # Zugriff auf die Felder des Spielfeldes über ein Koordinaten-Paar.
74
83
  #
75
- # @param coordinates [CubeCoordinates] X- und Y-Koordinate als Paar, sonst wie
84
+ # @param coordinates [Coordinates] X- und Y-Koordinate als Paar, sonst wie
76
85
  # bei {Board#field}.
77
86
  #
78
87
  # @return [Field] Wie bei {Board#field}.
@@ -82,31 +91,87 @@ class Board
82
91
  field(coordinates.x, coordinates.y)
83
92
  end
84
93
 
85
- # Liefert alle Felder die dem Spieler mit der gegebenen Farbe gehoeren
94
+ # TODO: Redo this recursively, starting from the corresponding corner and then moving alongside edges and corners
95
+
96
+ # Alle Felder einer bestimmten Farbe
86
97
  #
87
- # @param color [PlayerColor] Die Spielerfarbe
88
- # @return [Array<Field>] Alle Felder der angegebenen Farbe die das Spielbrett enthält.
89
- def fields_of_color(color)
90
- field_list.select{ |f| f.color == color }
98
+ # @param color [Color] Die Farbe der Felder
99
+ # @return [Array<Field>] Eine Liste aller felder, die die gegebene Farbe haben
100
+ def fields_of_color(color, fields = [Coordinates.new(0, 0),
101
+ Coordinates.new(0, BOARD_SIZE - 1),
102
+ Coordinates.new(BOARD_SIZE - 1, BOARD_SIZE - 1),
103
+ Coordinates.new(BOARD_SIZE - 1, 0)].select { |it| field_at(it).color == color })
104
+ copy = Array.new(fields)
105
+
106
+ copy.each do |field|
107
+ [Coordinates.new(1, 0),
108
+ Coordinates.new(1, -1),
109
+ Coordinates.new(0, -1),
110
+ Coordinates.new(-1, -1),
111
+ Coordinates.new(-1, 0),
112
+ Coordinates.new(-1, 1),
113
+ Coordinates.new(0, 1),
114
+ Coordinates.new(1, 1)].each do |neighbor|
115
+ new_field = field + neighbor
116
+ next unless Board.contains(new_field) && @fields[new_field.x][new_field.y].color == color
117
+
118
+ fields << new_field unless fields.include?(new_field)
119
+ end
120
+ end
121
+
122
+ if copy.count == fields.count
123
+ fields
124
+ else
125
+ fields_of_color(color, fields)
126
+ end
91
127
  end
92
128
 
93
- def pieces
94
- field_list.map(&:pieces).flatten
129
+ # @param it [Coordinates] Die zu untersuchenden Koordinaten
130
+ # @return [Boolean] Ob die gegebenen Koordinaten auf dem Board liegen oder nicht
131
+ def in_bounds?(it)
132
+ it.x >= 0 && it.y >= 0 && it.x < BOARD_SIZE && it.y < BOARD_SIZE
95
133
  end
96
134
 
135
+ # @param color [Color] Die Farbe der Steine
136
+ # @return [Array<PieceShape>] Eine Liste aller Steintypen, die die gegebene Farbe noch nicht gespielt hat
97
137
  def deployed_pieces(color)
98
- pieces.select { |p| p.color == color }
138
+ case color
139
+ when Color::RED
140
+ deployed_red_pieces
141
+ when Color::BLUE
142
+ deployed_blue_pieces
143
+ when Color::YELLOW
144
+ deployed_yellow_pieces
145
+ when Color::GREEN
146
+ deployed_green_pieces
147
+ end
99
148
  end
100
149
 
150
+ # @return eine unabhaengige Kopie des Spielbretts
101
151
  def clone
102
152
  Marshal.load(Marshal.dump(self))
103
153
  end
104
154
 
105
- # Gibt eine textuelle Repräsentation des Spielbrettes aus. Hier steht R für
106
- # einen roten Fisch, B für einen blauen, ~ für ein leeres Feld und O für ein
107
- # Kraken-Feld.
155
+ # @param coords [Coordinates] Die Koordinaten des Felds
156
+ # @return Das Feld an den gegebenen Koordinaten
157
+ def [](coords)
158
+ field_at(coords)
159
+ end
160
+
161
+ # Gibt eine textuelle Repräsentation des Spielbrettes aus.
108
162
  def to_s
109
- field_list.sort_by(&:z).map{ |f| f.obstructed ? 'OO' : f.empty? ? '--' : f.pieces.last.to_s }.join
163
+ "\n" +
164
+ (0...BOARD_SIZE).to_a.map do |y|
165
+ (0...BOARD_SIZE).to_a.map do |x|
166
+ @fields[x][y].to_s
167
+ end.join(' ')
168
+ end.join("\n")
110
169
  end
111
170
 
171
+ # @param position [Coordinates] Die zu überprüfenden Koordinaten
172
+ # @return Ob die gegebenen Koordinaten auf dem board liegen
173
+ def self.contains(position)
174
+ position.x >= 0 && position.x < BOARD_SIZE &&
175
+ position.y >= 0 && position.y < BOARD_SIZE
176
+ end
112
177
  end