software_challenge_client 1.2.1 → 19.0.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +3 -0
  3. data/README.md +64 -26
  4. data/example/client.rb +1 -71
  5. data/example/main.rb +1 -1
  6. data/lib/software_challenge_client.rb +4 -2
  7. data/lib/software_challenge_client/board.rb +66 -19
  8. data/lib/software_challenge_client/client_interface.rb +10 -5
  9. data/lib/software_challenge_client/condition.rb +2 -2
  10. data/lib/software_challenge_client/coordinates.rb +17 -0
  11. data/lib/software_challenge_client/debug_hint.rb +8 -4
  12. data/lib/software_challenge_client/direction.rb +53 -0
  13. data/lib/software_challenge_client/field.rb +26 -12
  14. data/lib/software_challenge_client/field_type.rb +25 -19
  15. data/lib/software_challenge_client/game_rule_logic.rb +230 -0
  16. data/lib/software_challenge_client/game_state.rb +45 -191
  17. data/lib/software_challenge_client/invalid_move_exception.rb +6 -8
  18. data/lib/software_challenge_client/line.rb +126 -0
  19. data/lib/software_challenge_client/line_direction.rb +15 -0
  20. data/lib/software_challenge_client/logging.rb +3 -2
  21. data/lib/software_challenge_client/move.rb +51 -38
  22. data/lib/software_challenge_client/network.rb +3 -1
  23. data/lib/software_challenge_client/player.rb +0 -39
  24. data/lib/software_challenge_client/player_color.rb +23 -13
  25. data/lib/software_challenge_client/protocol.rb +20 -83
  26. data/lib/software_challenge_client/runner.rb +2 -1
  27. data/lib/software_challenge_client/util/constants.rb +8 -5
  28. data/lib/software_challenge_client/version.rb +1 -1
  29. data/software_challenge_client.gemspec +2 -0
  30. metadata +24 -8
  31. data/lib/software_challenge_client/action.rb +0 -217
  32. data/lib/software_challenge_client/card_type.rb +0 -13
  33. data/lib/software_challenge_client/field_unavailable_exception.rb +0 -17
  34. data/lib/software_challenge_client/game_rules.rb +0 -376
@@ -1,16 +1,14 @@
1
- # encoding: UTF-8
1
+ # encoding: utf-8
2
2
 
3
- # Exception indicating a move which was performed is not valid for the given
4
- # state.
3
+ # Exception, die geworfen wird, wenn ein ungültiger Zug ausgeführt wird.
4
+ # @see Move#perform!
5
5
  class InvalidMoveException < StandardError
6
- def initialize(msg, move_or_action)
7
- # This exception will be thrown by a move or by an individual action,
8
- # depending where the rule violation was detected.
9
- @move_or_action = move_or_action
6
+ def initialize(msg, move)
7
+ @move = move
10
8
  super(msg)
11
9
  end
12
10
 
13
11
  def message
14
- "#{super}: #{@move_or_action}"
12
+ "#{super}: #{@move}"
15
13
  end
16
14
  end
