software_challenge_client 21.2.0 → 22.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,7 @@ require_relative './util/constants'
4
4
  require_relative 'player'
5
5
  require_relative 'board'
6
6
  require_relative 'condition'
7
+ require_relative 'color'
7
8
 
8
9
  # Ein Spielzustand. Wird vom Server an die Computerspieler übermittelt und
9
10
  # enthält alles, was der Computerspieler wissen muss, um einen Zug zu machen.
@@ -19,36 +20,6 @@ class GameState
19
20
  # @return [Integer] Aktuelle Rundennummer (von 1 beginnend)
20
21
  attr_accessor :round
21
22
 
22
- # @!attribute [rw] startColor
23
- # @return [Color] Die Farbe, die zuerst legen darf
24
- attr_accessor :start_color
25
-
26
- # @!attribute [rw] valid_colors
27
- # @return [Array<Color>] Ein Array aller Farben die ziehen können in
28
- # der Reihenfolge in der sie drankommen
29
- attr_accessor :valid_colors
30
-
31
- # @!attribute [rw] ordered_colors
32
- # @return [Array<Color>] Ein Array aller Farben in
33
- # der Reihenfolge in der sie drankommen
34
- attr_accessor :ordered_colors
35
-
36
- # @!attribute [r] undeployed_blue_pieces
37
- # @return [Array<PieceShape>] Die blauen, nicht gesetzten Spielsteine
38
- attr_accessor :undeployed_blue_pieces
39
-
40
- # @!attribute [r] undeployed_yellow_pieces
41
- # @return [Array<PieceShape>] Die gelben, nicht gesetzten Spielsteine
42
- attr_accessor :undeployed_yellow_pieces
43
-
44
- # @!attribute [r] undeployed_red_pieces
45
- # @return [Array<PieceShape>] Die roten, nicht gesetzten Spielsteine
46
- attr_accessor :undeployed_red_pieces
47
-
48
- # @!attribute [r] undeployed_green_pieces
49
- # @return [Array<PieceShape>] Die grünen, nicht gesetzten Spielsteine
50
- attr_accessor :undeployed_green_pieces
51
-
52
23
  # @!attribute [r] player_one
53
24
  # @return [Player] Der erste Spieler
54
25
  attr_reader :player_one
@@ -57,14 +28,14 @@ class GameState
57
28
  # @return [Player] Der zweite Spieler
58
29
  attr_reader :player_two
59
30
 
31
+ # @!attribute [rw] start_team
32
+ # @return [Team] Der Spieler der zuerst zieht
33
+ attr_accessor :start_team
34
+
60
35
  # @!attribute [rw] board
61
36
  # @return [Board] Das aktuelle Spielbrett
62
37
  attr_accessor :board
63
38
 
64
- # @!attribute [rw] startPiece
65
- # @return [PieceShape] Der Stein, der im ersten Zug von allen Farben gelegt werden muss
66
- attr_accessor :start_piece
67
-
68
39
  # @!attribute [rw] last_move
69
40
  # @return [Move] Der zuletzt gemachte Zug (ist nil vor dem ersten Zug, also
70
41
  # bei turn == 0)
@@ -82,25 +53,18 @@ class GameState
82
53
 
83
54
  # Erstellt einen neuen leeren Spielstand.
84
55
  def initialize
85
- @ordered_colors = [Color::BLUE, Color::YELLOW, Color::RED, Color::GREEN]
86
56
  @board = Board.new
87
57
  @turn = 0
88
- @undeployed_blue_pieces = PieceShape.to_a
89
- @undeployed_yellow_pieces = PieceShape.to_a
90
- @undeployed_red_pieces = PieceShape.to_a
91
- @undeployed_green_pieces = PieceShape.to_a
92
- @start_piece = GameRuleLogic.get_random_pentomino
93
- @start_color = Color::BLUE
94
58
  end
95
59
 
96
60
  # Fügt einen Spieler zum Spielzustand hinzu.
97
61
  #
98
62
  # @param player [Player] Der hinzuzufügende Spieler.
99
63
  def add_player(player)
100
- case player.type
101
- when PlayerType::ONE
64
+ case player.color
65
+ when Color::RED
102
66
  @player_one = player
103
- when PlayerType::TWO
67
+ when Color::BLUE
104
68
  @player_two = player
