A solution in Ruby to the Codehire Cup Semi-final (Round 2) problem in the second Codehire Cup held across Australia in June and July 2013.
In June and July 2013, Codehire held the second Codehire Cup across Australia. As last year, the contest featured some relatively simple coding problems. Contestants could choose to use C/C++, C#, Java, JavaScript, PHP, Python, or Ruby to submit solutions through a web-based interface.
Contestants were ranked according to the time taken to complete the problem, as well as by an assessment of their approach and coding style by a panel of judges.
The Problem
The Codehire Cup Semi-final (Round 2) problem read:
Instructions
Implement a firewall to process incoming TCP network packets. For each packet, the firewall must determine what action to take and the specific rule that triggered the action. Action will be either
ALLOW
,REJECT
orDROP
represented as strings.You are given a rule set and a (simplified) representation of an incoming packet.
Rule Sets
A Rule Set comprises several rules with each rule containing an index (integer starting at 1), a field ID (character), a field match value (string) and the action to take. These values will be comma separated.
Field ID can be
I
,R
orP
(representing the attributes IP Address, Protocol and Port respectively).Field values are an arbitrary string and can be the special value
*
which represents any value.For example:
1,I,192.168.0.1,ALLOW 2,P,443,REJECT 3,R,Gopher,DROP 4,I,*,ALLOWPackets
Packets are represented as a comma delimited string containing the source IP address (string), Protocol (string) and Port (Integer)
For example:
192.168.10.100,HTTP,80Provided Input
The challenge provides you with sample inputs containing a packet definition on the first line followed by 1 or more lines of a rule set.
Matching
A firewall rule is matched when the given field and field value are present in the TCP packet representation. At this point traversal of the rule set should halt and your program should write the rule index and the action taken to the challenge output as a comma delimited pair.
For example:
3,DROPNo Match
If the packet matches none of the rules in the rule set then you must return the default action which will always be
ALLOW
. The rule index in this case is 0.ie:
0,ALLOW
The Solution
Since the string representations of the various fields are the same for both the firewall rules and the packets, and since we’re only matching exact values, we don’t need to parse the individual fields. All that we have to do is compare the relevant field in the rule to the relevant field in the packet.
fields = %w(I R P)
packet, *rules = input.split("\n").map { |e| e.split(',') }
action = '0,ALLOW'
rules.each do |rule|
field = fields.index(rule[1])
if rule[2] == '*' or rule[2] == packet[field]
action = rule[0] + ',' + rule[3]
break
end
end
output << action
The solution assumes well-formed input.
Another Solution
The shortest code golf (short but unreadable) solution I could come up with in Ruby is 143 characters.
p,*r=input.split("\n").map{|e|e.split(',')}+[%w{0 I * ALLOW}]
output<<(m=r.select{|r|r[2]=='*'||r[2]==p[%w{I R P}.index(r[1])]}[0])[0]+','+m[3]
More Codehire Cup 2013 Solutions
- Codehire Cup Preliminary (Round 1) Solution
- Codehire Cup Semi-final (Round 2) Solution
- Codehire Cup Grand Final (Round 3) Solution