@@ -0,0 +1,126 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require_relative './util/constants'
5
+ require_relative 'direction'
6
+ require_relative 'coordinates'
7
+ require_relative 'line_direction'
8
+
9
+ # Ein Iterator, der alle Koordinatenpaare auf einer Linie des Spielbrettes enthält.
10
+ class Line
11
+ include Enumerable
12
+ include Constants
13
+
14
+ # Erzeugt einen neuen Iterator.
15
+ #
16
+ # @param start [Coordinates]
17
+ # @param direction [LineDirection]
18
+ def initialize(start, direction)
19
+ @direction = direction
20
+ @start = start
21
+ # we will iterate from left to right, so find the leftmost field on the line
22
+ # inside the field note that (0,0) is the lowest, leftmost point, x-axis
23
+ # goes to the right, y-axis goes up
24
+ case @direction
25
+ when LineDirection::HORIZONTAL
26
+ leftmost_x = 0
27
+ leftmost_y = @start.y
28
+ when LineDirection::VERTICAL
29
+ leftmost_x = @start.x
30
+ leftmost_y = SIZE - 1
31
+ when LineDirection::RISING_DIAGONAL
32
+ # for rising diagonals, we have to decrease x and y
33
+ shift = [@start.x, @start.y].min
34
+ leftmost_x = @start.x - shift
35
+ leftmost_y = @start.y - shift
36
+ when LineDirection::FALLING_DIAGONAL
37
+ # for falling diagonals, we have to decrease x and increase y
38
+ shift = [@start.x, (SIZE - 1) - @start.y].min
39
+ leftmost_x = @start.x - shift
40
+ leftmost_y = @start.y + shift
41
+ end
42
+ @xi = leftmost_x
43
+ @yi = leftmost_y
44
+
45
+ @members = []
46
+ while @xi >= 0 && @yi >= 0 && @xi < SIZE && @yi < SIZE
47
+ @members << Coordinates.new(@xi, @yi)
48
+ # horizontal lines and diagonals move right
49
+ if [LineDirection::HORIZONTAL,
50
+ LineDirection::RISING_DIAGONAL,
51
+ LineDirection::FALLING_DIAGONAL].include? @direction
52
+ @xi += 1
53
+ end
54
+ # vertical lines and falling diagonals move down
55
+ if [LineDirection::VERTICAL,
56
+ LineDirection::FALLING_DIAGONAL].include? @direction
57
+ @yi -= 1
58
+ elsif @direction == LineDirection::RISING_DIAGONAL
59
+ # rising diagonals move up
60
+ @yi += 1
61
+ end
62
+ end
63
+ end
64
+
65
+ def each(&block)
66
+ @members.each(&block)
67
+ end
68
+
69
+ # Begrenzt den Iterator auf Koordinatenpaare von Feldern innerhalb der gegebenen beiden Koordinatenpaare (exklusive).
70
+ # Kann als Filter verwendet werden.
71
+ #
72
+ # @example
73
+ # Line.new(
74
+ # Coordinates.new(2, 3), LineDirection::HORIZONTAL
75
+ # ).select do |c|
76
+ # Line.between(Coordinates.new(2, 3), Coordinates.new(5, 3), LineDirection::HORIZONTAL).call(c)
77
+ # end
78
+ def self.between(start, bound, direction)
79
+ lower_x = [start.x, bound.x].min
80
+ lower_y = [start.y, bound.y].min
81
+ higher_x = [start.x, bound.x].max
82
+ higher_y = [start.y, bound.y].max
83
+ proc do |f|
84
+ case direction
85
+ when LineDirection::HORIZONTAL
86
+ f.x > lower_x && f.x < higher_x
87
+ when LineDirection::VERTICAL
88
+ f.y > lower_y && f.y < higher_y
89
+ when LineDirection::RISING_DIAGONAL, LineDirection::FALLING_DIAGONAL
90
+ f.x > lower_x && f.x < higher_x && f.y > lower_y && f.y < higher_y
91
+ else
92
+ throw `unknown direction ${direction}`
93
+ end
94
+ end
95
+ end
96
+
97
+ # @param line_direction [LineDirection] Ausrichtung der Linie
98
+ # @return [Array<Direction>] Die beiden Bewegungsrichtungen, die auf einer Linie mit der Ausrichtung möglich sind.
99
+ def self.directions_for_line_direction(line_direction)
100
+ case line_direction
101
+ when LineDirection::HORIZONTAL
102
+ [Direction::LEFT, Direction::RIGHT]
103
+ when LineDirection::VERTICAL
104
+ [Direction::UP, Direction::DOWN]
105
+ when LineDirection::RISING_DIAGONAL
106
+ [Direction::UP_RIGHT, Direction::DOWN_LEFT]
107
+ when LineDirection::FALLING_DIAGONAL
108
+ [Direction::UP_LEFT, Direction::DOWN_RIGHT]
109
+ end
110
+ end
111
+
112
+ # @param line_direction [Direction] Bewegungsrichtung
113
+ # @return [Array<Direction>] Die Ausrichtung einer Linie, die auf der Bewegungsrichtung liegt.
114
+ def self.line_direction_for_direction(direction)
115
+ case direction
116
+ when Direction::LEFT, Direction::RIGHT
117
+ LineDirection::HORIZONTAL
118
+ when Direction::UP, Direction::DOWN
119
+ LineDirection::VERTICAL
120
+ when Direction::UP_RIGHT, Direction::DOWN_LEFT
121
+ LineDirection::RISING_DIAGONAL
122
+ when Direction::UP_LEFT, Direction::DOWN_RIGHT
123
+ LineDirection::FALLING_DIAGONAL
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'typesafe_enum'
4
+ # Ausrichtung einer Linie auf dem Spielbrett. Mögliche Werte sind:
5
+ # - HORIZONTAL
6
+ # - VERTICAL
7
+ # - RISING_DIAGONAL
8
+ # - FALLING_DIAGONAL
9
+
10
+ class LineDirection < TypesafeEnum::Base
11
+ new :HORIZONTAL
12
+ new :VERTICAL
13
+ new :RISING_DIAGONAL
14
+ new :FALLING_DIAGONAL
15
+ end
@@ -1,9 +1,10 @@
1
+ # coding: utf-8
1
2
  require 'logger'
