software_challenge_client 21.1.0 → 22.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/Dockerfile +1 -1
  4. data/README.md +1 -1
  5. data/RELEASES.md +12 -0
  6. data/bin/console +0 -0
  7. data/bin/setup +0 -0
  8. data/develop.sh +0 -0
  9. data/example/main.rb +0 -0
  10. data/example/start.bat +0 -0
  11. data/generate-authors.sh +0 -0
  12. data/lib/software_challenge_client/board.rb +11 -61
  13. data/lib/software_challenge_client/color.rb +13 -3
  14. data/lib/software_challenge_client/field.rb +30 -11
  15. data/lib/software_challenge_client/game_rule_logic.rb +55 -255
  16. data/lib/software_challenge_client/game_state.rb +158 -212
  17. data/lib/software_challenge_client/move.rb +41 -0
  18. data/lib/software_challenge_client/piece.rb +55 -56
  19. data/lib/software_challenge_client/piece_type.rb +16 -0
  20. data/lib/software_challenge_client/player.rb +12 -6
  21. data/lib/software_challenge_client/protocol.rb +201 -267
  22. data/lib/software_challenge_client/runner.rb +1 -1
  23. data/lib/software_challenge_client/team.rb +25 -0
  24. data/lib/software_challenge_client/util/constants.rb +2 -3
  25. data/lib/software_challenge_client/version.rb +1 -1
  26. data/lib/software_challenge_client.rb +3 -6
  27. data/lib/update_client_module.sh +0 -0
  28. data/push_image_production.sh +12 -0
  29. data/release.sh +0 -0
  30. metadata +7 -10
  31. data/lib/software_challenge_client/coordinate_set.rb +0 -92
  32. data/lib/software_challenge_client/piece_shape.rb +0 -109
  33. data/lib/software_challenge_client/player_type.rb +0 -14
  34. data/lib/software_challenge_client/rotation.rb +0 -22
  35. data/lib/software_challenge_client/set_move.rb +0 -24
  36. data/lib/software_challenge_client/skip_move.rb +0 -13