105
69
  end
106
70
  end
@@ -115,45 +79,11 @@ class GameState
115
79
  turn.even? ? player_two : player_one
116
80
  end
117
81
 
118
- # @return [PlayerType] Typ des Spielers, der gerade nicht an der Reihe ist.
119
- def other_player_type
82
+ # @return [Team] Typ des Spielers, der gerade nicht an der Reihe ist.
83
+ def other_team
120
84
  other_player.type
121
85
  end
122
86
 
123
- # @return [Color] Der jetzige Index in der Zug Reihenfolge der Farben.
124
- def current_color_index
125
- turn % 4
126
- end
127
-
128
- # @return [Color] Farbe, der gerade an der Reihe ist.
129
- def current_color
130
- ordered_colors[current_color_index]
131
- end
132
-
133
- # @return [Color] Farbe des aktuellen Spielers, die gerade nicht an der Reihe ist.
134
- def other_color
135
- Color.find_by_ord((current_color.ord + 2) % 4)
136
- end
137
-
138
- # @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die noch nicht gelegt wurden
139
- def undeployed_pieces(color)
140
- case color
141
- when Color::RED
142
- undeployed_red_pieces
143
- when Color::BLUE
144
- undeployed_blue_pieces
145
- when Color::YELLOW
146
- undeployed_yellow_pieces
147
- when Color::GREEN
148
- undeployed_green_pieces
149
- end
150
- end
151
-
152
- # @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die schon gelegt wurden
153
- def deployed_pieces(color)
154
- board.deployed_pieces(color)
155
- end
156
-
157
87
  # @return [Bool] Ob diese gamestate in der ersten Runde ist
158
88
  def is_first_move?
159
89
  round == 1
@@ -173,11 +103,6 @@ class GameState
173
103
  !condition.nil?
174
104
  end
175
105
 
176
- # Entfernt die jetzige Farbe aus der Farbrotation
177
- def remove_active_color
178
- ordered_colors.delete current_color
179
- end
180
-
181
106
  # @return [Player] Der Spieler, der das Spiel gewonnen hat, falls dies schon
182
107
  # entschieden ist. Sonst false.
183
108
  def winner
@@ -227,6 +152,6 @@ class GameState
227
152
 
228
153
  # @return [Array<Field>] Alle Felder mit Blöcken des Spielers, der gerade an der Reihe ist.
229
154
  def own_fields
230
- board.fields_of_color(current_color)
155
+ board.fields_of_color(current_player.color)
231
156
  end
232
157
  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,88 +2,77 @@
2
2
 
3
3
  # Ein Spielstein mit Ausrichtung, Koordinaten und Farbe
4
4
  class Piece
5
- # @!attribute [r] Farbe
5
+ # @!attribute [rw] Color
6
6
  # @return [Color]
7
- attr_reader :color
7
+ attr_accessor :color
8
8
 
9
- # @!attribute [r] Form
10
- # @return [PieceShape]
11
- attr_reader :kind
9
+ # @!attribute [r] Typ des Spielsteins
10
+ # @return [PieceType]
11
+ attr_reader :type
12
12
 
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
13
+ # @!attribute [rw] Koordinaten
22
14
  # @return [Coordinates]
23
- attr_reader :position
15
+ attr_accessor :position
24
16
 
25
- # @!attribute [r] Ein Array der Positionsdaten aller Bestandteile von dem Stein in Board Koordinaten, also schon ggf. gedreht und um position versetzt.
26
- # return [Array<Coordinates>]
27
- attr_reader :coords
17
+ # @!attribute [rw] tower_height
18
+ # @return [Integer] Die Anzahl Spielsteine übereinander inklusive des obersten
19
+ attr_accessor :height
28
20
 
29
- # Erstellt einen neuen leeren Spielstein.
30
- def initialize(color, kind, rotation = Rotation::NONE, is_flipped = false, position = Coordinates.origin)
21
+ # Erstellt einen neuen Spielstein.
22
+ def initialize(color, type, position = Coordinates.origin, height = 0)
31
23
  @color = color
32
- @kind = kind
33
- @rotation = rotation
34
- @is_flipped = is_flipped
24
+ @type = type
35
25
  @position = position