2
3
 
3
- # This module provides a shared logger to all classes into which it is mixed.
4
+ # Dieses Modul kann inkludiert werden, um eine Logausgabe auf der Konsole verwenden zu können.
4
5
  # See http://stackoverflow.com/a/6768164/390808
5
6
  #
6
- # Usage:
7
+ # Verwendung:
7
8
  #
8
9
  # class MyClass
9
10
  # include Logging
@@ -1,70 +1,83 @@
1
- # encoding: UTF-8
1
+ # encoding: utf-8
2
2
  require_relative 'debug_hint'
3
- require_relative 'action'
4
3
 
5
- # A move that can be performed in Mississippi Queen. A move consists of multiple
6
- # actions in a specific order.
4
+ # Ein Spielzug. Er ist definiert durch das Koordinatenpaar des Ausgangsfeldes (ein Fisch des Spielers, der den Zug machen will) und eine Bewegungsrichtung.
7
5
  class Move
8
- # @!attribute [r] actions
6
+ # @!attribute [r] x
7
+ # @return [Integer] X-Koordinate des Fisches, der bewegt werden soll. Die Spalte ganz links auf dem Spielbrett hat X-Koordinate 0, die ganz rechts 9.
8
+ attr_reader :x
9
+
10
+ # @!attribute [r] y
11
+ # @return [Integer] Y-Koordinate des Fisches, der bewegt werden soll. Die Zeile ganz unten auf dem Spielbrett hat Y-Koordinate 0, die ganz oben 9.
12
+ attr_reader :y
13
+
14
+ # @!attribute [r] direction
9
15
  #
10
- # @return [Array<Action>] List of actions which should be performed in this
11
- # move in the order determined by the array order.
12
- attr_reader :actions
16
+ # @return [Direction] Die Richtung, in die bewegt werden soll.
17
+ attr_reader :direction
13
18
 
14
19
  # @!attribute [r] hints
15
- # @return [Array<DebugHint>] the move's hints
20
+ # @return [Array<DebugHint>] Hinweise, die an den Zug angeheftet werden sollen. Siehe {DebugHint}.
16
21
  attr_reader :hints
17
22
 
