software_challenge_client 21.0.1 → 22.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb6f7046235b14fdf74c293c8c4f1b40a014373f949e9c9987f1ee36db6e579f
4
- data.tar.gz: 95cb06324e9ae3ef77e7a76200bd45f47af3176f18f744f138c835d14ef7ade2
3
+ metadata.gz: 5409d523f45de264ef1616783fc0e901ea63460f831df5b65a014cc5effba23c
4
+ data.tar.gz: 1e9d622dbb0008fff464ca1e39a02ae3bab89192f07674ebd0f63b09b45f0fab
5
5
  SHA512:
6
- metadata.gz: 382fe8164ebb55803018b0ebec3c04061d9fbc65e770702383190ea9a5279f5cb6e0ddcbb12e3a3b3057d31450f416f4388d3ddafb1e14447c15bd2fb16a937a
7
- data.tar.gz: fa76ba63c8634597486a9b34665a0c731870a25ace4ddef3d4b9b05206b6c31e97077a2bf12106193e321dfec6225c99d3361435d8938229169e77ecad9b0c3a
6
+ metadata.gz: 02e77e4cc105dbccc0c52df6c3d3f7486cf36015d49ed08d6132c69983724e1cdff0fef12c0267b348137c5693b209aff80123dd5a297d28e0e6227ead3a9bbc
7
+ data.tar.gz: 9ee8e0a060c2b214353ca95647dd40bc844043688354663a9ccdd959269f38a70c85fae6bc531ec0eec5a862522e01c876984bc4bf1b4920de8e67f80d311c93
data/Dockerfile CHANGED
@@ -1,3 +1,3 @@
1
- FROM ruby:2.6.5
1
+ FROM ruby:2.6.6
2
2
 
3
3
  RUN gem install --no-document software_challenge_client
data/RELEASES.md CHANGED
@@ -1,3 +1,15 @@
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
+
1
13
  = 21.0.1
2
14
 
3
15
  Improved performance and defined Ruby version 2.5.5 as minimum requirement
data/bin/console CHANGED
File without changes
data/bin/setup CHANGED
File without changes
data/develop.sh CHANGED
File without changes
data/example/main.rb CHANGED
File without changes
data/example/start.bat CHANGED
File without changes
data/generate-authors.sh CHANGED
File without changes
@@ -4,7 +4,6 @@ module SoftwareChallengeClient
4
4
  require 'software_challenge_client/client_interface.rb'
5
5
  require 'software_challenge_client/color.rb'
6
6
  require 'software_challenge_client/condition.rb'
7
- require 'software_challenge_client/coordinate_set.rb'
8
7
  require 'software_challenge_client/coordinates.rb'
9
8
  require 'software_challenge_client/debug_hint.rb'
10
9
  require 'software_challenge_client/field.rb'
@@ -13,16 +12,14 @@ module SoftwareChallengeClient
13
12
  require 'software_challenge_client/has_hints.rb'
14
13
  require 'software_challenge_client/invalid_move_exception.rb'
15
14
  require 'software_challenge_client/logging.rb'
15
+ require 'software_challenge_client/move.rb'
16
16
  require 'software_challenge_client/network.rb'
17
17
  require 'software_challenge_client/piece.rb'
18
- require 'software_challenge_client/piece_shape.rb'
18
+ require 'software_challenge_client/piece_type.rb'
19
19
  require 'software_challenge_client/player.rb'
20
- require 'software_challenge_client/player_type.rb'
21
20
  require 'software_challenge_client/protocol.rb'
22
- require 'software_challenge_client/rotation.rb'
23
21
  require 'software_challenge_client/runner.rb'
24
- require 'software_challenge_client/set_move.rb'
25
- require 'software_challenge_client/skip_move.rb'
22
+ require 'software_challenge_client/team.rb'
26
23
  require 'software_challenge_client/util/constants.rb'
27
24
  require 'software_challenge_client/version.rb'
28
25
  end
@@ -5,31 +5,16 @@ require_relative './util/constants'
5
5
  require_relative 'game_state'
6
6
  require_relative 'field'
7
7
 
