software_challenge_client 21.0.1 → 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.
@@ -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