18
- # Initializer
19
- #
20
- def initialize(actions = [], hints = [])
21
- @actions = actions
22
- @hints = hints
23
+ # Erstellt einen neuen Zug.
24
+ # @param x [Integer]
25
+ # @param y [Integer]
26
+ # @param direction [Direction]
27
+ def initialize(x, y, direction)
28
+ @x = x
29
+ @y = y
30
+ @direction = direction
31
+ @hints = []
23
32
  end
24
33
 
25
- # adds a hint to the move
26
- # @param hint [DebugHint] the added hint
34
+ # @param hint [DebugHint]
27
35
  def add_hint(hint)
28
36
  @hints.push(hint)
29
37
  end
30
38
 
31
39
  def ==(other)
32
- actions.size == other.actions.size &&
33
- actions.zip(other.actions).map { |a, b| a == b }.all?
40
+ x == other.x && y == other.y && direction == other.direction
34
41
  end
35
42
 
36
43
  def to_s
37
- "Move: #{actions}"
44
+ "Move: (#{x},#{y}) #{direction}"
38
45
  end
39
46
 
40
- def add_action(action)
41
- @actions << action
47
+ # @return [Coordinates] Die Koordinaten des Ausgangsfeldes des Zuges als Koordinatenpaar.
48
+ def from_field
49
+ Coordinates.new(x, y)
42
50
  end
43
51
 
44
- def add_action_with_order(action, index)
45
- @actions[index] = action
52
+ # Überprüft, ob der Zug in dem gegebenen Spielzustand regelkonform ausgeführt werden kann.
53
+ # @param gamestate [GameState]
54
+ # @return [Boolean]
55
+ def valid?(gamestate)
56
+ GameRuleLogic.valid_move(self, gamestate.board)
46
57
  end
47
58
 
59
+ # Führt den Zug in dem gegebenen Spielzustand aus. Sollte dabei gegen Spielregeln verstossen werden, wird eine InvalidMoveException geworfen.
60
+ # @param gamestate [GameState]
48
61
  def perform!(gamestate)
49
- raise InvalidMoveException.new(
50
- "Zug enthält keine Aktionen (zum Aussetzen die Aktion Skip benutzen).",
51
- self) if @actions.empty?
52
- @actions.each do |action|
53
- action.perform!(gamestate)
62
+ if GameRuleLogic.valid_move(self, gamestate.board)
63
+ type = gamestate.board.field(x, y).type
64
+ gamestate.board.change_field(x, y, FieldType::EMPTY)
65
+ target = GameRuleLogic.move_target(self, gamestate.board)
66
+ gamestate.board.change_field(target.x, target.y, type)
67
+ else
68
+ raise InvalidMoveException.new('Invalid move', self)
54
69
  end
55
- raise InvalidMoveException.new(
56
- 'Es muss eine Karte gespielt werden.',
57
- self) if gamestate.current_player.must_play_card
58
70
  # change the state to the next turn
59
71
  gamestate.last_move = self
60
72
  gamestate.turn += 1
61
73
  gamestate.switch_current_player
62
- # change carrots for next player if on first/second-position-field
63
- if gamestate.current_field.type == FieldType::POSITION_1 && gamestate.is_first(gamestate.current_player)
64
- gamestate.current_player.carrots += 10
65
- end
66
- if gamestate.current_field.type == FieldType::POSITION_2 && gamestate.is_second(gamestate.current_player)
67
- gamestate.current_player.carrots += 30
68
- end
74
+ end
75
+
76
+
77
+ # Ermittelt die Koordinaten des Zielfeldes des Zuges mit einer gegebenen Zugweite.
78
+ # @param speed [Integer] Die Zugweite. Entspricht normalerweise der Anzahl der Fische auf der Bewegungslinie.
79
+ # @return [Coordinates] Koordinaten des Zielfeldes. Eventuell ausserhalb des Spielbrettes.
80
+ def target_field(speed)
81
+ direction.translate(from_field, speed)
69
82
  end
70
83
  end
@@ -7,10 +7,12 @@ require 'rexml/element'
7
7
  require_relative 'protocol'