8
- # Ein Spielbrett fuer Blokus
8
+ # Ein Spielbrett fuer Ostseeschach
9
9
  class Board
10
10
  include Constants
11
+
11
12
  # @!attribute [r] fields
12
13
  # @note Besser über die {#field} Methode auf Felder zugreifen.
13
14
  # @return [Array<Array<Field>>] Ein Feld wird an der Position entsprechend
14
15
  # seiner x und y Coordinates im Array gespeichert.
15
16
  attr_reader :fields
16
17
 
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
28
-
29
- # @!attribute [r] deployed_green_pieces
30
- # @return [Array<PieceShape>] Die grünen, gesetzten Spielsteine
31
- attr_accessor :deployed_green_pieces
32
-
33
18
  # Erstellt ein neues leeres Spielbrett.
34
19
  def initialize(fields = [])
35
20
  @fields = Board.empty_game_field
@@ -91,39 +76,19 @@ class Board
91
76
  field(coordinates.x, coordinates.y)
92
77
  end
93
78
 
94
- # TODO: Redo this recursively, starting from the corresponding corner and then moving alongside edges and corners
79
+ def fields_of_color(color)
80
+ fields = []
95
81
 
96
- # Alle Felder einer bestimmten Farbe
97
- #
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)
82
+ (0...BOARD_SIZE).to_a.map do |x|
83
+ (0...BOARD_SIZE).to_a.map do |y|
84
+ f = field(x,y)
85
+ if (f.color == color)
86
+ fields << f
87
+ end
119
88
  end
120
89
  end
121
90
 
122
- if copy.count == fields.count
123
- fields
124
- else
125
- fields_of_color(color, fields)
126
- end
91
+ fields
127
92
  end
128
93
 
129
94
  # @param it [Coordinates] Die zu untersuchenden Koordinaten
@@ -132,21 +97,6 @@ class Board
132
97
  it.x >= 0 && it.y >= 0 && it.x < BOARD_SIZE && it.y < BOARD_SIZE
133
98
  end
134
99
 
