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,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