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.
@@ -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.
@@ -14,53 +15,32 @@ class GameState
14
15
  # @!attribute [rw] turn
15
16
  # @return [Integer] Aktuelle Zugnummer (von 0 beginnend)
16
17
  attr_accessor :turn
18
+
17
19
  # @!attribute [rw] round
18
20
  # @return [Integer] Aktuelle Rundennummer (von 1 beginnend)
19
21
  attr_accessor :round
20
22
 
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
23
  # @!attribute [r] player_one
49
24
  # @return [Player] Der erste Spieler
50
25
  attr_reader :player_one
26
+
51
27
  # @!attribute [r] player_two
52
28
  # @return [Player] Der zweite Spieler
53
29
  attr_reader :player_two
30
+
31
+ # @!attribute [rw] start_team
32
+ # @return [Team] Der Spieler der zuerst zieht
33
+ attr_accessor :start_team
34
+
54
35
  # @!attribute [rw] board
55
36
  # @return [Board] Das aktuelle Spielbrett
56
37
  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
38
+
60
39
  # @!attribute [rw] last_move
61
40
  # @return [Move] Der zuletzt gemachte Zug (ist nil vor dem ersten Zug, also
62
41
  # bei turn == 0)
63
42
  attr_accessor :last_move
43
+
64
44
  # @!attribute [rw] condition
65
45
  # @return [Condition] Gewinner und Gewinngrund, falls das Spiel bereits
66
46
  # entschieden ist, sonst nil.
@@ -73,67 +53,37 @@ class GameState
73
53
 
74
54
  # Erstellt einen neuen leeren Spielstand.
75
55
  def initialize
76
- @current_color = Color::RED
77
- @start_color = Color::RED
78
56
  @board = Board.new
79
57
  @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
58
  end
86
59
 
87
60
  # Fügt einen Spieler zum Spielzustand hinzu.
88
61
  #
89
62
  # @param player [Player] Der hinzuzufügende Spieler.
90
63
  def add_player(player)
91
- if player.type == PlayerType::ONE
64
+ case player.color
65
+ when Color::RED
92
66
  @player_one = player
93
- elsif player.type == PlayerType::TWO
67
+ when Color::BLUE
94
68
  @player_two = player
95
69
  end
96
70
  end
97
71
 
98
72
  # @return [Player] Spieler, der gerade an der Reihe ist.
99
73
  def current_player
100
- turn % 2 == 0 ? player_one : player_two
74
+ turn.even? ? player_one : player_two
101
75
  end
102
76
 
103
77
  # @return [Player] Spieler, der gerade nicht an der Reihe ist.
104
78
  def other_player
105
- turn % 2 == 0 ? player_two : player_one
79
+ turn.even? ? player_two : player_one
106
80
  end
107
81
 
108
- # @return [PlayerType] Typ des Spielers, der gerade nicht an der Reihe ist.
109
- def other_player_type
82
+ # @return [Team] Typ des Spielers, der gerade nicht an der Reihe ist.
83
+ def other_team
110
84
  other_player.type
111
85
  end
112
86
 
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
87
  # @return [Bool] Ob diese gamestate in der ersten Runde ist
138
88
  def is_first_move?
139
89
  round == 1
@@ -153,11 +103,6 @@ class GameState
153
103
  !condition.nil?
154
104
  end
155
105
 
156
- # Entfernt die jetzige Farbe aus der Farbrotation
157
- def remove_active_color
158
- ordered_colors.delete current_color
159
- end
160
-
161
106
  # @return [Player] Der Spieler, der das Spiel gewonnen hat, falls dies schon
162
107
  # entschieden ist. Sonst false.
163
108
  def winner
@@ -207,6 +152,6 @@ class GameState
207
152
 
208
153
  # @return [Array<Field>] Alle Felder mit Blöcken des Spielers, der gerade an der Reihe ist.
209
154
  def own_fields
210
- board.fields_of_color(current_color)
155
+ board.fields_of_color(current_player.color)
211
156
  end
212
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,59 +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
- attr_reader :coords
17
+ # @!attribute [rw] tower_height
18
+ # @return [Integer] Die Anzahl Spielsteine übereinander inklusive des obersten
19
+ attr_accessor :height
26
20
 
27
- # Erstellt einen neuen leeren Spielstein.
28
- 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)
29
23
  @color = color
30
- @kind = kind
31
- @rotation = rotation
32
- @is_flipped = is_flipped
24
+ @type = type
33
25
  @position = position
26
+ @height = height
27
+ end
28
+
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
34
54
 
35
- @coords = coords_priv
55
+ coords.map{ |x| x + position }.to_a
36
56
  end
37
57
 
38
58
  def ==(other)
39
- color == other.color &&
40
- kind == other.kind &&
41
- rotation == other.rotation &&
42
- is_flipped == other.is_flipped &&
43
- position == other.position
59
+ !other.nil? &&
60
+ color == other.color &&
61
+ position == other.position &&
62
+ type == other.type
44
63
  end
45
64
 
65
+ # @return [String] Gibt die String-Repräsentation zurück
46
66
  def to_s
47
- "#{color.key} #{kind.key} at #{position} rotation #{rotation.key}#{is_flipped ? ' (flipped)' : ''}"
67
+ "#{color.key} #{type.key} at #{position}"
48
68
  end
49
69
 
50
- def inspect
51
- 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]}"
52
73
  end
53
74
 
54
- private
55
- def coords_priv
56
- kind.transform(@rotation, @is_flipped).transform do |it|
57
- Coordinates.new(it.x + @position.x, it.y + @position.y)
58
- end.coordinates
75
+ def inspect
76
+ to_s
59
77
  end