8
8
  require_relative 'board'
9
9
  require_relative 'client_interface'
10
+ require_relative 'util/constants'
10
11
 
11
12
  # This class handles the socket connection to the server
12
13
  class Network
13
14
  include Logging
15
+ include Constants
14
16
 
15
17
  # @!attribute [r] connected
16
18
  # @return [Boolean] true, if the client is connected to a server
@@ -43,7 +45,7 @@ class Network
43
45
  element.add_attribute('reservationCode', @reservation_id)
44
46
  else
45
47
  element = REXML::Element.new('join')
46
- element.add_attribute('gameType', 'swc_2018_hase_und_igel')
48
+ element.add_attribute('gameType', GAME_IDENTIFIER)
47
49
  end
48
50
  document.add(element)
49
51
  sendXML(document)
@@ -1,5 +1,4 @@
1
1
  # encoding: UTF-8
2
- require_relative 'card_type'
3
2
 
4
3
  # Ein Spieler
5
4
  class Player
@@ -11,53 +10,15 @@ class Player
11
10
  # @return [PlayerColor] die Farbe des Spielers, Rot oder Blau
12
11
  attr_reader :color
13
12
 
14
- # @!attribute [rw] points
15
- # @return [Integer] der aktuelle Punktestand des Spielers
16
- attr_accessor :points
17
-
18
- # @!attribute [rw] index
19
- # @return [Integer] die aktuelle Position des Spielers auf dem Spielbrett,
20
- # entspricht index des Feldes, von 0 bis 64
21
- attr_accessor :index
22
-
23
- # @!attribute [rw] carrots
24
- # @return [Integer] die aktuelle Anzahl Karotten des Spielers
25
- attr_accessor :carrots
26
-
27
- # @!attribute [rw] salads
28
- # @return [Integer] die aktuelle Anzahl Salate des Spielers
29
- attr_accessor :salads
30
-
31
- # @!attribute [rw] cards
32
- # @return [Array[CardType]] die noch nicht gespielten Karten
33
- attr_accessor :cards
34
-
35
- # @!attribute [rw] last_non_skip_action
36
- # @return [Action] letzte Aktion, die kein Skip war
37
- attr_accessor :last_non_skip_action
38
-
39
- # @!attribute [rw] must_play_card
40
- # @return [Boolean] zeigt an, ob eine Karte gespielt werden muss, wird in Zugvalidierung verwendet.
41
- attr_accessor :must_play_card
42
-
43
13
  # Konstruktor
44
14
  # @param color [PlayerColor] Farbe
45
15
  # @param name [String] Name
46
16
  def initialize(color, name)
47
17
  @color = color
48
18
  @name = name
49
- @points = 0
50
- @index = 0
51
- @carrots = 68
52
- @salads = 5
53
- @cards = CardType.to_a
54
19
  end
55
20
 
56
21
  def ==(other)
57
22
  color == other.color
58
23
  end
59
-
60
- def owns_card_of_type(card_type)
61
- cards.include? card_type
62
- end
63
24
  end
@@ -1,25 +1,35 @@
1
- # encoding: UTF-8
1
+ # encoding: utf-8
2
2
  # player color constants
3
3
  require 'typesafe_enum'
4
- class PlayerColor < TypesafeEnum::Base
5
4
 
5
+ # Die Spielerfarben. RED, BLUE oder NONE.
6
+ class PlayerColor < TypesafeEnum::Base
6
7
  new :NONE
7
8
  new :RED
8
9
  new :BLUE
9
10
 
10
- # Returns the opponents Color
11
- #
12
- # @param color [PlayerColor] The player's color, whose opponent needs to be found
13
- # @return [PlayerColor] the opponent's color
11
+ # @param color [PlayerColor]
12
+ # @return [PlayerColor] Farbe des Gegenspielers
14
13
  def self.opponent_color(color)