@@ -1,212 +1,158 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './util/constants'
4
- require_relative 'player'
5
- require_relative 'board'
6
- require_relative 'condition'
7
-
8
- # Ein Spielzustand. Wird vom Server an die Computerspieler übermittelt und
9
- # enthält alles, was der Computerspieler wissen muss, um einen Zug zu machen.
10
- #
11
- # Um eine Liste der gerade möglichen Züge zu bekommen, gibt es die Methode
12
- # {GameState#possible_moves}.
13
- class GameState
14
- # @!attribute [rw] turn
15
- # @return [Integer] Aktuelle Zugnummer (von 0 beginnend)
16
- attr_accessor :turn
17
- # @!attribute [rw] round
18
- # @return [Integer] Aktuelle Rundennummer (von 1 beginnend)
19
- attr_accessor :round
20
-
21
- # @!attribute [rw] startColor
22
- # @return [Color] Die Farbe, die zuerst legen darf
23
- attr_accessor :start_color
24
- # @!attribute [rw] current_color_index
25
- # @return [Color] Der jetzige Index in der Zug Reihenfolge der Farben.
26
- attr_accessor :current_color_index
27
- # @!attribute [rw] ordered_colors
28
- # @return [Array<Color>] Ein Array aller Farben die ziehen können in
29
- # der Reihenfolge in der sie drankommen
30
- attr_accessor :ordered_colors
31
-
32
- # @!attribute [r] undeployed_blue_pieces
33
- # @return [Array<PieceShape>] Die blauen, nicht gesetzten Spielsteine
34
- attr_accessor :undeployed_blue_pieces
35
-
36
- # @!attribute [r] undeployed_yellow_pieces
37
- # @return [Array<PieceShape>] Die gelben, nicht gesetzten Spielsteine
38
- attr_accessor :undeployed_yellow_pieces
39
-
40
- # @!attribute [r] undeployed_red_pieces
41
- # @return [Array<PieceShape>] Die roten, nicht gesetzten Spielsteine
42
- attr_accessor :undeployed_red_pieces
43
-
44
- # @!attribute [r] undeployed_green_pieces
45
- # @return [Array<PieceShape>] Die grünen, nicht gesetzten Spielsteine
46
- attr_accessor :undeployed_green_pieces
47
-
48
- # @!attribute [r] player_one
49
- # @return [Player] Der erste Spieler
50
- attr_reader :player_one
51
- # @!attribute [r] player_two
52
- # @return [Player] Der zweite Spieler
53
- attr_reader :player_two
54
- # @!attribute [rw] board
55
- # @return [Board] Das aktuelle Spielbrett
56
- attr_accessor :board
57
- # @!attribute [rw] startPiece
58
- # @return [PieceShape] Der Stein, der im ersten Zug von allen Farben gelegt werden muss
59
- attr_accessor :start_piece
60
- # @!attribute [rw] last_move
61
- # @return [Move] Der zuletzt gemachte Zug (ist nil vor dem ersten Zug, also
62
- # bei turn == 0)
63
- attr_accessor :last_move
64
- # @!attribute [rw] condition
65
- # @return [Condition] Gewinner und Gewinngrund, falls das Spiel bereits
66
- # entschieden ist, sonst nil.
67
- attr_accessor :condition
68
-
69
- # Zugriff auf ein Feld des Spielbrettes. Siehe {Board#field}.
70
- def field(x, y)
71
- board.field(x, y)
72
- end
73
-
74
- # Erstellt einen neuen leeren Spielstand.
75
- def initialize
76
- @current_color = Color::RED
77
- @start_color = Color::RED
78
- @board = Board.new
79
- @turn = 0
80
- @undeployed_blue_pieces = PieceShape.to_a
81
- @undeployed_yellow_pieces = PieceShape.to_a
82
- @undeployed_red_pieces = PieceShape.to_a
83
- @undeployed_green_pieces = PieceShape.to_a
84
- @start_piece = GameRuleLogic.get_random_pentomino
85
- end
86
-
87
- # Fügt einen Spieler zum Spielzustand hinzu.
88
- #
89
- # @param player [Player] Der hinzuzufügende Spieler.
90
- def add_player(player)
91
- if player.type == PlayerType::ONE
92
- @player_one = player
93
- elsif player.type == PlayerType::TWO
94
- @player_two = player
95
- end
96
- end
97
-
98
- # @return [Player] Spieler, der gerade an der Reihe ist.
99
- def current_player
100
- turn % 2 == 0 ? player_one : player_two
101
- end
102
-
103
- # @return [Player] Spieler, der gerade nicht an der Reihe ist.
104
- def other_player
105
- turn % 2 == 0 ? player_two : player_one
106
- end
107
-
108
- # @return [PlayerType] Typ des Spielers, der gerade nicht an der Reihe ist.
109
- def other_player_type
110
- other_player.type
111
- end
112
-
113
- # @return [Color] Farbe, der gerade an der Reihe ist.
114
- def current_color
115
- ordered_colors[current_color_index]
116
- end
117
-
118
- # @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die noch nicht gelegt wurden
119
- def undeployed_pieces(color)
120
- case color
121
- when Color::RED
122
- undeployed_red_pieces
123
- when Color::BLUE
124
- undeployed_blue_pieces
125
- when Color::YELLOW
126
- undeployed_yellow_pieces
127
- when Color::GREEN
128
- undeployed_green_pieces
129
- end
130
- end
131
-
132
- # @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die schon gelegt wurden
133
- def deployed_pieces(color)
134
- board.deployed_pieces(color)
135
- end
136
-
137
- # @return [Bool] Ob diese gamestate in der ersten Runde ist
138
- def is_first_move?
139
- round == 1
140
- end
141
-
142
- # Führt einen Zug auf dem Spielzustand aus. Das Spielbrett wird entsprechend
143
- # modifiziert.
144
- #
145
- # @param move [Move] Der auszuführende Zug.
146
- def perform!(move)
147
- GameRuleLogic.perform_move(self, move)
148
- end
149
-
150
- # @return [Boolean] true, falls das Spiel bereits geendet hat, false bei noch
151
- # laufenden Spielen.
152
- def game_ended?
153
- !condition.nil?
154
- end
155
-
156
- # Entfernt die jetzige Farbe aus der Farbrotation
157
- def remove_active_color
158
- ordered_colors.delete current_color
159
- end
160
-
161
- # @return [Player] Der Spieler, der das Spiel gewonnen hat, falls dies schon
162
- # entschieden ist. Sonst false.
163
- def winner
164
- condition.nil? ? nil : condition.winner
165
- end
166
-
167
- # @return [String] Der Grund, warum das Spiel beendet wurde, nil falls das
168
- # Spiel noch läuft.
169
- def winning_reason
170
- condition.nil? ? nil : condition.reason
171
- end
172
-
173
- # Ermittelt die Punkte eines Spielers. Wenn das Spiel durch Erreichen des
174
- # Rundenlimits beendet wird, hat der Spieler mit den meisten Punkten gewonnen.
175
- #
176
- # @param player [Player] Der Spieler, dessen Punkte berechnet werden sollen.
177
- # @return [Integer] Die Punkte des Spielers
178
- def points_for_player(_player)
179
- # TODO
180
- -1
181
- end
182
-
183
- def ==(other)
184
- turn == other.turn &&
185
- start_color == other.start_color &&
186
- current_color == other.current_color &&
187
- blue == other.blue &&
188
- yellow == other.yellow &&
189
- red == other.red &&
190
- green == other.green &&
191
- board == other.board &&
192
- lastMove == other.lastMove &&
193
- condition == other.condition
194
- end
195
-
196
- # Erzeugt eine Kopie des Spielzustandes. Änderungen an dieser Kopie
197
- # beeinflussen den originalen Spielzustand nicht. Die Kopie kann also zum
198
- # testen von Spielzügen genutzt werden.
199
- def clone
200
- Marshal.load(Marshal.dump(self))
201
- end
202
-
203
- # Wechselt den Spieler, der aktuell an der Reihe ist.
204
- def switch_current_player
205
- @current_player_color = other_player_color
206
- end
207
-
208
- # @return [Array<Field>] Alle Felder mit Blöcken des Spielers, der gerade an der Reihe ist.
209
- def own_fields
210
- board.fields_of_color(current_color)
211
- end
212
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './util/constants'
4
+ require_relative 'player'
5
+ require_relative 'board'
6
+ require_relative 'condition'
7
+ require_relative 'color'
8
+
9
+ # Ein Spielzustand. Wird vom Server an die Computerspieler übermittelt und
10
+ # enthält alles, was der Computerspieler wissen muss, um einen Zug zu machen.
11
+ #
12
+ # Um eine Liste der gerade möglichen Züge zu bekommen, gibt es die Methode
13
+ # {GameState#possible_moves}.
14
+ class GameState
15
+ # @!attribute [rw] turn
16
+ # @return [Integer] Aktuelle Zugnummer (von 0 beginnend)
17
+ attr_accessor :turn
18
+
19
+ # @!attribute [r] player_one
20
+ # @return [Player] Der erste Spieler
21
+ attr_reader :player_one
22
+
23
+ # @!attribute [r] player_two
24
+ # @return [Player] Der zweite Spieler
25
+ attr_reader :player_two
26
+
27
+ # @!attribute [rw] start_team
28
+ # @return [Team] Der Spieler der zuerst zieht
29
+ attr_accessor :start_team
30
+
31
+ # @!attribute [rw] board
32
+ # @return [Board] Das aktuelle Spielbrett
33
+ attr_accessor :board
34
+
35
+ # @!attribute [rw] last_move
36
+ # @return [Move] Der zuletzt gemachte Zug (ist nil vor dem ersten Zug, also
37
+ # bei turn == 0)
38
+ attr_accessor :last_move
39
+
40
+ # @!attribute [rw] condition
41
+ # @return [Condition] Gewinner und Gewinngrund, falls das Spiel bereits
42
+ # entschieden ist, sonst nil.
43
+ attr_accessor :condition
44
+
45
+ # Zugriff auf ein Feld des Spielbrettes. Siehe {Board#field}.
46
+ def field(x, y)
47
+ board.field(x, y)
48
+ end
49
+
50
+ # Erstellt einen neuen leeren Spielstand.
51
+ def initialize
52
+ @board = Board.new
53
+ @turn = 0
54
+ end
55
+
56
+ # Fügt einen Spieler zum Spielzustand hinzu.
57
+ #
58
+ # @param player [Player] Der hinzuzufügende Spieler.
59
+ def add_player(player)
60
+ case player.color
61
+ when Color::RED
62
+ @player_one = player
63
+ when Color::BLUE
64
+ @player_two = player
65
+ end
66
+ end
67
+
68
+ # @return [Player] Spieler, der gerade an der Reihe ist.
69
+ def current_player
70
+ turn.even? ? player_one : player_two
71
+ end
72
+
73
+ # @return [Player] Spieler, der gerade nicht an der Reihe ist.
74
+ def other_player
75
+ turn.even? ? player_two : player_one
76
+ end
77
+
78
+ # @return [Team] Typ des Spielers, der gerade nicht an der Reihe ist.
79
+ def other_team
80
+ other_player.type
81
+ end
82
+
83
+ # @return [Integer] Aktuelle Rundennummer (von 1 beginnend)
84
+ def round
85
+ turn / 2 + 1
86
+ end
87
+
88
+ # @return [Bool] Ob diese gamestate in der ersten Runde ist
89
+ def is_first_move?
90
+ round == 1
91
+ end
92
+
93
+ # Führt einen Zug auf dem Spielzustand aus. Das Spielbrett wird entsprechend
94
+ # modifiziert.
95
+ #
96
+ # @param move [Move] Der auszuführende Zug.
97
+ def perform!(move)
98
+ GameRuleLogic.perform_move(self, move)
99
+ end
100
+
101
+ # @return [Boolean] true, falls das Spiel bereits geendet hat, false bei noch
102
+ # laufenden Spielen.
103
+ def game_ended?
104
+ !condition.nil?
105
+ end
106
+
107
+ # @return [Player] Der Spieler, der das Spiel gewonnen hat, falls dies schon
108
+ # entschieden ist. Sonst false.
109
+ def winner
110
+ condition.nil? ? nil : condition.winner
111
+ end
112
+
113
+ # @return [String] Der Grund, warum das Spiel beendet wurde, nil falls das
114
+ # Spiel noch läuft.
115
+ def winning_reason
116
+ condition.nil? ? nil : condition.reason
117
+ end
118
+
119
+ # Ermittelt die Punkte eines Spielers. Wenn das Spiel durch Erreichen des
120
+ # Rundenlimits beendet wird, hat der Spieler mit den meisten Punkten gewonnen.
121
+ #
122
+ # @param player [Player] Der Spieler, dessen Punkte berechnet werden sollen.
123
+ # @return [Integer] Die Punkte des Spielers
124
+ def points_for_player(_player)
125
+ # TODO
126
+ -1
127
+ end
128
+
129
+ def ==(other)
130
+ turn == other.turn &&
131
+ start_color == other.start_color &&
132
+ current_color == other.current_color &&
133
+ blue == other.blue &&
134
+ yellow == other.yellow &&
135
+ red == other.red &&
136
+ green == other.green &&
137
+ board == other.board &&
138
+ lastMove == other.lastMove &&
139
+ condition == other.condition
140
+ end
141
+
142
+ # Erzeugt eine Kopie des Spielzustandes. Änderungen an dieser Kopie
143
+ # beeinflussen den originalen Spielzustand nicht. Die Kopie kann also zum
144
+ # testen von Spielzügen genutzt werden.
145
+ def clone
146
+ Marshal.load(Marshal.dump(self))
147
+ end
148
+
149
+ # Wechselt den Spieler, der aktuell an der Reihe ist.
150
+ def switch_current_player
151
+ @current_player_color = other_player_color
152
+ end
153
+
154
+ # @return [Array<Field>] Alle Felder mit Blöcken des Spielers, der gerade an der Reihe ist.
155
+ def own_fields
156
+ board.fields_of_color(current_player.color)
157
+ end
158
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'has_hints'
4
+
5
+ # Ein Move repräsentiert eine Bewegung eines Steins auf dem Spielbrett
6
+ class Move
7
+ include HasHints
8
+
9
+ # @!attribute [r] Koordinaten von dem der Spielstein in diesem Zug wegbewegt wird
10
+ # @return [Coordinates]
11
+ attr_reader :from
12
+
13
+ # @!attribute [r] Koordinaten zu denen der Spielstein in diesem Zug hinbewegt wird
14
+ # @return [Coordinates]
15
+ attr_reader :to
16
+
17
+ # Erstellt ein neuen Zug.
18
+ def initialize(from, to)
19
+ @from = from
20
+ @to = to
21
+ @hints = []
22
+ end
23
+
24
+ def piece(gamestate)
25
+ gamestate.board.field_at(from).piece
26
+ end
27
+
28
+ def piece_t(gamestate)
29
+ gamestate.board.field_at(to).piece
30
+ end
31
+
32
+ def ==(other)
33
+ from == other.from &&
34
+ to == other.to
35
+ end
36
+
37
+ # @return [String] Gibt die String-Repräsentation zurück
38
+ def to_s
39
+ "Move(#{from}->#{to})"
40
+ end
41
+ end
@@ -2,81 +2,80 @@
2
2
 
