software_challenge_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b08956211b43e0c2cd823c5351ca8834295d848a
4
+ data.tar.gz: a6eb47e5ed59e726ca330d7cd2d8687b056d2de9
5
+ SHA512:
6
+ metadata.gz: 7473a1158058138f9c7b46bf4f254f940451452b67433974af963382c2418c1ef05c440bff6bcef9d085d1e803e7eb02cb42c923b76fbc4966ca30df6109aec3
7
+ data.tar.gz: d91262b781f43d53e9f4cee8a82c8f0cb6a95d8dcdf6501b1da407ffb08b43d406479eaf6c428d402dcd51bba8aa95416984f31afa066c13d5b2111e9ae5970a
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ /bin/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in SoftwareChallengeClient.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Software Challenge Client
2
+
3
+ This gem includes everything to build a client for the coding
4
+ competition [Software-Challenge](http://www.software-challenge.de).
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'software_challenge_client'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install software_challenge_client
21
+
22
+ ## Usage
23
+
24
+ See the example client in the example directory.
25
+
26
+ ## Development
27
+
28
+ After checking out the repo, run `bin/setup` to install
29
+ dependencies. Then, run `rake false` to run the tests. You can also
30
+ run `bin/console` for an interactive prompt that will allow you to
31
+ experiment.
32
+
33
+ To install this gem onto your local machine, run `bundle exec rake
34
+ install`. To release a new version, update the version number in
35
+ `version.rb`, and then run `bundle exec rake release`, which will
36
+ create a git tag for the version, push git commits and tags, and push
37
+ the `.gem` file to [rubygems.org](https://rubygems.org).
38
+
39
+ ## Contributing
40
+
41
+ Bug reports and pull requests are welcome on GitHub at
42
+ https://github.com/CAU-Kiel-Tech-Inf/socha_ruby_client. This project
43
+ is intended to be a safe, welcoming space for collaboration, and
44
+ contributors are expected to adhere to the
45
+ [Contributor Covenant](contributor-covenant.org) code of conduct.
data/RELEASES.md ADDED
@@ -0,0 +1,3 @@
1
+ = 0.1.0
2
+
3
+ First complete version.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "yard"
3
+
4
+ YARD::Rake::YardocTask.new do |t|
5
+ t.files = ['lib/**/*.rb'] # optional
6
+ t.options = ['--any', '--extra', '--opts'] # optional
7
+ end
data/example/client.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'software_challenge_client'
2
+
3
+ class Client < ClientInterface
4
+ attr_accessor :gamestate
5
+
6
+ def initialize
7
+ puts "Zufallsspieler erstellt."
8
+ end
9
+
10
+ # gets called, when it's your turn
11
+ def getMove
12
+ puts "Spielstand: #{self.gamestate.pointsForPlayer(self.gamestate.currentPlayer)} - #{self.gamestate.pointsForPlayer(self.gamestate.otherPlayer)}"
13
+ mov = self.randomMove
14
+ unless mov.nil?
15
+ puts 'Zug gefunden: '
16
+ puts mov.to_s
17
+ end
18
+ return mov
19
+ end
20
+
21
+ # choose a random move
22
+ def randomMove
23
+ possibleMoves = self.gamestate.getPossibleMoves
24
+ if possibleMoves.length > 0
25
+ return possibleMoves[SecureRandom.random_number(possibleMoves.length)]
26
+ else
27
+ return nil
28
+ end
29
+ end
30
+ end
data/example/main.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'software_challenge_client'
2
+ require 'optparse'
3
+ require 'ostruct'
4
+
5
+ require_relative 'client'
6
+
7
+ options = OpenStruct.new
8
+ options.host = '127.0.0.1'
9
+ options.port = 13050
10
+ options.reservation = ''
11
+
12
+ opt_parser = OptionParser.new do |opt|
13
+ opt.banner = "Usage: main.rb [OPTIONS]"
14
+ opt.separator ""
15
+ opt.separator "Options"
16
+
17
+ opt.on("-p","--port PORT", Integer,"connect to the server at PORT (default #{options.port})") do |p|
18
+ options.port = p
19
+ end
20
+
21
+ opt.on("-h","--host HOST","the host's IP address (default #{options.host})") do |h|
22
+ options.host = h
23
+ end
24
+
25
+ opt.on_tail("-?", "--help", "Show this message") do
26
+ puts opt
27
+ exit
28
+ end
29
+
30
+ end
31
+
32
+ opt_parser.parse!(ARGV)
33
+
34
+ client = Client.new
35
+ runner = Runner.new(options.host, options.port, client)
36
+ runner.start()
@@ -0,0 +1,17 @@
1
+ module SoftwareChallengeClient
2
+ require "software_challenge_client/version"
3
+ require "software_challenge_client/board"
4
+ require "software_challenge_client/client_interface"
5
+ require "software_challenge_client/condition"
6
+ require "software_challenge_client/connection"
7
+ require "software_challenge_client/debug_hint"
8
+ require "software_challenge_client/field"
9
+ require "software_challenge_client/field_type"
10
+ require "software_challenge_client/game_state"
11
+ require "software_challenge_client/move"
12
+ require "software_challenge_client/network"
13
+ require "software_challenge_client/player"
14
+ require "software_challenge_client/player_color"
15
+ require "software_challenge_client/protocol"
16
+ require "software_challenge_client/runner"
17
+ end
@@ -0,0 +1,315 @@
1
+ require_relative './util/constants'
2
+ require_relative 'game_state'
3
+ require_relative 'player'
4
+ require_relative 'field_type'
5
+ require_relative 'field'
6
+
7
+ require 'securerandom'
8
+
9
+ # @author Ralf-Tobias Diekert
10
+ # A representation of a twixt game board
11
+ class Board
12
+ # @!attribute [r] fields
13
+ # @return [Array<Array<Field>>] the board's fields
14
+ attr_reader :fields
15
+ # @!attribute [r] connections
16
+ # @return [Array<Connection>] the board's connections
17
+ attr_reader :connections
18
+
19
+ def initialize
20
+ self.init
21
+ end
22
+
23
+ # Initializes the board
24
+ #
25
+ # @param init [Boolean] if 'true', then the board will be initialized with swamps, otherwise the board will be completely empty
26
+ def initialize(init)
27
+ if init
28
+ self.init
29
+ else
30
+ self.makeClearBoard
31
+ end
32
+ end
33
+
34
+ # Initializes the board with swamps
35
+ def init
36
+ @fields = Array.new(Constants::SIZE) {Array.new(Constants::SIZE)}
37
+ @fields[0][0] = Field.new(FieldType::SWAMP, 0, 0)
38
+ @fields[0][Constants::SIZE - 1] = Field.new(FieldType::SWAMP, 0, Constants::SIZE - 1)
39
+ @fields[Constants::SIZE - 1][0] = Field.new(FieldType::SWAMP, Constants::SIZE - 1, 0)
40
+ @fields[Constants::SIZE - 1][Constants::SIZE - 1] = Field.new(FieldType::SWAMP, Constants::SIZE - 1, Constants::SIZE - 1)
41
+ for x in 1..(Constants::SIZE - 2)
42
+ @fields[x][0] = Field.new(FieldType::RED, x, 0);
43
+ @fields[x][Constants::SIZE - 1] = Field.new(FieldType::RED, x, Constants::SIZE - 1);
44
+ end
45
+ for y in 1..(Constants::SIZE - 2)
46
+ @fields[0][y] = Field.new(FieldType::BLUE, 0, y);
47
+ @fields[Constants::SIZE - 1][y] = Field.new(FieldType::BLUE, Constants::SIZE - 1, y);
48
+ end
49
+ for x in 1..(Constants::SIZE - 2)
50
+ for y in 1..(Constants::SIZE - 2)
51
+ @fields[x][y] = Field.new(FieldType::NORMAL, x, y);
52
+ end
53
+ end
54
+ self.placeSwamps()
55
+ @connections = Array.new;
56
+ end
57
+
58
+ # Places swamps at random coordinates
59
+ def placeSwamps
60
+ # big swamp
61
+ x = 1 + SecureRandom.random_number(Constants::SIZE - 4)
62
+ y = 1 + SecureRandom.random_number(Constants::SIZE - 4)
63
+ for i in x..(x + 2)
64
+ for j in y..(y + 2)
65
+ self.fields[i][j].type = FieldType::SWAMP
66
+ end
67
+ end
68
+ # first medium swamp
69
+ x = 1 + SecureRandom.random_number(Constants::SIZE - 3)
70
+ y = 1 + SecureRandom.random_number(Constants::SIZE - 3)
71
+ for i in x..(x + 1)
72
+ for j in y..(y + 1)
73
+ self.fields[i][j].type = FieldType::SWAMP
74
+ end
75
+ end
76
+ # second medium swamp
77
+ x = 1 + SecureRandom.random_number(Constants::SIZE - 3)
78
+ y = 1 + SecureRandom.random_number(Constants::SIZE - 3)
79
+ for i in x..(x + 1)
80
+ for j in y..(y + 1)
81
+ self.fields[i][j].type = FieldType::SWAMP
82
+ end
83
+ end
84
+ # little swamp
85
+ x = 1 + SecureRandom.random_number(Constants::SIZE - 2)
86
+ y = 1 + SecureRandom.random_number(Constants::SIZE - 2)
87
+ self.fields[x][y].type = FieldType::SWAMP
88
+ end
89
+
90
+
91
+ # creates a cleared board
92
+ def makeClearBoard
93
+ @fields = Array.new(Constants::SIZE, Array.new(Constants::SIZE))
94
+ @connections = Array.new
95
+ end
96
+
97
+ # gets the owner's color for the field at the coordinate (x, y)
98
+ #
99
+ # @param x [Integer] x-coordinate
100
+ # @param y [Integer] y-coordinate
101
+ # @return [PlayerColor] owner's color of field (x, y)
102
+ def getOwnerColor(x, y)
103
+ return self.fields[x][y].ownerColor
104
+ end
105
+
106
+
107
+ # sets the owner's color for the field at the coordinate (x, y)
108
+ #
109
+ # @param x [Integer] x-coordinate
110
+ # @param y [Integer] y-coordinate
111
+ # @param player [Player] new owner of field (x, y)
112
+ def put(x, y, player)
113
+ self.fields[x][y].owner = player.color;
114
+ self.createNewWires(x, y);
115
+ end
116
+
117
+ # creates wires at the coordinate (x, y), if it is possible
118
+ #
119
+ # @param x [Integer] x-coordinate
120
+ # @param y [Integer] y-coordinate
121
+ def createNewWires(x, y)
122
+ if self.checkPossibleWire(x, y, x - 2, y - 1)
123
+ self.createWire(x, y, x - 2, y - 1)
124
+ end
125
+ if self.checkPossibleWire(x, y, x - 1, y - 2)
126
+ self.createWire(x, y, x - 1, y - 2)
127
+ end
128
+ if self.checkPossibleWire(x, y, x - 2, y + 1)
129
+ self.createWire(x, y, x - 2, y + 1)
130
+ end
131
+ if self.checkPossibleWire(x, y, x - 1, y + 2)
132
+ self.createWire(x, y, x - 1, y + 2)
133
+ end
134
+ if self.checkPossibleWire(x, y, x + 2, y - 1)
135
+ self.createWire(x, y, x + 2, y - 1)
136
+ end
137
+ if self.checkPossibleWire(x, y, x + 1, y - 2)
138
+ self.createWire(x, y, x + 1, y - 2)
139
+ end
140
+ if self.checkPossibleWire(x, y, x + 2, y + 1)
141
+ self.createWire(x, y, x + 2, y + 1)
142
+ end
143
+ if self.checkPossibleWire(x, y, x + 1, y + 2)
144
+ self.createWire(x, y, x + 1, y + 2)
145
+ end
146
+
147
+ end
148
+
149
+ # creates a new wire
150
+ #
151
+ # @param x1 [Integer] x-coordinate starting point
152
+ # @param y1 [Integer] y-coordinate starting point
153
+ # @param x2 [Integer] x-coordinate ending point
154
+ # @param y2 [Integer] y-coordinate ending point
155
+ def createWire(x1, y1, x2, y2)
156
+ self.connections.push(Connection.new(x1, y1, x2, y2, self.fields[x1][y1].ownerColor))
157
+ end
158
+
159
+ # checks, if a wire can be placed at specified coordinates
160
+ #
161
+ # @param x1 [Integer] x-coordinate starting point
162
+ # @param y1 [Integer] y-coordinate starting point
163
+ # @param x2 [Integer] x-coordinate ending point
164
+ # @param y2 [Integer] y-coordinate ending point
165
+ # @return [Boolean] 'true', if a wire can be placed at specified coordinates
166
+ def checkPossibleWire(x1, y1, x2, y2)
167
+ if x2 < Constants::SIZE && y2 < Constants::SIZE && x2 >= 0 && y2 >= 0
168
+ if self.fields[x2][y2].ownerColor == self.fields[x1][y1].ownerColor
169
+ return !self.existsBlockingWire(x1, y1, x2, y2)
170
+ end
171
+ end
172
+ return false
173
+ end
174
+
175
+ # checks, if a blocking wire exists
176
+ #
177
+ # @param x1 [Integer] x-coordinate starting point
178
+ # @param y1 [Integer] y-coordinate starting point
179
+ # @param x2 [Integer] x-coordinate ending point
180
+ # @param y2 [Integer] y-coordinate ending point
181
+ # @return [Boolean] 'true', if another wire would block the creation of a new wire at specified coordinates
182
+ def existsBlockingWire(x1, y1, x2, y2)
183
+ smallerX, biggerX = [x1, x2].minmax
184
+ smallerY, biggerY = [y1, y2].minmax
185
+ for x in smallerX..biggerX
186
+ for y in smallerY..biggerY # checks all 6 Fields, from
187
+ # where there could be
188
+ # blocking connections
189
+ if !self.fields[x][y].ownerColor.nil? && (x != x1 || y != y1) &&
190
+ (x != x2 || y != y2) # excludes the Fields with no owner and
191
+ # the fields (x1, y2), (x2, y2)
192
+ # themselves.
193
+ if self.isWireBlocked(x1, y1, x2, y2, x, y)
194
+ return true
195
+ end
196
+ end
197
+ end
198
+ end
199
+ return false
200
+ end
201
+
202
+ # gets connections for the coordinate (x, y)
203
+ #
204
+ # @param x [Integer] x-coordinate
205
+ # @param y [Integer] y-coordinate
206
+ # @return [Array] Array of connections from field (x, y)
207
+ def getConnections(x, y)
208
+ xyConnections = Array.new
209
+ if !self.connections.nil?
210
+ for c in self.connections
211
+ if c.x1 == x && c.y1 == y
212
+ xyConnections.push(Connection.new(x, y, c.x2, c.y2, c.ownerColor))
213
+ end
214
+ if c.x2 == x && c.y2 == y
215
+ xyConnections.push(Connection.new(x, y, c.x1, c.y1, c.ownerColor))
216
+ end
217
+ end
218
+ end
219
+ return xyConnections
220
+ end
221
+
222
+ # following functions are helper functions for the blocking wire check
223
+ #http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
224
+ def onSegment(px,py,qx,qy,rx,ry)
225
+ if qx <= [px, rx].max && qx >= [px, rx].min &&
226
+ qy <= [py, ry].max && qy >= [py, ry].min
227
+ return true
228
+ end
229
+ return false
230
+ end
231
+
232
+ def orientation(px,py,qx,qy,rx,ry)
233
+ val = (qy - py) * (rx - qx) -
234
+ (qx - px) * (ry - qy)
235
+
236
+ if val == 0
237
+ return 0
238
+ end
239
+ if val > 0
240
+ return 1
241
+ end
242
+ return 2
243
+ end
244
+
245
+ def doIntersect(p1x,p1y, q1x,q1y, p2x,p2y, q2x,q2y)
246
+ o1 = orientation(p1x,p1y, q1x,q1y, p2x,p2y)
247
+ o2 = orientation(p1x,p1y, q1x,q1y, q2x,q2y)
248
+ o3 = orientation(p2x,p2y, q2x,q2y, p1x,p1y)
249
+ o4 = orientation(p2x,p2y, q2x,q2y, q1x,q1y)
250
+
251
+ if o1 != o2 && o3 != o4
252
+ return true
253
+ end
254
+
255
+ if o1 == 0 && onSegment(p1x,p1y, p2x,p2y, q1x,q1y)
256
+ return true
257
+ end
258
+
259
+ if o2 == 0 && onSegment(p1x,p1y, q2x,q2y, q1x,q1y)
260
+ return true
261
+ end
262
+
263
+ if o3 == 0 && onSegment(p2x,p2x, p1x,p1y, q2x,q2y)
264
+ return true
265
+ end
266
+
267
+ if o4 == 0 && onSegment(p2x,p2y, q1x,q1y, q2x,q2y)
268
+ return true
269
+ end
270
+
271
+ return false
272
+ end
273
+
274
+ # checks for the wire (x1, y1) -> (x2, y2), if it is blocked by any connection going out from (x,y).
275
+ #
276
+ # @param x1 [Integer] x-coordinate starting point
277
+ # @param y1 [Integer] y-coordinate starting point
278
+ # @param x2 [Integer] x-coordinate ending point
279
+ # @param y2 [Integer] y-coordinate ending point
280
+ # @param x [Integer] x-coordinate comparison field
281
+ # @param y [Integer] y-coordinate comparison field
282
+ # @return [Boolean] 'true', if another wire would block the creation of a new wire at specified coordinates
283
+ def isWireBlocked(x1, y1, x2, y2, x, y)
284
+ for c in getConnections(x, y)
285
+ if self.doIntersect(x1, y1, x2, y2, x, y, c.x2, c.y2)
286
+ return true
287
+ end
288
+ end
289
+ return false
290
+ end
291
+
292
+ def to_s
293
+ return self.fields.map { |f| f.map {|i| (i.ownerColor==PlayerColor::RED ? 'R' : (i.ownerColor==PlayerColor::BLUE ? 'B' : (i.type==FieldType::SWAMP ? 'S' : (i.type==FieldType::RED ? 'r' : (i.type==FieldType::BLUE ? 'b' : ' '))))) }.join(",")}.join("\n")
294
+ end
295
+
296
+ def ==(another_board)
297
+ for x in 0..(Constants.SIZE - 1)
298
+ for y in 0..(Constants.SIZE - 1)
299
+ if self.fields[x][y] != another_board.fields[x][y]
300
+ return false;
301
+ end
302
+ end
303
+ end
304
+ if self.connections.length != another_board.connections.length
305
+ return false;
306
+ end
307
+ for c in another_board.connections
308
+ if self.connections.include?(c)
309
+ return false
310
+ end
311
+ end
312
+
313
+ return true;
314
+ end
315
+ end