135
- # @param color [Color] Die Farbe der Steine
136
- # @return [Array<PieceShape>] Eine Liste aller Steintypen, die die gegebene Farbe noch nicht gespielt hat
137
- def deployed_pieces(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
148
- end
149
-
150
100
  # @return eine unabhaengige Kopie des Spielbretts
151
101
  def clone
152
102
  Marshal.load(Marshal.dump(self))
@@ -2,15 +2,25 @@
2
2
 
3
3
  require 'typesafe_enum'
4
4
 
5
- # Die Spielsteinfarben. BLUE, YELLOW, RED und GREEN
5
+ require_relative 'team'
6
+
7
+ # TODO 2022: Replace with bool?
8
+ # Die Spielsteinfarben. BLUE, und RED
6
9
  class Color < TypesafeEnum::Base
7
10
  new :BLUE, 'B'
8
- new :YELLOW, 'Y'
9
11
  new :RED, 'R'
10
- new :GREEN, 'G'
11
12
 
12
13
  # Gibt den color namen zurück
13
14
  def to_s
14
15
  self.key.to_s
15
16
  end
17
+
18
+ # Gibt das zugehörige Team zurück
19
+ def to_t
20
+ if self.key == :RED
21
+ Team::ONE
22
+ else
23
+ Team::TWO
24
+ end
25
+ end
16
26
  end
@@ -4,47 +4,66 @@
4
4
  # Ein Feld des Spielfelds. Ein Spielfeld ist durch die Koordinaten eindeutig
5
5
  # identifiziert.
6
6
  class Field
7
- # @!attribute [rw] color
8
- # @return [Color] Farbe des überdeckenden Spielsteins, falls vorhanden, sonst
9
- # nil
10
- attr_accessor :color
11
7
  # @!attribute [r] coordinates
12
8
  # @return [Coordinates] die X-Y-Koordinaten des Feldes
13
9
  attr_reader :coordinates
14
10
 
11
+ # @!attribute [rw] piece
12
+ # @return [Piece] das Piece auf diesem Feld, falls vorhanden, sonst nil
13
+ attr_accessor :piece
14
+
15
15
  # Erstellt ein neues leeres Feld.
16
16
  #
17
17
  # @param x [Integer] X-Koordinate
18
18
  # @param y [Integer] Y-Koordinate
19
19
  # @param color [Color] Farbe des Spielsteins, der das Feld überdeckt, nil falls kein Spielstein es überdeckt
20
- def initialize(x, y, color = nil)
21
- @color = color
20
+ def initialize(x, y, piece = nil)
21
+ @piece = piece
22
22
  @coordinates = Coordinates.new(x, y)
23
23
  end
24
24
 
25
25
  # Vergleicht zwei Felder. Felder sind gleich, wenn sie gleiche Koordinaten und
26
- # gleichen Typ haben.
26
+ # den gleichen Spielstein haben.
27
27
  # @return [Boolean] true bei Gleichheit, sonst false.
28
28
  def ==(other)
29
- coordinates == other.coordinates &&
30
- color == other.color
29
+ !other.nil? && coordinates == other.coordinates && piece == other.piece
31
30
  end
32
31
 
32
+ # @return [Integer] X-Koordinate des Felds
33
33
  def x
34
34
  coordinates.x
35
35
  end
36
36
 
37
+ # @return [Integer] Y-Koordinate des Felds
37
38
  def y
38
39
  coordinates.y
39
40
  end
40
41
 
42
+ # @return [Team] Team des Pieces auf dem Feld
43
+ def team
44
+ if piece.nil?
45
+ nil
46
+ else
47
+ piece.color.to_t
48
+ end
49
+ end
50
+
51
+ # @return [PieceColor] Farbe des Pieces auf dem Feld
52
+ def color
53
+ if piece.nil?
54
+ nil
55
+ else
56
+ piece.color
57
+ end
58
+ end
59
+
41
60
  # @return [Boolean] true, wenn das Feld nicht durch einen Spielstein überdeckt ist, sonst false
42
61
  def empty?
43
- color.nil?
62
+ piece.nil?
44
63
  end
45
64
 
46
65
  # @return [String] Textuelle Darstellung des Feldes.
47
66
  def to_s
48
- empty? ? '_' : color.value
67
+ empty? ? '__' : piece.to_ss
49
68
  end
50
69
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  require_relative './util/constants'
4
4
  require_relative 'invalid_move_exception'
5
- require_relative 'set_move'
5
+ require_relative 'move'
6
6
 
7
7
  require 'set'
8
8
 
9
- # Methoden, welche die Spielregeln von Blokus abbilden.
9
+ # Methoden, welche die Spielregeln von Ostseeschach abbilden.
10
10
  #
11
11
  # Es gibt hier viele Helfermethoden, die von den beiden Hauptmethoden {GameRuleLogic#valid_move?}
12
12
  # und {GameRuleLogic.possible_moves} benutzt werden.
@@ -19,251 +19,69 @@ class GameRuleLogic
19
19
 
20
20
  # Gibt alle möglichen Züge für den Spieler zurück, der in der gamestate dran ist.
21
21
  # Diese ist die wichtigste Methode dieser Klasse für Schüler.
22
- #
23
22
  # @param gamestate [GameState] Der zu untersuchende Spielstand.
23
+ #
24
+ # @return [Array<Move>] Die möglichen Moves
24
25
  def self.possible_moves(gamestate)
25
- re = possible_setmoves(gamestate)
26
+ moves = []
27
+ fields = gamestate.board.fields_of_color(gamestate.current_player.color)
26
28
 
27
- re << SkipMove.new unless gamestate.is_first_move?
29
+ fields.each do |f|
30
+ moves.push(*moves_for_piece(gamestate, f.piece))
31
+ end
28
32
 
29
- re
33
+ moves.select { |m| valid_move?(gamestate, m) }.to_a
30
34
  end
31
35
 
32
36
  # Gibt einen zufälligen möglichen Zug zurück
33
37
  # @param gamestate [GameState] Der zu untersuchende Spielstand.
38
+ #
39
+ # @return [Move] Ein möglicher Move
34
40
  def self.possible_move(gamestate)
35
41
  possible_moves(gamestate).sample
36
42
  end
37
43
 
38
- # Gibt alle möglichen Legezüge zurück
39
- # @param gamestate [GameState] Der zu untersuchende Spielstand.
40
- def self.possible_setmoves(gamestate)
41
- if gamestate.is_first_move?
42
- possible_start_moves(gamestate)
43
- else
44
- all_possible_setmoves(gamestate).flatten
45
- end
46
- end
47
-
48
- # Gibt alle möglichen Legezüge in der ersten Runde zurück
49
- # @param gamestate [GameState] Der zu untersuchende Spielstand.
50
- def self.possible_start_moves(gamestate)
51
- color = gamestate.current_color
52
- shape = gamestate.start_piece
53
- area1 = shape.dimension
54
- area2 = Coordinates.new(area1.y, area1.x)
55
- moves = Set[]
56
-
57
- # Hard code corners for most efficiency (and because a proper algorithm would be pretty illegible here)
58
- # Upper Left
59
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(0, 0)))
60
-
61
- # Upper Right
62
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(BOARD_SIZE - area1.x, 0)))
63
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(BOARD_SIZE - area2.x, 0)))
64
-
65
- # Lower Left
66
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(0, BOARD_SIZE - area1.y)))
67
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(0, BOARD_SIZE - area2.y)))
68
-
69
- # Lower Right
70
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(BOARD_SIZE - area1.x, BOARD_SIZE - area1.y)))
71
- moves.merge(moves_for_shape_on(color, shape, Coordinates.new(BOARD_SIZE - area2.x, BOARD_SIZE - area2.y)))
72
-
73
- moves.select { |m| valid_set_move?(gamestate, m) }.to_a
74
- end
75
-
76
- # Hilfsmethode um Legezüge für eine [PieceShape] zu berechnen.
77
- # @param color [Color] Die Farbe der Spielsteine der Züge
78
- # @param shape [PieceShape] Die Form der Spielsteine der Züge
79
- # @param position [Coordinates] Die Position der Spielsteine der Züge
80
- def self.moves_for_shape_on(color, shape, position)
81
- moves = Set[]
82
- Rotation.each do |r|
83
- [true, false].each do |f|
84
- moves << SetMove.new(Piece.new(color, shape, r, f, position))
85
- end
86
- end
87
- moves
88
- end
89
-
90
- # Gib eine Liste aller möglichen Legezüge zurück, auch wenn es die erste Runde ist.
91
- # @param gamestate [GameState] Der zu untersuchende Spielstand.
92
- def self.all_possible_setmoves(gamestate)
93
- moves = []
94
- fields = valid_fields(gamestate)
95
- gamestate.undeployed_pieces(gamestate.current_color).each do |p|
96
- (moves << possible_moves_for_shape(gamestate, p, fields)).flatten
97
- end
98
- moves
99
- end
100
-
101
- # Gibt eine Liste aller möglichen SetMoves für diese Form zurück.
44
+ # Hilfsmethode um Legezüge für einen [Piece] zu berechnen.
102
45
  # @param gamestate [GameState] Der zu untersuchende Spielstand.