3
3
  # Ein Spielstein mit Ausrichtung, Koordinaten und Farbe
4
4
  class Piece
5
- # @!attribute [r] Farbe
5
+ include Constants
6
+
7
+ # @!attribute [rw] Color
6
8
  # @return [Color]
7
- attr_reader :color
9
+ attr_accessor :color
8
10
 
9
- # @!attribute [r] Form
10
- # @return [PieceShape]
11
- attr_reader :kind
11
+ # @!attribute [r] Typ des Spielsteins
12
+ # @return [PieceType]
13
+ attr_reader :type
12
14
 
13
- # @!attribute [r] Drehung
14
- # @return [Rotation]
15
- attr_reader :rotation
16
-
17
- # @!attribute [r] Ob der Stein an der Y-Achse gespiegelt ist
18
- # @return [Boolean]
19
- attr_reader :is_flipped
20
-
21
- # @!attribute [r] Koordinaten
15
+ # @!attribute [rw] Koordinaten
22
16
  # @return [Coordinates]
23
- attr_reader :position
17
+ attr_accessor :position
24
18
 
25
- attr_reader :coords
19
+ # @!attribute [rw] tower_height
20
+ # @return [Integer] Die Anzahl Spielsteine übereinander inklusive des obersten
21
+ attr_accessor :height
26
22
 
