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,58 @@
1
+ require_relative 'debug_hint'
2
+
3
+ # @author Ralf-Tobias Diekert
4
+ # A move, that can be performed in twixt
5
+ class Move
6
+ # @!attribute [r] x
7
+ # @return [Integer] x-coordinate
8
+ attr_reader :x
9
+ # @!attribute [r] y
10
+ # @return [Integer] y-coordinate
11
+ attr_reader :y
12
+ # @!attribute [r] hints
13
+ # @return [Array<DebugHint>] the move's hints
14
+ attr_reader :hints
15
+
16
+ # Initializer
17
+ #
18
+ # @param x [Integer] x-coordinate
19
+ # @param y [Integer] y-coordinate
20
+ def initialize(x, y)
21
+ @x = x
22
+ @y = y
23
+ @hints = Array.new
24
+ end
25
+
26
+ # @overload addHint(hint)
27
+ # adds a hint to the move
28
+ # @param hint [DebugHint] the added hint
29
+ # @overload addHint(key, value)
30
+ # adds a hint to the move
31
+ # @param key the added hint's key
32
+ # @param value the added hint's value
33
+ # @overload addHint(string)
34
+ # adds a hint to the move
35
+ # @param hint [String] the added hint's content
36
+ def addHint(hint)
37
+ @hints.push(hint);
38
+ end
39
+
40
+ # adds a hint to the move
41
+ def addHint(key, value)
42
+ self.addHint(DebugHint.new(key, value))
43
+ end
44
+
45
+ # adds a hint to the move
46
+ def addHint(string)
47
+ self.addHint(DebugHint.new(string))
48
+ end
49
+
50
+ def ==(another_move)
51
+ return self.x == another_move.x && self.y == another_move.y
52
+ end
53
+
54
+ def to_s
55
+ return "Move:(#{self.x},#{self.y})"
56
+ end
57
+
58
+ end
@@ -0,0 +1,146 @@
1
+ require 'socket'
2
+ require_relative 'protocol'
3
+ require_relative 'board'
4
+ require_relative 'client_interface'
5
+ require 'rexml/document'
6
+ require 'rexml/element'
7
+
8
+ # @author Ralf-Tobias Diekert
9
+ # This class handles the socket connection to the server
10
+ class Network
11
+ @socket
12
+ @host
13
+ @port
14
+
15
+ @board
16
+ @client
17
+ @protocol
18
+
19
+ @receiveBuffer
20
+ @reservationID
21
+
22
+ # @!attribute [r] connected
23
+ # @return [Boolean] true, if the client is connected to a server
24
+ attr_reader :connected
25
+
26
+ def initialize(host, port, board, client)
27
+ @host, @port, @connected, @board, @client =
28
+ host, port, false, board, client
29
+
30
+ @protocol = Protocol.new(self, @client)
31
+ @reservationID = ''
32
+ @receiveBuffer = ''
33
+
34
+ puts '> Network/Socket created.'
35
+ end
36
+
37
+ # connects the client with a given server
38
+ #
39
+ # @return [Boolean] true, if successfully connected to the server
40
+ def connect
41
+ @socket = TCPSocket.open(@host, @port)
42
+ @connected = true
43
+
44
+ self.sendString('<protocol>')
45
+ if @reservationID != ''
46
+ document = REXML::Docuent.new
47
+ element = REXML::Element.new('joinPrepared')
48
+ element.add_attribute('reservationCode', @reservationID)
49
+ document.add(element)
50
+ self.sendXML(document)
51
+ else
52
+ document = REXML::Document.new
53
+ element = REXML::Element.new('join')
54
+ element.add_attribute('gameType', 'swc_2016_twixt')
55
+ document.add(element)
56
+ self.sendXML(document)
57
+ end
58
+ return @connected
59
+ end
60
+
61
+ # disconnects the client from a server
62
+ def disconnect
63
+
64
+ if @connected
65
+ sendString("</protocol>")
66
+ @connected = false
67
+ @socket.close
68
+ end
69
+ puts '> Disconnected.'
70
+ end
71
+
72
+ # reads from the socket until "</room>" is read
73
+ def readString
74
+ puts 'reading'
75
+ sockMsg = ''
76
+ if(!@connected)
77
+ return
78
+ end
79
+
80
+ line =''
81
+ char = ''
82
+ while line!="</room>"
83
+ char = @socket.getc
84
+ line+=char
85
+ if char=='\n' || char==' '
86
+
87
+ line = ''
88
+ end
89
+ sockMsg += char
90
+ end
91
+ puts 'ended reading'
92
+ if sockMsg != ''
93
+
94
+ @receiveBuffer.concat(sockMsg)
95
+
96
+ # Remove <protocol> tag
97
+ @receiveBuffer = @receiveBuffer.gsub('<protocol>', '')
98
+
99
+ puts 'Receive:'
100
+ puts ''
101
+ #puts @receiveBuffer
102
+
103
+ # Process text
104
+ @protocol.processString('<msg>'+@receiveBuffer+'</msg>');
105
+ self.emptyReceiveBuffer
106
+ end
107
+ return true
108
+ end
109
+
110
+ # empties the receive buffer
111
+ def emptyReceiveBuffer
112
+ @receiveBuffer = ''
113
+ end
114
+
115
+ # processes an incomming message
116
+ #
117
+ # @return [Boolean] true, if the processing of a incomming message was successfull
118
+ def processMessages
119
+ if !@connected
120
+ return false
121
+ end
122
+ return self.readString
123
+ end
124
+
125
+ # sends a string to the socket
126
+ #
127
+ # @param s [String] the message, to be sent
128
+ def sendString(s)
129
+ if(@connected)
130
+ @socket.print(s);
131
+ puts 'Send:'
132
+ puts ''
133
+ puts(s);
134
+ end
135
+ end
136
+
137
+ # sends a xml Document to the buffer
138
+ #
139
+ # @param xml [REXML::Docuent] the Document, that will be sent
140
+ def sendXML(xml)
141
+ text = ''
142
+ xml.write(text)
143
+ self.sendString(text);
144
+ end
145
+
146
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'player_color'
2
+
3
+ # @author Ralf-Tobias Diekert
4
+ # A player, participating at a game
5
+ class Player
6
+ # @!attribute [r] color
7
+ # @return [PlayerColor] the player's color
8
+ attr_reader :color
9
+ # @!attribute [rw] points
10
+ # @return [Integer] the player's points
11
+ attr_accessor :points
12
+
13
+ # Initializer
14
+ # @param the new player's color
15
+ def initialize(color)
16
+ @color = color
17
+ self.points = 0
18
+ end
19
+
20
+ def ==(another_player)
21
+ return self.color == another_player.color
22
+ end
23
+
24
+ end
@@ -0,0 +1,23 @@
1
+ # @author Ralf-Tobias Diekert
2
+ #player color constants
3
+ module PlayerColor
4
+ NONE = 1
5
+ RED = 2
6
+ BLUE = 4
7
+
8
+ # Returns the opponents Color
9
+ #
10
+ # @param color [PlayerColor] The player's color, whose opponent needs to be found
11
+ # @return [PlayerColor] the opponent's color
12
+ def self.opponentColor(color)
13
+ if color == PlayerColor::RED
14
+ return PlayerColor::BLUE
15
+ end
16
+ if color == PlayerColor::BLUE
17
+ return PlayerColor::RED
18
+ end
19
+ if color == PlayerColor::NONE
20
+ return PlayerColor::NONE
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,149 @@
1
+ require 'socket'
2
+ require_relative 'board'
3
+ require_relative 'move'
4
+ require_relative 'player'
5
+ require_relative 'network'
6
+ require_relative 'connection'
7
+ require_relative 'client_interface'
8
+ require 'rexml/document'
9
+ require 'rexml/streamlistener'
10
+
11
+ # @author Ralf-Tobias Diekert
12
+ # This class handles the parsing of xml strings according to the network protocol of twixt
13
+ class Protocol
14
+ include REXML::StreamListener
15
+
16
+ # @!attribute [r] gamestate
17
+ # @return [Gamestate] current gamestate
18
+ attr_reader :gamestate
19
+ # @!attribute [rw] roomID
20
+ # @return [String] current room id
21
+ attr_accessor :roomID
22
+ # @!attribute [r] client
23
+ # @return [ClientInterface] current client
24
+ attr_reader :client
25
+ @network
26
+
27
+ def initialize(network, client)
28
+ @gamestate = GameState.new
29
+ @network, @client = network, client
30
+ self.client.gamestate = self.gamestate
31
+ end
32
+
33
+ # starts xml-string parsing
34
+ #
35
+ # @param text [String] the xml-string that will be parsed
36
+ def processString(text)
37
+ list = self
38
+ #puts "Parse XML:\n#{text}\n----END XML"
39
+ REXML::Document.parse_stream(text, list)
40
+ end
41
+
42
+ # called if an end-tag is read
43
+ #
44
+ # @param name [String] the end-tag name, that was read
45
+ def tag_end(name)
46
+ case name
47
+ when "board"
48
+ puts @gamestate.board.to_s
49
+ when "condition"
50
+ puts "Game ended"
51
+ @network.disconnect
52
+ end
53
+ end
54
+
55
+ # called if a start tag is read
56
+ # Depending on the tag the gamestate is updated
57
+ # or the client will be asked for a move
58
+ #
59
+ # @param name [String] the start-tag, that was read
60
+ # @param attrs [Dictionary<String, String>] Attributes attached to the tag
61
+ def tag_start(name, attrs)
62
+ case name
63
+ when "room"
64
+ @roomID = attrs['roomId']
65
+ puts "roomId : "+@roomID
66
+ when "data"
67
+ puts "data(class) : "+attrs['class']
68
+ if attrs['class'] == "sc.framework.plugins.protocol.MoveRequest"
69
+ @client.gamestate = self.gamestate
70
+ move = @client.getMove
71
+ document = REXML::Document.new
72
+ document.add_element('room',{'roomId' => @roomID})
73
+ data = REXML::Element.new('data')
74
+ data.add_attribute('class', 'move')
75
+ data.add_attribute('x', move.x)
76
+ data.add_attribute('y', move.y)
77
+ document.root.add_element(data)
78
+ for h in move.hints
79
+ hint = REXML::Element.new('hint')
80
+ hint.add_attribute('content', h.content)
81
+ document.root.elements['data'].elements << hint
82
+ end
83
+ self.sendXml(document)
84
+ end
85
+ if attrs['class'] == "error"
86
+ puts "Game ended - ERROR"
87
+ puts attrs['message']
88
+ @network.disconnect
89
+ end
90
+ when "state"
91
+ puts 'new gamestate'
92
+ @gamestate.turn = attrs['turn'].to_i
93
+ @gamestate.startPlayerColor = attrs['startPlayer'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
94
+ @gamestate.currentPlayerColor = attrs['currentPlayer'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE
95
+ puts "Turn: #{@gamestate.turn}"
96
+ when "red"
97
+ puts 'new red player'
98
+ @gamestate.addPlayer(Player.new(attrs['color'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE))
99
+ @gamestate.red.points = attrs['points'].to_i
100
+ when "blue"
101
+ puts 'new blue player'
102
+ @gamestate.addPlayer(Player.new(attrs['color'] == 'RED' ? PlayerColor::RED : PlayerColor::BLUE))
103
+ @gamestate.blue.points = attrs['points'].to_i
104
+ when "board"
105
+ puts 'new board'
106
+ @gamestate.board = Board.new(true)
107
+ when "field"
108
+ type = FieldType::NORMAL
109
+ ownerColor = PlayerColor::NONE
110
+ case attrs['type']
111
+ when 'SWAMP'
112
+ type = FieldType::SWAMP
113
+ when 'RED'
114
+ type = FieldType::RED
115
+ when 'BLUE'
116
+ type = FieldType::BLUE
117
+ when "winner"
118
+ puts "Game ended"
119
+ @network.disconnect
120
+ end
121
+
122
+ case attrs['owner']
123
+ when 'RED'
124
+ ownerColor = PlayerColor::RED
125
+ when 'BLUE'
126
+ ownerColor = PlayerColor::BLUE
127
+ end
128
+ x = attrs['x'].to_i
129
+ y = attrs['y'].to_i
130
+
131
+ @gamestate.board.fields[x][y] = Field.new(type, x, y)
132
+ @gamestate.board.fields[x][y].ownerColor = ownerColor
133
+ when "connection"
134
+ @gamestate.board.connections.push(Connection.new(attrs['x1'].to_i, attrs['y1'].to_i, attrs['x2'].to_i, attrs['y2'].to_i, attrs['owner']))
135
+ when "lastMove"
136
+ @gamestate.lastMove = Move.new(attrs['x'], attrs['y'])
137
+ when "condition"
138
+ @gamestate.condition = Condition.new(attrs['winner'], attrs['reason'])
139
+ end
140
+ end
141
+
142
+ # send a xml document
143
+ #
144
+ # @param document [REXML::Document] the document, that will be send to the connected server
145
+ def sendXml(document)
146
+ @network.sendXML(document)
147
+ end
148
+
149
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'board'
2
+ require_relative 'client_interface'
3
+ require_relative 'network'
4
+
5
+ class Runner
6
+ attr_reader :network
7
+
8
+ def initialize(host, port, client)
9
+ puts 'Software Challenge 2015'
10
+ puts 'Ruby Client'
11
+ puts "Host: #{host}"
12
+ puts "Port: #{port}"
13
+
14
+ board = Board.new(true)
15
+ @network = Network.new(host, port, board, client)
16
+ end
17
+
18
+ def start
19
+ self.network.connect
20
+ if self.network.connected == false
21
+ puts 'Not connected'
22
+ return
23
+ end
24
+
25
+ while self.network.connected
26
+ self.network.processMessages
27
+ sleep(0.01)
28
+ end
29
+
30
+ puts 'Program end...'
31
+ self.network.disconnect
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ #Game constants
2
+ module Constants
3
+ ROUND_LIMIT = 100
4
+ SIZE = 24 #board's width and height
5
+ end