103
- # @param shape Die [PieceShape], die die Züge nutzen sollen
46
+ # @param piece [Piece] Der Typ des Spielsteines
104
47
  #
105
- # @return Alle möglichen Züge mit der Form
106
- def self.possible_moves_for_shape(gamestate, shape, fields = valid_fields(gamestate))
107
- color = gamestate.current_color
108
-
48
+ # @return [Array<Move>] Die möglichen Moves
49
+ def self.moves_for_piece(gamestate, piece)
109
50
  moves = Set[]
110
- fields.each do |field|
111
- shape.unique_transforms().each do |t|
112
- piece = Piece.new(color, shape, t.r, t.f, Coordinates.new(0, 0))
113
- piece.coords.each do |pos|
114
- moves << SetMove.new(Piece.new(color, shape, t.r, t.f, Coordinates.new(field.x - pos.x, field.y - pos.y)))
115
- end
116
- end
117
- end
118
- moves.select { |m| valid_set_move?(gamestate, m) }.to_a
119
- end
120
-
121
- # Gibt eine Liste aller Felder zurück, an denen möglicherweise Züge gemacht werden kann.
122
- # @param gamestate [GameState] Der zu untersuchende Spielstand.
123
- def self.valid_fields(gamestate)
124
- color = gamestate.current_color
125
- board = gamestate.board
126
- fields = Set[]
127
- board.fields_of_color(color).each do |field|
128
- [Coordinates.new(field.x - 1, field.y - 1),
129
- Coordinates.new(field.x - 1, field.y + 1),
130
- Coordinates.new(field.x + 1, field.y - 1),
131
- Coordinates.new(field.x + 1, field.y + 1)].each do |corner|
132
- next unless Board.contains(corner)
133
- next unless board[corner].empty?
134
- next if neighbor_of_color?(board, Field.new(corner.x, corner.y), color)
135
-
136
- fields << corner
137
- end
138
- end
139
- fields
140
- end
141
-
142
- # Überprüft, ob das gegebene Feld ein Nachbarfeld mit der Farbe [color] hat
143
- # @param board [Board] Das aktuelle Board
144
- # @param field [Field] Das zu überprüfende Feld
145
- # @param color [Color] Nach der zu suchenden Farbe
146
- def self.neighbor_of_color?(board, field, color)
147
- [Coordinates.new(field.x - 1, field.y),
148
- Coordinates.new(field.x, field.y - 1),
149
- Coordinates.new(field.x + 1, field.y),
150
- Coordinates.new(field.x, field.y + 1)].any? do |neighbor|
151
- Board.contains(neighbor) && board[neighbor].color == color
51
+ piece.target_coords.each do |c|
52
+ moves << Move.new(piece.position, c)
152
53
  end