27
- # Erstellt einen neuen leeren Spielstein.
28
- def initialize(color, kind, rotation = Rotation::NONE, is_flipped = false, position = Coordinates.origin)
23
+ # Erstellt einen neuen Spielstein.
24
+ def initialize(color, type, position = Coordinates.origin, height = 0)
29
25
  @color = color
30
- @kind = kind
31
- @rotation = rotation
32
- @is_flipped = is_flipped
26
+ @type = type
33
27
  @position = position
34
-
35
- @coords = coords_priv
36
- end
37
-
38
- # Dreht den Stein
39
- def rotate!(rotation)
40
- @rotation = @rotation.rotate(rotation)
41
- @coords = coords_priv
42
- end
43
-
44
- # Flipped den Stein
45
- def flip!(f = true)
46
- @is_flipped = @is_flipped ^ f
47
- @coords = coords_priv
28
+ @height = height
48
29
  end
49
30
 
50
- # Setzt den Stein auf eine Position
51
- def locate!(position)
52
- @position = position
53
- @coords = coords_priv
54
- end
55
-
56
- # Verschiebt den Stein
57
- def move!(shift)
58
- @position = position + shift
59
- @coords = coords_priv
31
+ # Berechnet die Koordinaten zu denen sich dieser Spielstein bewegen könnte.
32
+ #
33
+ # @return [Array<Coordinates>] Die Zielkoordinaten
34
+ def target_coords
35
+ xdir = 0
36
+ if color == Color::RED
37
+ xdir = 1
38
+ else
39
+ xdir = -1
40
+ end
41
+
42
+ case type
43
+ when PieceType::Herzmuschel
44
+ coords = [Coordinates.new(xdir,-1), Coordinates.new(xdir,1)]
45
+ when PieceType::Moewe
46
+ coords = [Coordinates.new(1,0), Coordinates.new(-1,0), Coordinates.new(0,1),
47
+ Coordinates.new(0,-1)]
48
+ when PieceType::Seestern
49
+ coords = [Coordinates.new(xdir,0), Coordinates.new(1,1), Coordinates.new(-1,1),
50
+ Coordinates.new(1,-1), Coordinates.new(-1,-1)]
51
+ when PieceType::Robbe
52
+ coords = [Coordinates.new(-1,2), Coordinates.new(1,2), Coordinates.new(-2,1),
53
+ Coordinates.new(2,1), Coordinates.new(-1,-2), Coordinates.new(1,-2),
54
+ Coordinates.new(-2,-1), Coordinates.new(2,-1)]
55
+ end
56
+
57
+ coords.map{ |x| x + position }.to_a
58
+ coords.map{ |x| x + position }.select{ |c| c.x >= 0 && c.y >=0 && c.x < BOARD_SIZE && c.y < BOARD_SIZE}.to_a
60
59
  end