36
-
37
- @coords = coords_priv
38
- end
39
-
40
- # Dreht den Stein
41
- def rotate!(rotation)
42
- @rotation = @rotation.rotate(rotation)
43
- @coords = coords_priv
26
+ @height = height
44
27
  end
45
28
 
46
- # Flipped den Stein
47
- def flip!(f = true)
48
- @is_flipped = @is_flipped ^ f
49
- @coords = coords_priv
50
- end
51
-
52
- # Setzt den Stein auf eine Position
53
- def locate!(position)
54
- @position = position
55
- @coords = coords_priv
56
- end
57
-
58
- # Verschiebt den Stein
59
- def move!(shift)
60
- @position = position + shift
61
- @coords = coords_priv
62
- end
63
-
64
- # Gibt die Fläche der transformierten Steinform von diesem Stein zurück
65
- def area()
66
- CoordinateSet.new(coords).area
29
+ # Berechnet die Koordinaten zu denen sich dieser Spielstein bewegen könnte.
30
+ #
31
+ # @return [Array<Coordinates>] Die Zielkoordinaten
32
+ def target_coords
33
+ xdir = 0
34
+ if color == Color::RED
35
+ xdir = 1
36
+ else
37
+ xdir = -1
38
+ end
39
+
40
+ case type
41
+ when PieceType::Herzmuschel
42
+ coords = [Coordinates.new(xdir,-1), Coordinates.new(xdir,1)]
43
+ when PieceType::Moewe
44
+ coords = [Coordinates.new(1,0), Coordinates.new(-1,0), Coordinates.new(0,1),
45
+ Coordinates.new(0,-1)]
46
+ when PieceType::Seestern
47
+ coords = [Coordinates.new(xdir,0), Coordinates.new(1,1), Coordinates.new(-1,1),
48
+ Coordinates.new(1,-1), Coordinates.new(-1,-1)]
49
+ when PieceType::Robbe
50
+ coords = [Coordinates.new(-1,2), Coordinates.new(1,2), Coordinates.new(-2,1),
51
+ Coordinates.new(2,1), Coordinates.new(-1,-2), Coordinates.new(1,-2),
52
+ Coordinates.new(-2,-1), Coordinates.new(2,-1)]
53
+ end
54
+
55
+ coords.map{ |x| x + position }.to_a
67
56
  end
68
57
 
69
58
  def ==(other)
70
- color == other.color &&
71
- coords == other.coords
59
+ !other.nil? &&
60
+ color == other.color &&
61
+ position == other.position &&
62
+ type == other.type
72
63
  end
73
64
 
65
+ # @return [String] Gibt die String-Repräsentation zurück
74
66
  def to_s
75
- "#{color.key} #{kind.key} at #{position} rotation #{rotation.key}#{is_flipped ? ' (flipped)' : ''}"
67
+ "#{color.key} #{type.key} at #{position}"
76
68
  end
77
69
 
78
- def inspect
79
- to_s
70
+ # @return [String] Gibt eine Kurzfassung der String-Repräsentation zurück
71
+ def to_ss
72
+ "#{color.key.to_s[0]}#{type.key.to_s[0]}"
80
73
  end
81
74
 
82
- private
83
-
84
- def coords_priv
85
- kind.transform(@rotation, @is_flipped).transform do |it|
86
- Coordinates.new(it.x + @position.x, it.y + @position.y)
87
- end.coordinates
75
+ def inspect
76
+ to_s
88
77
  end
89
78
  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)
@@ -2,8 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
  require 'socket'
4
4
  require_relative 'board'
5
- require_relative 'set_move'
6
- require_relative 'skip_move'
5
+ require_relative 'move'
6
+ require_relative 'piece_type'
7
7
  require_relative 'player'
8
8
  require_relative 'network'
9
9
  require_relative 'client_interface'
@@ -61,26 +61,23 @@ class Protocol
61
61
  case name
62
62
  when 'board'
63
63
  logger.debug @gamestate.board.to_s
64
- when 'color'
65
- if @context[:color] == :valid_colors
66
- @gamestate.valid_colors << Color.to_a.find {|s| s.key == @context[:last_text].to_sym }
64
+ when 'startTeam'
65
+ @gamestate.add_player(Player.new(Color::RED, "ONE", 0))
66
+ @gamestate.add_player(Player.new(Color::BLUE, "TWO", 0))
67
+ if @context[:last_text] == "ONE"
68
+ @gamestate.start_team = @gamestate.player_one
69
+ else
70
+ @gamestate.start_team = @gamestate.player_two
67
71
  end