54
+ moves.select { |m| valid_move?(gamestate, m) }.to_a
153
55
  end
154
56
 
155
- # # Return a list of all moves, impossible or not.
156
- # # There's no real usage, except maybe for cases where no Move validation happens
157
- # # if `Constants.VALIDATE_MOVE` is false, then this function should return the same
158
- # # Set as `::getPossibleMoves`
159
- # def self.get_all_set_moves()
160
- # moves = []
161
- # Color.each do |c|
162
- # PieceShape.each do |s|
163
- # Rotation.each do |r|
164
- # [false, true].each do |f|
165
- # (0..BOARD_SIZE-1).to_a.each do |x|
166
- # (0..BOARD_SIZE-1).to_a.each do |y|
167
- # moves << SetMove.new(Piece.new(c, s, r, f, Coordinates.new(x, y)))
168
- # end
169
- # end
170
- # end
171
- # end
172
- # end
173
- # end
174
- # moves
175
- # end
176
-
177
57
  # --- Move Validation ------------------------------------------------------------
178
58
 
179
59
  # Prüft, ob der gegebene [Move] zulässig ist.
180
60
  # @param gamestate [GameState] Der zu untersuchende Spielstand.
181
- # @param move der zu überprüfende Zug
61
+ # @param move [Move] Der zu überprüfende Zug
182
62
  #
183
63
  # @return ob der Zug zulässig ist
184
64
  def self.valid_move?(gamestate, move)
185
- if move.instance_of? SkipMove
186
- !gamestate.is_first_move?
187
- else
188
- valid_set_move?(gamestate, move)
189
- end
190
- end
65
+ return false unless gamestate.current_player.color == move.piece(gamestate).color
191
66
 
192
- # Prüft, ob der gegebene [SetMove] zulässig ist.
193
- # @param gamestate [GameState] der aktuelle Spielstand
194
- # @param move [SetMove] der zu überprüfende Zug
195
- #
196
- # @return ob der Zug zulässig ist
197
- def self.valid_set_move?(gamestate, move)
198
- # Check whether the color's move is currently active
199
- return false if move.piece.color != gamestate.current_color
67
+ return false unless gamestate.board.in_bounds?(move.to)
200
68
 