15
- if color == PlayerColor::RED
16
- return PlayerColor::BLUE
17
- end
18
- if color == PlayerColor::BLUE
19
- return PlayerColor::RED
14
+ case color
15
+ when PlayerColor::RED
16
+ PlayerColor::BLUE
17
+ when PlayerColor::BLUE
18
+ PlayerColor::RED
19
+ when PlayerColor::NONE
20
+ PlayerColor::NONE
20
21
  end
21
- if color == PlayerColor::NONE
22
- return PlayerColor::NONE
22
+ end
23
+
24
+ # @param color [PlayerColor] Die Spielerfarbe, zu dem der Feldtyp ermittelt werden soll.
25
+ # @return [FieldType] Der zur Spielerfarbe gehörende Feldtyp, also FieldType::RED für PlayerColor::RED und FieldType::BLUE für PlayerColor::BLUE. In allen anderen Fällen nil.
26
+ # @see FieldType#player_color
27
+ def self.field_type(color)
28
+ case color
29
+ when PlayerColor::RED
30
+ FieldType::RED
31
+ when PlayerColor::BLUE
32
+ FieldType::BLUE
23
33
  end
24
34
  end
25
35
  end
@@ -56,8 +56,6 @@ class Protocol
56
56
  case name
57
57
  when 'board'
58
58
  logger.debug @gamestate.board.to_s
59
- when 'type'
60
- @context[:player].cards << CardType.find_by_key(@context[:last_text].to_sym)
61
59
  end
62
60
  end
63
61
 
@@ -92,8 +90,8 @@ class Protocol
92
90
  logger.debug 'new gamestate'
93
91
  @gamestate = GameState.new
94
92
  @gamestate.turn = attrs['turn'].to_i
