software_challenge_client 0.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.
@@ -0,0 +1,7 @@
1
+ class ClientInterface
2
+ attr_accessor :gamestate
3
+
4
+ def getMove
5
+ raise "Not yet implemented"
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'player'
2
+
3
+ # @author Ralf-Tobias Diekert
4
+ # winning condition
5
+ class Condition
6
+ # @!attribute [r] winner
7
+ # @return [Player] winning player
8
+ attr_reader :winner
9
+ # @!attribute [r] reason
10
+ # @return [String] winning reason
11
+ attr_reader :reason
12
+
13
+ # Initializes the winning Condition with a player and a reason
14
+ # @param winer [Player] winning player
15
+ # @param reason [String] winning reason
16
+ def initialize(winner, reason)
17
+ @winner = winner
18
+ @reason = reason
19
+ end
20
+
21
+ end
@@ -0,0 +1,49 @@
1
+ require_relative 'player_color'
2
+
3
+ # @author Ralf-Tobias Diekert
4
+ # A connection between two fields owned by a specific player
5
+ class Connection
6
+ # @!attribute [r] x1
7
+ # @return [Integer] x-coordinate starting point
8
+ attr_reader :x1
9
+ # @!attribute [r] x2
10
+ # @return [Integer] y-coordinate starting point
11
+ attr_reader :x2
12
+ # @!attribute [r] y1
13
+ # @return [Integer] x-coordinate ending point
14
+ attr_reader :y1
15
+ # @!attribute [r] y2
16
+ # @return [Integer] y-coordinate ending point
17
+ attr_reader :y2
18
+ # @!attribute [r] ownerColor
19
+ # @return [PlayerColor] connection's owner's color
20
+ attr_reader :ownerColor
21
+
22
+ # Initializer
23
+ #
24
+ # @param x1 [Integer] x-coordinate starting point
25
+ # @param y1 [Integer] y-coordinate starting point
26
+ # @param x2 [Integer] x-coordinate ending point
27
+ # @param y2 [Integer] y-coordinate ending point
28
+ # @param owner [PlayerColor] connection's owner's color
29
+ def initialize(x1, y1, x2, y2, ownerColor)
30
+ @x1 = x1
31
+ @x2 = x2
32
+ @y1 = y1
33
+ @y2 = y2
34
+ @ownerColor = ownerColor
35
+ end
36
+
37
+ def ==(another_connection)
38
+ if(self.x1 == another_connection.x1 && self.y1 == another_connection.y1 && self.x2 == another_connection.x2 && self.y2 == another_connection.y2 ||
39
+ self.x1 == another_connection.x2 && self.y1 == another_connection.y2 && self.x2 == another_connection.x1 && self.y2 == another_connection.y1)
40
+ return ownerColor == c.ownerColor
41
+ else
42
+ return false
43
+ end
44
+ end
45
+
46
+ def to_s
47
+ return "#{self.ownerColor} : (#{self.x1}, #{self.y1}) - (#{self.x2}, #{self.y2})"
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ # @author Ralf-Tobias Diekert
2
+ # A debug hint, that can be added to a move
3
+ class DebugHint
4
+
5
+ # @!attribute [r] content
6
+ # @return [String] a hint
7
+ attr_reader :content
8
+
9
+ # @overload initialize
10
+ # Creates an empty hint
11
+ # @overload initialize(key, value)
12
+ # Creates a hint with a key and a value
13
+ # @param key Key of the hint
14
+ # @param value of the hint
15
+ # @overload initialize(content)
16
+ # Creates a hint with specified content
17
+ # @param content of the hint
18
+ def initialize
19
+
20
+ end
21
+
22
+ def initialize(key, value)
23
+ if key.nil?
24
+ self.content = "#{value}"
25
+ else
26
+ self.content = "#{key} = #{value}"
27
+ end
28
+ end
29
+
30
+ def initialize(content)
31
+ self.content = "#{content}"
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ require_relative 'player_color'
2
+ require_relative 'field_type'
3
+
4
+ # @author Ralf-Tobias Diekert
5
+ # A field on the game board
6
+ class Field
7
+ # @!attribute [rw] ownerColor
8
+ # @return [PlayerColor] the field's owner's color
9
+ attr_accessor :ownerColor
10
+ # @!attribute [rw] type
11
+ # @return [PlayerColor] the field's type
12
+ attr_accessor :type
13
+ # @!attribute [r] x
14
+ # @return [Integer] the field's x-coordinate
15
+ attr_reader :x
16
+ # @!attribute [r] y
17
+ # @return [Integer] the field's y-coordinate
18
+ attr_reader :y
19
+
20
+ # Initializer
21
+ #
22
+ # @param type [FieldType] field type
23
+ # @param x [Integer] x-coordinate
24
+ # @param y [Integer] y-coordinate
25
+ def initialize(type, x, y)
26
+ self.ownerColor = PlayerColor::NONE
27
+ self.type = type
28
+ @x = x
29
+ @y = y
30
+ end
31
+
32
+ def ==(another_field)
33
+ return self.ownerColor == another_field.ownerColor &&
34
+ self.type == another_field.type &&
35
+ self.x == another_field.x &&
36
+ self.y == another_field.y
37
+ end
38
+
39
+ def to_s
40
+ return "Field: x = #{self.x}, y = #{self.y}, owner = #{self.ownerColor}, type = #{self.type}"
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ # @author Ralf-Tobias Diekert
2
+ #Fieldtype constants
3
+ module FieldType
4
+ NORMAL = 1
5
+ RED = 2
6
+ BLUE = 4
7
+ SWAMP = 8
8
+ end
@@ -0,0 +1,343 @@
1
+ require_relative './util/constants'
2
+ require_relative 'player'
3
+ require_relative 'board'
4
+ require_relative 'move'
5
+ require_relative 'condition'
6
+ require_relative 'player_color'
7
+ require_relative 'field_type'
8
+
9
+ # @author Ralf-Tobias Diekert
10
+ # The state of a game
11
+ class GameState
12
+
13
+ # @!attribute [rw] turn
14
+ # @return [Integer] turn number
15
+ attr_accessor :turn
16
+ # @!attribute [rw] startPlayerColor
17
+ # @return [PlayerColor] the start-player's color
18
+ attr_accessor :startPlayerColor
19
+ # @!attribute [rw] currentPlayerColor
20
+ # @return [PlayerColor] the current player's color
21
+ attr_accessor :currentPlayerColor
22
+ # @!attribute [r] red
23
+ # @return [Player] the red player
24
+ attr_reader :red
25
+ # @!attribute [r] blue
26
+ # @return [Player] the blue player
27
+ attr_reader :blue
28
+ # @!attribute [rw] board
29
+ # @return [Board] the game's board
30
+ attr_accessor :board
31
+ # @!attribute [rw] lastMove
32
+ # @return [Move] the last move, that was made
33
+ attr_accessor :lastMove
34
+ # @!attribute [rw] condition
35
+ # @return [Condition] the winner and winning reason
36
+ attr_accessor :condition
37
+
38
+ def initialize
39
+ self.currentPlayerColor = PlayerColor::RED
40
+ self.startPlayerColor = PlayerColor::RED
41
+ self.board = Board.new(true)
42
+ end
43
+
44
+ # adds a player to the gamestate
45
+ #
46
+ # @param player [Player] the player, that will be added
47
+ def addPlayer(player)
48
+ if player.color == PlayerColor::RED
49
+ @red = player
50
+ else if player.color == PlayerColor::BLUE
51
+ @blue = player
52
+ end
53
+ end
54
+ end
55
+
56
+ # gets the current player
57
+ #
58
+ # @return [Player] the current player
59
+ def currentPlayer
60
+ if self.currentPlayerColor == PlayerColor::RED
61
+ return self.red
62
+ else
63
+ return self.blue
64
+ end
65
+ end
66
+
67
+ # gets the other (not the current) player
68
+ #
69
+ # @return [Player] the other (not the current) player
70
+ def otherPlayer
71
+ if self.currentPlayerColor == PlayerColor::RED
72
+ return self.blue
73
+ else
74
+ return self.red
75
+ end
76
+ end
77
+
78
+ # gets the other (not the current) player's color
79
+ #
80
+ # @return [PlayerColor] the other (not the current) player's color
81
+ def otherPlayerColor
82
+ return PlayerColor.opponentColor(self.currentPlayerColor)
83
+ end
84
+
85
+ # gets the start player
86
+ #
87
+ # @return [Player] the startPlayer
88
+ def startPlayer
89
+ if self.startPlayer == PlayerColor::RED
90
+ return self.red
91
+ else
92
+ return self.blue
93
+ end
94
+ end
95
+
96
+ # switches current player
97
+ def switchCurrentPlayer
98
+ if currentPlayer.color == PlayerColor::RED
99
+ @currentPlayer = self.blue
100
+ else
101
+ @currentPlayer = self.red
102
+ end
103
+ end
104
+
105
+ # prepares next turn and sets the last move
106
+ #
107
+ # @param [Move] the last move
108
+ def prepareNextTurn(lastMove)
109
+ @turn++
110
+ @lastMove = lastMove;
111
+ self.switchCurrentPlayer()
112
+ end
113
+
114
+ # gets the current round
115
+ #
116
+ # @return [Integer] the current round
117
+ def round
118
+ return self.turn / 2
119
+ end
120
+
121
+ # gets all possible moves
122
+ #
123
+ # @return [Array<Move>] a list of all possible moves
124
+ def getPossibleMoves
125
+ enemyFieldType = currentPlayer.color == PlayerColor::RED ? FieldType::BLUE : FieldType::RED
126
+ moves = Array.new
127
+ for x in 0..(Constants::SIZE-1)
128
+ for y in 0..(Constants::SIZE-1)
129
+ if (self.board.fields[x][y].ownerColor == PlayerColor::NONE &&
130
+ self.board.fields[x][y].type != FieldType::SWAMP &&
131
+ self.board.fields[x][y].type != enemyFieldType)
132
+ moves.push(Move.new(x, y))
133
+ end
134
+ end
135
+ end
136
+ return moves
137
+ end
138
+
139
+ # performs a move on the gamestate
140
+ #
141
+ # @param move [Move] the move, that will be performed
142
+ # @param player [Player] the player, who makes the move
143
+ def perform(move, player)
144
+ if !move.nil?
145
+ if move.x < Constants::SIZE && move.y < Constants::SIZE &&
146
+ move.x >= 0 && move.y >= 0
147
+ if self.getPossibleMoves.include?(move)
148
+ self.board.put(move.x, move.y, player)
149
+ player.points = self.pointsForPlayer(player)
150
+ else
151
+ raise "Der Zug ist nicht möglich, denn der Platz ist bereits besetzt oder nicht besetzbar."
152
+ end
153
+ else
154
+ raise "Startkoordinaten sind nicht innerhalb des Spielfeldes."
155
+ end
156
+ end
157
+ end
158
+
159
+ # gets a player's points
160
+ #
161
+ # @param player [Player] the player, whos statistics will be returned
162
+ # @return [Integer] the points of the player
163
+ def playerStats(player)
164
+ return self.playerStats(player.color)
165
+ end
166
+
167
+ # gets a player's points by the player's color
168
+ #
169
+ # @param playerColor [PlayerColor] the player's color, whos statistics will be returned
170
+ # @return [Integer] the points of the player
171
+ def playerStats(playerColor)
172
+ if playerColor == PlayerColor::RED
173
+ return self.gameStats[0];
174
+ else
175
+ return self.gameStats[1]
176
+ end
177
+ end
178
+
179
+ # gets the players' statistics
180
+ #
181
+ # @return [Array<Integer>] the points for both players
182
+ def gameStats
183
+ stats = Array.new(2, Array.new(1))
184
+
185
+ stats[0][0] = self.red.points
186
+ stats[1][0] = self.blue.points
187
+
188
+ return stats
189
+ end
190
+
191
+ # get the players' names
192
+ #
193
+ # @return [Array<String>] the names for both players
194
+ def playerNames
195
+ return [red.displayName, blue.displayName]
196
+ end
197
+
198
+ # sets the game-ended condition
199
+ #
200
+ # @param winner [Player] the winner of the game
201
+ # @param reason [String] the winning reason
202
+ def endGame(winner, reason)
203
+ if condition.nil?
204
+ @condition = Condition.new(winner, reason)
205
+ end
206
+ end
207
+
208
+ # has the game ended?
209
+ #
210
+ # @return [Boolean] true, if the game has allready ended
211
+ def gameEnded?
212
+ return !self.condition.nil?
213
+ end
214
+
215
+ # gets the game's winner
216
+ #
217
+ # @return [Player] the game's winner
218
+ def winner
219
+ return condition.nil? ? nil : self.condition.winner
220
+ end
221
+
222
+ # gets the winning reason
223
+ #
224
+ # @return [String] the winning reason
225
+ def winningReason
226
+ return condition.nil? ? nil : self.condition.reason
227
+ end
228
+
229
+ # calculates a player's points
230
+ #
231
+ # @param player [Player] the player, whos point will be calculated
232
+ # @return [Integer] the points of the player
233
+ def pointsForPlayer(player)
234
+ playerColor = player.color
235
+ longestPath = 0
236
+
237
+ outermostFieldsInCircuit = Array.new(Array.new)
238
+ visited = Array.new(Constants::SIZE).map {|j| Array.new(Constants::SIZE).map {|i| false}} #// all by default initialized to false
239
+ for x in 0..(Constants::SIZE-1)
240
+ for y in 0..(Constants::SIZE-1)
241
+ if visited[x][y] == false
242
+ if self.board.fields[x][y].ownerColor == playerColor
243
+ startOfCircuit = Array.new
244
+ startOfCircuit.push(self.board.fields[x][y])
245
+ circuit = self.circuit(startOfCircuit, Array.new)
246
+ for f in circuit
247
+ visited[f.x][f.y] = true
248
+ end
249
+ outermost = Array.new(2)
250
+ if playerColor == PlayerColor::RED
251
+
252
+ outermost[0] = self.bottomMostFieldInCircuit(circuit)
253
+ outermost[1] = self.topMostFieldInCircuit(circuit)
254
+ else
255
+ outermost[0] = leftMostFieldInCircuit(circuit)
256
+ outermost[1] = rightMostFieldInCircuit(circuit)
257
+ end
258
+ outermostFieldsInCircuit.push(outermost)
259
+
260
+ end
261
+ visited[x][y] = true
262
+ end
263
+ end
264
+ end
265
+ for fields in outermostFieldsInCircuit
266
+ if (playerColor == PlayerColor::RED && fields[1].y - fields[0].y > longestPath)
267
+ longestPath = fields[1].y - fields[0].y
268
+ end
269
+ if (playerColor == PlayerColor::BLUE && fields[1].x - fields[0].x > longestPath)
270
+ longestPath = fields[1].x - fields[0].x
271
+ end
272
+ end
273
+
274
+ return longestPath # return longestPath
275
+ end
276
+
277
+ # the following functions are helpers for the points calculation
278
+ def bottomMostFieldInCircuit(circuit)
279
+ bottomMostField = circuit[0]
280
+ for f in circuit
281
+ if f.y < bottomMostField.y
282
+ bottomMostField = f
283
+ end
284
+ end
285
+ return bottomMostField
286
+ end
287
+
288
+ def topMostFieldInCircuit(circuit)
289
+ topMostField = circuit[0]
290
+ for f in circuit
291
+ if f.y > topMostField.y
292
+ topMostField = f
293
+ end
294
+ end
295
+ return topMostField
296
+ end
297
+
298
+ def leftMostFieldInCircuit(circuit)
299
+ leftMostField = circuit[0]
300
+ for f in circuit
301
+ if f.x < leftMostField.x
302
+ leftMostField = f
303
+ end
304
+ end
305
+ return leftMostField
306
+ end
307
+
308
+ def rightMostFieldInCircuit(circuit)
309
+ rightMostField = circuit[0]
310
+ for f in circuit
311
+ if f.x > rightMostField.x
312
+ rightMostField = f
313
+ end
314
+ end
315
+ return rightMostField
316
+ end
317
+
318
+ def circuit(circuit, visited)
319
+ changed = false;
320
+ toBeAddedFields = Array.new
321
+ for f in circuit
322
+ if !visited.include?(f)
323
+ changed = true
324
+ visited.push(f)
325
+ for c in self.board.getConnections(f.x,f.y)
326
+ if !circuit.include?(self.board.fields[c.x2][c.y2])
327
+ toBeAddedFields.push(self.board.fields[c.x2][c.y2])
328
+ end
329
+ if !circuit.include?(self.board.fields[c.x1][c.y1])
330
+ toBeAddedFields.push(self.board.fields[c.x1][c.y1])
331
+ end
332
+ end
333
+ end
334
+ end
335
+ circuit.push(*toBeAddedFields)
336
+ if changed
337
+ return self.circuit(circuit, visited)
338
+ else
339
+ return circuit
340
+ end
341
+ end
342
+
343
+ end