software_challenge_client 20.2.4 → 21.2.0

Sign up to get free protection for your applications and to get access to all the features.
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 -3
  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 +94 -37
  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 +2 -0
  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 -56
  23. data/lib/software_challenge_client/game_rule_logic.rb +258 -335
  24. data/lib/software_challenge_client/game_state.rb +106 -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 +71 -13
  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 +81 -74
  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 -25
  44. data/lib/software_challenge_client/direction.rb +0 -55
  45. data/lib/software_challenge_client/drag_move.rb +0 -22
  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: 15b53eaa3c0eeb422a9a321d62856fc683cce0d17c2791bf1a8e2d416f8f3619
4
- data.tar.gz: 8cc14adf8bc35f1b80e138929e3df951d173da9e54a9313bd83d494318b0e00e
3
+ metadata.gz: 679cfef66fc6ad4179d34801147b0640e79e2930c607069c3da6e52c5ff00862
4
+ data.tar.gz: bf3dc2f6e06ed94e72328b8babc4741faad2c0510e965f144dcd94b9a80c66ee
5
5
  SHA512:
6
- metadata.gz: 2156956f4bfe9418ad679fff25fe4cfbe075a88149d9fe54aa6d60b1ea5f408f889afd0478319af3d48461a5b74d9a602ef1a205516e1c03023d1619561bb0db
7
- data.tar.gz: c8a75a5c1fe0ee33d53bcb1331b3479968c98f2d7041cdafebb5e2f31db786c774b9f936e7a423a9092b71425c9e61e50fa650242b667f3960efa66b56894c59
6
+ metadata.gz: d99e60671de8a35ad5901c46c418bce5b49ab1ef91551cccc17284bbdf82272719a3049dac3338fcd660c48eea21bc2e2ad8262c3d6803da7eab5251e33664ee
7
+ data.tar.gz: 2ef1c173e01c84cfdc37cd882aea28e04af7151cad00276b1d4a8d4d3f26243fd0e2f8e01584dd6f007954715b2ac6af5fed961aeb5cc0c2982788df296456eb
@@ -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.2.0
2
+
3
+ Adjustments for Backend version 21.2.0
4
+
5
+ = 21.1.0
6
+
7
+ Pieces are now mutable and `==` of pieces considers rotated shapes which result in the same covered board fields as equal.
8
+
9
+ = 21.0.2
10
+
11
+ Fixed problem which caused `last_move` of a `GameState` always be `nil` (thanks to wollw!).
12
+
13
+ = 21.0.1
14
+
15
+ Improved performance and defined Ruby version 2.5.5 as minimum requirement
16
+
17
+ = 21.0.0
18
+
19
+ First version for game "Blokus"
20
+
1
21
  = 20.2.4
2
22
 
3
23
  Update game name in documentation
data/Rakefile CHANGED
@@ -1,6 +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.files = ['lib/**/*.rb'] # optional
6
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,42 +5,44 @@ 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
- # Anzahl der Felder eines hexagonalen Spielfeldes
19
- # @param radius [Integer] Radius des Spielfeldes
20
- def self.field_amount(radius)
21
- return 1 if radius == 1
22
- (radius - 1) * 6 + Board.field_amount(radius - 1)
23
- 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
24
28
 
25
- # Anzahl der Felder des fuer Hive verwendeten Spielfeldes
26
- 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
27
32
 
28
33
  # Erstellt ein neues leeres Spielbrett.
29
34
  def initialize(fields = [])
30
35
  @fields = Board.empty_game_field
31
- fields.each{ |f| add_field(f) }
36
+ fields.each { |f| add_field(f) }
32
37
  end
33
38
 
34
39
  # @return [Array] leere Felder entsprechend des Spielbrettes angeordnet
35
40
  def self.empty_game_field
36
- fields = []
37
- (-SHIFT..SHIFT).to_a.each do |x|
38
- fields[x + SHIFT] ||= []
39
- ([-SHIFT, -x-SHIFT].max..[SHIFT, -x+SHIFT].min).to_a.each do |y|
40
- 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)
41
44
  end
42
45
  end
43
- fields
44
46
  end
45
47
 
46
48
  # Entfernt alle Felder des Spielfeldes
@@ -50,7 +52,7 @@ class Board
50
52
 
51
53
  # @return [Array] Liste aller Felder
52
54
  def field_list
53
- @fields.flatten.select{ |e| !e.nil? }
55
+ @fields.flatten.reject(&:nil?)
54
56
  end
55
57
 
56
58
  # Vergleicht zwei Spielbretter. Gleichheit besteht, wenn zwei Spielbretter die
@@ -59,26 +61,27 @@ class Board
59
61
  field_list == other.field_list
60
62
  end
61
63
 
62
- # 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.
63
66
  #
64
67
  # @param field [Field] Das einzufügende Feld.
65
68
  def add_field(field)
66
- @fields[field.x + SHIFT][field.y + SHIFT] = field
69
+ @fields[field.x][field.y] = field
67
70
  end
68
71
 
69
72
  # Zugriff auf die Felder des Spielfeldes
70
73
  #
71
74
  # @param x [Integer] Die X-Koordinate des Feldes.
72
75
  # @param y [Integer] Die Y-Koordinate des Feldes.
73
- # @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.
74
78
  def field(x, y)
75
- return nil if (x < -SHIFT) || (y < -SHIFT)
76
- 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+
77
80
  end
78
81
 
79
82
  # Zugriff auf die Felder des Spielfeldes über ein Koordinaten-Paar.
80
83
  #
81
- # @param coordinates [CubeCoordinates] X- und Y-Koordinate als Paar, sonst wie
84
+ # @param coordinates [Coordinates] X- und Y-Koordinate als Paar, sonst wie
82
85
  # bei {Board#field}.
83
86
  #
84
87
  # @return [Field] Wie bei {Board#field}.
@@ -88,23 +91,60 @@ class Board
88
91
  field(coordinates.x, coordinates.y)
89
92
  end
90
93
 
91
- # 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
92
97
  #
93
- # @param color [PlayerColor] Die Spielerfarbe
94
- # @return [Array<Field>] Alle Felder der angegebenen Farbe die das Spielbrett enthält.
95
- def fields_of_color(color)
96
- 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
97
127
  end
98
128
 
99
- # @return [Array] Liste aller Spielsteine, die auf dem Spielbrett platziert wurden
100
- def pieces
101
- 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
102
133
  end
103
134
 
104
- # @param [PlayerColor] Spielerfarbe
105
- # @return [Array] Liste aller Spielsteine eines Spielers, die auf dem Spielbrett platziert wurden
135
+ # @param color [Color] Die Farbe der Steine
136
+ # @return [Array<PieceShape>] Eine Liste aller Steintypen, die die gegebene Farbe noch nicht gespielt hat
106
137
  def deployed_pieces(color)
107
- 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
108
148
  end
109
149
 
110
150
  # @return eine unabhaengige Kopie des Spielbretts
@@ -112,9 +152,26 @@ class Board
112
152
  Marshal.load(Marshal.dump(self))
113
153
  end
114
154
 
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
+
115
161
  # Gibt eine textuelle Repräsentation des Spielbrettes aus.
116
162
  def to_s
117
- 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")
118
169
  end
119
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
120
177
  end