60
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,33 +61,24 @@ 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] == :ordered_colors
66
- @gamestate.ordered_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
- when 'yellowShapes'
86
-
87
- when 'redShapes'
88
-
89
- when 'greenShapes'
90
-
91
82
  end
92
83
  end
93
84
 
@@ -105,7 +96,7 @@ class Protocol
105
96
  when 'data'
106
97
  logger.debug "data(class) : #{attrs['class']}"
107
98
  @context[:data_class] = attrs['class']
108
- if attrs['class'] == 'sc.framework.plugins.protocol.MoveRequest'
99
+ if attrs['class'] == 'moveRequest'
109
100
  @client.gamestate = gamestate
110
101
  move = @client.move_requested
111
102
  sendString(move_to_xml(move))
@@ -122,79 +113,32 @@ class Protocol
122
113
  when 'state'
123
114
  logger.debug 'new gamestate'
124
115
  @gamestate = GameState.new
125
- @gamestate.current_color_index = attrs['currentColorIndex'].to_i
126
116
  @gamestate.turn = attrs['turn'].to_i
127
- @gamestate.round = attrs['round'].to_i
128
- @gamestate.start_piece = PieceShape.to_a.find {|s| s.key == attrs['startPiece'].to_sym }
117
+ @gamestate.round = @gamestate.turn / 2
129
118
  logger.debug "Round: #{@gamestate.round}, Turn: #{@gamestate.turn}"
130
- when 'first'
131
- logger.debug 'new first player'
132
- player = Player.new(PlayerType::ONE, attrs['displayName'])
133
- @gamestate.add_player(player)
134
- @context[:player] = player
135
- @context[:color] = :one
136
- when 'second'
137
- logger.debug 'new second player'
138
- player = Player.new(PlayerType::TWO, attrs['displayName'])
139
- @gamestate.add_player(player)
140
- @context[:player] = player
141
- @context[:color] = :two
142
- when 'orderedColors'
143
- @context[:color] = :ordered_colors
144
- @gamestate.ordered_colors = []
145
119
  when 'board'
146
120
  logger.debug 'new board'
147
121
  @gamestate.board = Board.new()
148
- when 'field'
149
- x = attrs['x'].to_i
150
- y = attrs['y'].to_i
151
- color = Color.find_by_key(attrs['content'].to_sym)
152
- field = Field.new(x, y, color)
153
- @gamestate.board.add_field(field)
154
- @context[:piece_target] = :field
155
- @context[:field] = field
156
- when 'blueShapes'
157
- @context[:piece_target] = :blue_shapes
158
- @gamestate.undeployed_blue_pieces = []
159
- when 'yellowShapes'
160
- @context[:piece_target] = :yellow_shapes
161
- @gamestate.undeployed_yellow_pieces = []
162
- when 'redShapes'
163
- @context[:piece_target] = :red_shapes
164
- @gamestate.undeployed_red_pieces = []
165
- when 'greenShapes'
166
- @context[:piece_target] = :green_shapes
167
- @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
168
127
  when 'piece'
169
- color = Color.find_by_key(attrs['color'].to_sym)
170
- kind = PieceShape.find_by_key(attrs['kind'].to_sym)
171
- rotation = Rotation.find_by_key(attrs['rotation'].to_sym)
172
- is_flipped = attrs['isFlipped'].downcase == "true"
173
- piece = Piece.new(color, kind, rotation, is_flipped, Coordinates.origin)
174
- case @context[:piece_target]
175
- when :blue_shapes
176
- @gamestate.undeployed_blue_pieces << piece
177
- when :yellow_shapes
178
- @gamestate.undeployed_yellow_pieces << piece
179
- when :red_shapes
180
- @gamestate.green_red_pieces << piece
181
- when :green_shapes
182
- @gamestate.undeployed_green_pieces << piece
183
- when :last_move
184
- @context[:last_move_piece] = piece
185
- else
186
- raise "unknown piece target #{@context[:piece_target]}"
187
- end
188
- when 'lastMove'
189
- type = attrs['class']
190
- if type == 'skipmove'
191
- @gamestate.last_move = SkipMove.new
192
- else
193
- @context[:last_move_type] = type
194
- @context[:piece_target] = :last_move
195
- end
196
- when 'startColor'
197
- @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
198
142
  when 'winner'
199
143
  # TODO
200
144
  # winning_player = parsePlayer(attrs)
@@ -238,28 +182,21 @@ class Protocol
238
182
  # @param move [Move] The move to convert to XML.
239
183
  def move_to_xml(move)
240
184
  builder = Builder::XmlMarkup.new(indent: 2)
185
+
186
+ if move.nil?
187
+ raise 'nil moves are not sendable!'
188
+ end
189
+
241
190
  # Converting every the move here instead of requiring the Move
242
191
  # class interface to supply a method which returns the XML
243
192
  # because XML-generation should be decoupled from internal data
244
193
  # structures.
245
- case move
246
- when SetMove
247
- builder.data(class: 'sc.plugin2021.SetMove') do |data|
248
- data.piece(color: move.piece.color, kind: move.piece.kind, rotation: move.piece.rotation, isFlipped: move.piece.is_flipped) do |piece|
249
- piece.position(x: move.piece.position.x, y: move.piece.position.y)
250
- end
251
- move.hints.each do |hint|
252
- data.hint(content: hint.content)
253
- end
254
- end
255
- when SkipMove
256
- builder.data(class: 'sc.plugin2021.SkipMove') do |data|
257
- data.color(@gamestate.current_color.key.to_s)
258
- move.hints.each do |hint|
259
- data.hint(content: hint.content)
260
- end
261
- 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)
262
198
  end
199
+
263
200
  builder.target!
264
201
  end
265
202
  end