95
- @gamestate.start_player_color = attrs['startPlayer'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
96
- @gamestate.current_player_color = attrs['currentPlayer'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
93
+ @gamestate.start_player_color = attrs['startPlayerColor'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
94
+ @gamestate.current_player_color = attrs['currentPlayerColor'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
97
95
  logger.debug "Turn: #{@gamestate.turn}"
98
96
  when 'red'
99
97
  logger.debug 'new red player'
@@ -116,38 +114,18 @@ class Protocol
116
114
  @gamestate.board = Board.new
117
115
  @context[:current_tile_index] = nil
118
116
  @context[:current_tile_direction] = nil
119
- when 'fields'
120
- type = FieldType.find_by_key(attrs['type'].to_sym)
121
- index = attrs['index'].to_i
117
+ when 'field'
118
+ type = FieldType.find_by_key(attrs['state'].to_sym)
119
+ x = attrs['x'].to_i
120
+ y = attrs['y'].to_i
122
121
  raise "unexpected field type: #{attrs['type']}. Known types are #{FieldType.map { |t| t.key.to_s }}" if type.nil?
123
- @gamestate.board.fields[index] = Field.new(type, index)
122
+ @gamestate.board.add_field(Field.new(x, y, type))
124
123
  when 'lastMove'
125
- @gamestate.last_move = Move.new
126
- when 'advance'
127
- @gamestate.last_move.add_action_with_order(
128
- Advance.new(attrs['distance'].to_i), attrs['order'].to_i
129
- )
130
- when 'card'
131
- @gamestate.last_move.add_action_with_order(
132
- Card.new(CardType.find_by_key(attrs['type'].to_sym), attrs['value'].to_i),
133
- attrs['order'].to_i
134
- )
135
- when 'skip'
136
- @gamestate.last_move.add_action_with_order(
137
- Skip.new, attrs['order'].to_i
138
- )
139
- when 'eatSalad'
140
- @gamestate.last_move.add_action_with_order(
141
- EatSalad.new, attrs['order'].to_i
142
- )
143
- when 'fallBack'
144
- @gamestate.last_move.add_action_with_order(
145
- FallBack.new, attrs['order'].to_i
146
- )
147
- when 'exchangeCarrots'
148
- @gamestate.last_move.add_action_with_order(
149
- ExchangeCarrots.new(attrs['value'].to_i), attrs['order'].to_i
150
- )
124
+ direction = Direction.find_by_key(attrs['direction'].to_sym)
125
+ x = attrs['x'].to_i
126
+ y = attrs['y'].to_i
127
+ raise "unexpected direction: #{attrs['direction']}. Known directions are #{Direction.map { |d| d.key.to_s }}" if direction.nil?
128
+ @gamestate.last_move = Move.new(x, y, direction)
151
129
  when 'winner'
152
130
  winning_player = parsePlayer(attrs)
153
131
  @gamestate.condition = Condition.new(winning_player)
@@ -155,24 +133,6 @@ class Protocol
155
133
  when 'left'
156
134
  logger.debug 'got left event, terminating'
157
135
  @network.disconnect
158
- when 'lastNonSkipAction'
159
- @context[:player].last_non_skip_action =
160
- case attrs['class']
161
- when 'advance'
162
- Advance.new(attrs['distance'].to_i)
163
- when 'card'
164
- Card.new(CardType.find_by_key(attrs['type'].to_sym), attrs['value'].to_i)
165
- when 'skip'
166
- Skip.new
167
- when 'eatSalad'
168
- EatSalad.new
169
- when 'fallBack'
170
- FallBack.new
171
- when 'exchangeCarrots'
172
- ExchangeCarrots.new(attrs['value'].to_i)
173
- else
174
- raise "Unknown action type #{attrs['class']}"
175
- end
176
136
  end
177
137
  end
178
138
 
@@ -181,16 +141,10 @@ class Protocol
181
141
  # @param attributes [Hash] Attributes for the new Player.
182
142
  # @return [Player] The created Player object.
183
143
  def parsePlayer(attributes)
184
- player = Player.new(
144
+ Player.new(
185
145
  PlayerColor.find_by_key(attributes['color'].to_sym),
186
146
  attributes['displayName']
187
147
  )
188
- player.points = attributes['points'].to_i
189
- player.index = attributes['index'].to_i
190
- player.carrots = attributes['carrots'].to_i
191
- player.salads = attributes['salads'].to_i
192
- player.cards = []
193
- player
194
148
  end
195
149
 
196
150
  # send a xml document
@@ -219,32 +173,15 @@ class Protocol
219
173
  # @param move [Move] The move to convert to XML.
220
174
  def move_to_xml(move)
221
175
  builder = Builder::XmlMarkup.new(indent: 2)
222
- builder.data(class: 'move') do |data|
223
- move.actions.each_with_index do |action, index|
224
- # Converting every action type here instead of requiring the Action
225
- # class interface to supply a method which returns the action hash
226
- # because XML-generation should be decoupled from internal data
227
- # structures.
228
- attribute = case action.type
229
- when :advance
230
- { distance: action.distance }
231
- when :skip, :eat_salad, :fall_back
232
- {}
233
- when :card
234
- { type: action.card_type.key.to_s, value: action.value }
235
- when :exchange_carrots
236
- { value: action.value }
237
- else
238
- raise "unknown action type: #{action.type.inspect}. "\
239
- "Can't convert to XML!"
240
- end
241
- attribute[:order] = index
242
- data.tag!(snake_case_to_lower_camel_case(action.type.to_s), attribute)
176
+ # Converting every the move here instead of requiring the Move
177
+ # class interface to supply a method which returns the XML
178
+ # because XML-generation should be decoupled from internal data
179
+ # structures.
180
+ builder.data(class: 'move', x: move.x, y: move.y, direction: move.direction.key) do |data|
181
+ move.hints.each do |hint|
182
+ data.hint(content: hint.content)
243
183
  end
244
184
  end
245
- move.hints.each do |hint|
246
- data.hint(content: hint.content)
247
- end
248
185
  builder.target!
249
186
  end
250
187