201
- # Check whether the shape is valid
202
- if gamestate.is_first_move?
203
- return false if move.piece.kind != gamestate.start_piece
204
- elsif !gamestate.undeployed_pieces(move.piece.color).include?(move.piece.kind)
205
- return false
206
- end
69
+ return false if gamestate.board.field_at(move.to).color == move.piece(gamestate).color
207
70
 
208
- # Check whether the piece can be placed
209
- move.piece.coords.each do |it|
210
- return false unless gamestate.board.in_bounds?(it)
211
- return false if obstructed?(gamestate.board, it)
212
- return false if borders_on_color?(gamestate.board, it, move.piece.color)
213
- end
71
+ return false unless move.piece(gamestate).target_coords.include? move.to
214
72
 
215
- if gamestate.is_first_move?
216
- # Check if it is placed correctly in a corner
217
- return false if move.piece.coords.none? { |it| corner?(it) }
218
- else
219
- # Check if the piece is connected to at least one tile of same color by corner
220
- return false if move.piece.coords.none? { |it| corners_on_color?(gamestate.board, it, move.piece.color) }
221
- end
73
+ # TODO 2022: Forgot checks?
222
74
 
223
75
  true
224
76
  end
225
77
 
226
- # Überprüft, ob das gegebene Feld ein Nachbarfeld mit der Farbe [color] hat
227
- # @param board [Board] Das aktuelle Spielbrett
228
- # @param field [Field] Das zu überprüfende Feld
229
- # @param color [Color] Nach der zu suchenden Farbe
230
- def self.borders_on_color?(board, position, color)
231
- [Coordinates.new(1, 0), Coordinates.new(0, 1), Coordinates.new(-1, 0), Coordinates.new(0, -1)].any? do |it|
232
- if board.in_bounds?(position + it)
233
- board[position + it].color == color
234
- else
235
- false
236
- end
237
- end
238
- end
239
-
240
- # Überprüft, ob das gegebene Feld ein diagonales Nachbarfeld mit der Farbe [color] hat
241
- # @param board [Board] Das aktuelle Spielbrett
242
- # @param position [Field] Das zu überprüfende Feld
243
- # @param color [Color] Nach der zu suchenden Farbe
244
- def self.corners_on_color?(board, position, color)
245
- [Coordinates.new(1, 1), Coordinates.new(1, -1), Coordinates.new(-1, -1), Coordinates.new(-1, 1)].any? do |it|
246
- board.in_bounds?(position + it) && board[position + it].color == color
247
- end
248
- end
249
-
250
- # Überprüft, ob die gegebene [position] an einer Ecke des Boards liegt.
251
- # @param position [Coordinates] Die zu überprüfenden Koordinaten
252
- def self.corner?(position)
253
- corner = [
254
- Coordinates.new(0, 0),
255
- Coordinates.new(BOARD_SIZE - 1, 0),
256
- Coordinates.new(0, BOARD_SIZE - 1),
257
- Coordinates.new(BOARD_SIZE - 1, BOARD_SIZE - 1)
258
- ]
259
- corner.include? position
260
- end
261
-
262
- # Überprüft, ob die gegebene [position] schon mit einer Farbe belegt wurde.
78
+ # Überprüft, ob die gegebene [position] mit einem Spielstein belegt ist.
263
79
  # @param board [Board] Das aktuelle Spielbrett
264
80
  # @param position [Coordinates] Die zu überprüfenden Koordinaten
81
+ #
82
+ # @return [Boolean] Ob die position belegt wurde
265
83
  def self.obstructed?(board, position)
266
- !board[position].color.nil?
84
+ !board.field_at(position).empty?
267
85
  end
268
86
 
269
87
  # --- Perform Move ------------------------------------------------------------
@@ -271,66 +89,48 @@ class GameRuleLogic
271
89
  # Führe den gegebenen [Move] im gebenenen [GameState] aus.
272
90
  # @param gamestate [GameState] der aktuelle Spielstand
273
91
  # @param move der auszuführende Zug
92
+ #
93
+ # @return [GameState] Der theoretische GameState
274
94
  def self.perform_move(gamestate, move)