68
- when 'shape'
69
- case @context[:piece_target]
70
- when :blue_shapes
71
- last = @context[:last_text]
72
- arr = PieceShape.to_a
73
- shape = arr.find {|s| s.key == @context[:last_text].to_sym }
74
- @gamestate.undeployed_blue_pieces << shape
75
- when :yellow_shapes
76
- shape = PieceShape.to_a.find {|s| s.key == @context[:last_text].to_sym }
77
- @gamestate.undeployed_yellow_pieces << shape
78
- when :red_shapes
79
- shape = PieceShape.to_a.find {|s| s.key == @context[:last_text].to_sym }
80
- @gamestate.undeployed_red_pieces << shape
81
- when :green_shapes
82
- shape = PieceShape.to_a.find {|s| s.key == @context[:last_text].to_sym }
83
- @gamestate.undeployed_green_pieces << shape
72
+ when 'team'
73
+ @context[:team] = @context[:last_text]
74
+ when 'int'
75
+ if @context[:team] == "ONE"
76
+ logger.info 'Got player one amber'
77
+ @gamestate.player_one.amber = @context[:last_text].to_i
78
+ else
79
+ logger.info 'Got player two amber'
80
+ @gamestate.player_two.amber = @context[:last_text].to_i
84
81
  end
85
82
  end
86
83
  end
@@ -99,7 +96,7 @@ class Protocol
99
96
  when 'data'
100
97
  logger.debug "data(class) : #{attrs['class']}"
101
98
  @context[:data_class] = attrs['class']
102
- if attrs['class'] == 'sc.framework.plugins.protocol.MoveRequest'
99
+ if attrs['class'] == 'moveRequest'
103
100
  @client.gamestate = gamestate
104
101
  move = @client.move_requested
105
102
  sendString(move_to_xml(move))
@@ -117,85 +114,31 @@ class Protocol
117
114
  logger.debug 'new gamestate'
118
115
  @gamestate = GameState.new
119
116
  @gamestate.turn = attrs['turn'].to_i
120
- @gamestate.round = attrs['round'].to_i
121
- @gamestate.start_piece = PieceShape.to_a.find {|s| s.key == attrs['startPiece'].to_sym }
117
+ @gamestate.round = @gamestate.turn / 2
122
118
  logger.debug "Round: #{@gamestate.round}, Turn: #{@gamestate.turn}"
123
- when 'first'
124
- logger.debug 'new first player'
125
- player = Player.new(PlayerType::ONE, attrs['displayName'])
126
- @gamestate.add_player(player)
127
- @context[:player] = player
128
- @context[:color] = :one
129
- when 'second'
130
- logger.debug 'new second player'
131
- player = Player.new(PlayerType::TWO, attrs['displayName'])
132
- @gamestate.add_player(player)
133
- @context[:player] = player
134
- @context[:color] = :two
135
- when 'validColors'
136
- @context[:color] = :valid_colors
137
- @gamestate.valid_colors = []
138
119
  when 'board'
139
120
  logger.debug 'new board'
140
121
  @gamestate.board = Board.new()
141
- when 'field'
142
- x = attrs['x'].to_i
143
- y = attrs['y'].to_i
144
- color = Color.find_by_key(attrs['content'].to_sym)
145
- field = Field.new(x, y, color)
146
- @gamestate.board.add_field(field)
147
- @context[:piece_target] = :field
148
- @context[:field] = field
149
- when 'blueShapes'
150
- @context[:piece_target] = :blue_shapes
151
- @gamestate.undeployed_blue_pieces = []
152
- when 'yellowShapes'
153
- @context[:piece_target] = :yellow_shapes
154
- @gamestate.undeployed_yellow_pieces = []
155
- when 'redShapes'
156
- @context[:piece_target] = :red_shapes
157
- @gamestate.undeployed_red_pieces = []
158
- when 'greenShapes'
159
- @context[:piece_target] = :green_shapes
160
- @gamestate.undeployed_green_pieces = []
122
+ when 'pieces'
123
+ @context[:entry] = :pieces
124
+ when 'coordinates'
125
+ @context[:x] = attrs['x'].to_i
126
+ @context[:y] = attrs['y'].to_i
161
127
  when 'piece'