61
60
 
62
61
  def ==(other)
63
- color == other.color &&
64
- coords == other.coords
62
+ !other.nil? &&
63
+ color == other.color &&
64
+ position == other.position &&
65
+ type == other.type
65
66
  end
66
67
 
68
+ # @return [String] Gibt die String-Repräsentation zurück
67
69
  def to_s
68
- "#{color.key} #{kind.key} at #{position} rotation #{rotation.key}#{is_flipped ? ' (flipped)' : ''}"
70
+ "#{color.key} #{type.key} at #{position}"
69
71
  end
70
72
 
71
- def inspect
72
- to_s
73
+ # @return [String] Gibt eine Kurzfassung der String-Repräsentation zurück
74
+ def to_ss
75
+ "#{color.key.to_s[0]}#{type.key.to_s[0]}"
73
76
  end
74
77
 
75
- private
76
-
77
- def coords_priv
78
- kind.transform(@rotation, @is_flipped).transform do |it|
79
- Coordinates.new(it.x + @position.x, it.y + @position.y)
80
- end.coordinates
78
+ def inspect
79
+ to_s
81
80
  end
82
81
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'typesafe_enum'
4
+
5
+ # Die Spielsteintypen. Herzmuschel, Möwe, Seestern und Robbe
6
+ class PieceType < TypesafeEnum::Base
7
+ new :Herzmuschel, 'C'
8
+ new :Moewe, 'G'
9
+ new :Seestern, 'S'
10
+ new :Robbe, 'R'
11
+
12
+ # @return [String] Gibt den color namen zurück
13
+ def to_s
14
+ self.key.to_s
15
+ end
16
+ end
@@ -7,16 +7,22 @@ class Player
7
7
  # @return [String] der Name des Spielers, hat keine Auswirkungen auf das Spiel
8
8
  attr_reader :name
9
9
 
10
- # @!attribute [r] type
11
- # @return [PlayerType] erster (PlayerType::ONE) oder zweiter (PlayerType::TWO) Spieler
12
- attr_reader :type
10
+ # @!attribute [r] color
11
+ # @return [Color] erster (Color::RED) oder zweiter (Color::BLUE) Spieler
12
+ attr_reader :color
13
+
14
+ # @!attribute [rw] amber
15
+ # @return [Integer] Anzahl Bernsteine die dieser Spieler gesammelt hat
16
+ attr_accessor :amber
13
17
 
14
18
  # Konstruktor
15
- # @param type [PlayerType] Erster oder zweiter
19
+ # @param type [Color] Rot oder blau
16
20
  # @param name [String] Name
17
- def initialize(type, name)
18
- @type = type
21
+ # @param amber [Integer] Menge des Bernsteins die der Spieler hat
22
+ def initialize(color, name, amber = 0)
23
+ @color = color
19
24
  @name = name
25
+ @amber = amber
20
26
  end
21
27
 
22
28
  def ==(other)