software_challenge_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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