275
95
  raise 'Invalid move!' unless valid_move?(gamestate, move)
276
96
 
277
- if move.instance_of? SetMove
278
- gamestate.undeployed_pieces(move.piece.color).delete(move.piece)
279
- # gamestate.deployed_pieces(move.piece.color).add(move.piece)
97
+ from_field = gamestate.board.field_at(move.from)
98
+ to_field = gamestate.board.field_at(move.to)
280
99
 
281
- # Apply piece to board
282
- move.piece.coords.each do |coord|
283
- gamestate.board[coord].color = move.piece.color
284
- end
100
+ # Update board pieces if one is stepped on
101
+ if not to_field.empty?
102
+ from_field.piece.height = from_field.piece.height + 1
285
103
 
286
- # If it was the last piece for this color, remove it from the turn queue
287
- if gamestate.undeployed_pieces(move.piece.color).empty?
288
- gamestate.lastMoveMono += move.color to(move.piece.kind == PieceShape.MONO)
289
- gamestate.remove_active_color
104
+ # Check for high tower
105
+ if from_field.piece.height >= 3
106
+ gamestate.current_player.amber = gamestate.current_player.amber + 1
107
+ to_field.piece = nil
290
108
  end
291
109
  end
110
+
111
+ # Update board fields
112
+ to_field.piece = from_field.piece
113
+ from_field.piece = nil
114
+
292
115
  gamestate.turn += 1
293
- gamestate.round += 1
294
116
  gamestate.last_move = move
295
117
  end
296
118
 
297
119
  # --- Other ------------------------------------------------------------
298
120
 
299
- # Berechne den Punktestand anhand der gegebenen [PieceShape]s.
300
- # @param undeployed eine Sammlung aller nicht gelegten [PieceShape]s
301
- # @param monoLast ob der letzte gelegte Stein das Monomino war
121
+ # Prueft, ob ein Spieler im gegebenen GameState gewonnen hat.
122
+ # @param gamestate [GameState] Der zu untersuchende GameState.
302
123
  #
303
- # @return die erreichte Punktezahl
304
- def self.get_points_from_undeployed(undeployed, mono_last = false)
305
- # If all pieces were placed:
306
- if undeployed.empty?
307
- # Return sum of all squares plus 15 bonus points
308
- return SUM_MAX_SQUARES + 15 +
309
- # If the Monomino was the last placed piece, add another 5 points
310
- mono_last ? 5 : 0
124
+ # @return [Condition] nil, if the game is not won or a Condition indicating the winning player
125
+ def self.winning_condition(gamestate)
126
+ if gamestate.player_one.amber >= 2
127
+ Condition.new(gamestate.player_one, "Spieler 1 hat 2 Bernsteine erreicht")
311
128
  end
312
- # One point per block per piece placed
313
- SUM_MAX_SQUARES - undeployed.map(&:size).sum
314
- end
315
-
316
- # Gibt einen zufälligen Pentomino zurück, welcher nicht `x` ist.
317
- def self.get_random_pentomino
318
- PieceShape.map(&:value).select { |it| it.size == 5 && it != PieceShape::PENTO_X }
319
- end
320
129
 
321
- # Entferne alle Farben, die keine Steine mehr auf dem Feld platzieren können.
322
- def remove_invalid_colors(gamestate)
323
- return if gamestate.ordered_colors.empty?
324
- return unless get_possible_moves(gamestate).empty?
325
-
326
- gamestate.remove_active_color
327
- remove_invalid_colors(gamestate)
328
- end
130
+ if gamestate.player_two.amber >= 2
131
+ Condition.new(gamestate.player_two, "Spieler 2 hat 2 Bernsteine erreicht")
132
+ end
329
133
 
330
- # Prueft, ob ein Spieler im gegebenen GameState gewonnen hat.
331
- # @param gamestate [GameState] Der zu untersuchende GameState.
332
- # @return [Condition] nil, if the game is not won or a Condition indicating the winning player
333
- def self.winning_condition(_gamestate)
334
- raise 'Not implemented yet!'
134
+ nil
335
135
  end
336
136
  end