162
- color = Color.find_by_key(attrs['color'].to_sym)
163
- kind = PieceShape.find_by_key(attrs['kind'].to_sym)
164
- rotation = Rotation.find_by_key(attrs['rotation'].to_sym)
165
- is_flipped = attrs['isFlipped'].downcase == "true"
166
- piece = Piece.new(color, kind, rotation, is_flipped, Coordinates.origin)
167
- case @context[:piece_target]
168
- when :blue_shapes
169
- @gamestate.undeployed_blue_pieces << piece
170
- when :yellow_shapes
171
- @gamestate.undeployed_yellow_pieces << piece
172
- when :red_shapes
173
- @gamestate.green_red_pieces << piece
174
- when :green_shapes
175
- @gamestate.undeployed_green_pieces << piece
176
- when :last_move
177
- @context[:last_move_piece] = piece
178
- else
179
- raise "unknown piece target #{@context[:piece_target]}"
180
- end
181
- when 'lastMove'
182
- type = attrs['class']
183
- if type == 'skipmove'
184
- @gamestate.last_move = SkipMove.new
185
- else
186
- @context[:last_move_type] = type
187
- @context[:piece_target] = :last_move
188
- end
189
- when 'position'
190
- case @context[:piece_target]
191
- when :last_move
192
- x = attrs['x'].to_i
193
- y = attrs['y'].to_i
194
- piece = @context[:last_move_piece]
195
- @gamestate.last_move = SetMove.new(Piece.new(piece.color, piece.kind, piece.rotation, piece.is_flipped, Coordinates.new(x, y)))
196
- end
197
- when 'startColor'
198
- @gamestate.start_color = Color::BLUE
128
+ x = @context[:x]
129
+ y = @context[:y]
130
+ team = Team.find_by_key(attrs['team'].to_sym)
131
+ type = PieceType.find_by_key(attrs['type'].to_sym)
132
+ count = attrs['count'].to_i
133
+ field = Field.new(x, y, Piece.new(team.to_c, type, Coordinates.new(x, y), count))
134
+ @gamestate.board.add_field(field)
135
+ when 'from'
136
+ @context[:from] = Coordinates.new(attrs['x'].to_i, attrs['y'].to_i)
137
+ when 'to'
138
+ from = @context[:from]
139
+ @gamestate.last_move = Move.new(Coordinates.new(from.x, from.y), Coordinates.new(attrs['x'].to_i, attrs['y'].to_i))
140
+ when 'ambers'
141
+ @context[:entry] = :ambers
199
142
  when 'winner'
200
143
  # TODO
201
144
  # winning_player = parsePlayer(attrs)
@@ -239,28 +182,21 @@ class Protocol
239
182
  # @param move [Move] The move to convert to XML.
240
183
  def move_to_xml(move)
241
184
  builder = Builder::XmlMarkup.new(indent: 2)
185
+
186
+ if move.nil?
187
+ raise 'nil moves are not sendable!'
188
+ end
189
+
242
190
  # Converting every the move here instead of requiring the Move
243
191
  # class interface to supply a method which returns the XML
244
192
  # because XML-generation should be decoupled from internal data
245
193
  # structures.
246
- case move
247
- when SetMove
248
- builder.data(class: 'sc.plugin2021.SetMove') do |data|
249
- data.piece(color: move.piece.color, kind: move.piece.kind, rotation: move.piece.rotation, isFlipped: move.piece.is_flipped) do |piece|
250
- piece.position(x: move.piece.position.x, y: move.piece.position.y)
251
- end
252
- move.hints.each do |hint|
253
- data.hint(content: hint.content)
254
- end
255
- end
256
- when SkipMove
257
- builder.data(class: 'sc.plugin2021.SkipMove') do |data|
258
- data.color(@gamestate.current_color.key.to_s)
259
- move.hints.each do |hint|
260
- data.hint(content: hint.content)
261
- end
262
- end
194
+
195
+ builder.data(class: 'move') do |d|
196
+ d.from(x: move.from.x, y: move.from.y)
197
+ d.to(x: move.to.x, y: move.to.y)
263
198
  end
199
+
264
200
  builder.target!
265
201
  end
266
202
  end