| Bytes | Lang | Time | Link |
|---|---|---|---|
| 508 | Python3 | 250311T175945Z | Ajax1234 |
| 189 | Perl | 151220T022851Z | Kenney |
| 334 | JavaScript ES6 | 151219T083109Z | user8165 |
Python3, 508 bytes
import re
E=enumerate
def f(t,s):
v=[]
while t:a,b,t=re.findall('(^\d+)(\D+)(.+)*',t)[0];v=v+[[b]*int(a)]if[]==v or v[-1][-1].lower()!=b.lower()else v[:-1]+[v[-1]+[b]*int(a)]
d={i[0].lower():''.join(i)for i in v}
d={(x,y):v for x,r in E([d.get(chr(i),'')for i in range(ord(min(d)),ord(max(d))+1)])for y,v in E(r)}
q,l=[(*i,[i])for i in d if 0==i[1]and d[i]==s],0
for x,y,p in q:l=max(l,y+1);q+=[(*D,p+[D])for X,Y in[(-1,0),(1,0),(0,-1),(0,1)]if d.get(D:=(x+X,y+Y),'').isupper()and D not in p]
return l
Perl, 231 219 203 192 189 bytes
includes +1 for -p
sub f{my($l,$p,$m)=@_;map{$m=$_>$m?$_:$m}f($l,$p+1)+1,f($l-1,$p),f($l+1,$p),f($l,$p-1)-1if$L[$l][$p]&&!$V{$l}{$p}++;$m}s/(\d+)(.)\s*/push@{$L[ord$2&~32]},(0|$2lt'a')x$1;()/ge;$_=0|f(ord,0)
Less golfed:
sub f{ # this is a recursive function, so we need locals.
my($l,$p,$m)=@_; # in: lane, position; local: max path length
map{
$m = $_ > $m ? $_ : $m # update max
}
f( $l, $p+1 )+1, # same lane, forward
f( $l-1, $p ), # left lane, same pos
f( $l+1, $p ), # right lane, same pos
f( $l, $p-1 )-1 # same lane, backtrack
if
$L[$l][$p] # check if there's road here
&& !$V{$l}{$p}++ # and we've not visited this point before.
;
$m # return the max
}
s/(\d+)(.)\s*/ # Parse RLE pattern, strip starting lane separator
push@{ $L[ord$2&~32] } # index @L using uppercase ascii-code, access as arrayref
,(0|$2lt'a')x$1 # unpack RLE as bitstring
;() # return empty list for replacement
/gex; # (x for ungolfing)
# $_ now contains trailing data: the start lane.
$_ = # assign output for -p
0| # make sure we print 0 instead of undef/nothing
f(ord,0) # begin calculation at start of current lane
Running
Store the code above in a file (say 231.pl). Input in the form of (\d+\w)+ *\w. Example: inputting track 4A5B4c3C and lane A:
echo 4A5B4c3C A | perl -p 231.pl
TestSuite
(not golfed)
printf "==== Testing %s\n", $file = shift // '231.pl';
sub t{
my($input,$expect) = @_;
# $input =~ s/\s//g;
printf "TEST %-20s -> %-3s: ", $input, $expect;
$output = `echo $input | perl -p $file`;
printf "%-3s %s\n", $output,
$output == $expect
? " PASS"
: " FAIL: $output != $expect";
}
t("4A5B4c3C A", 7);
t("4A5B4c3C C", 0);
t("4A2B3D D", 3);
t("4A4a4A3b6B5C A", 12);
t("4A4a4A3b6B5C B", 0);
t("4A4a4A3b6B5C C", 12);
t("12M4n10N11O M", 14 );
t("4A5B1b2B4c3C A", 8);
t("1a2A2a2B1c1C1d3D B", 4 );
t("2A1b1B2C1D3E A", 3 );
t("10A9b1B8c2C9D1E11F A", 11);
- update 219 save 12 bytes by reworking array indices.
- update 203 Save 16 bytes by refactoring recursion.
- update 192 save 11 bytes by eliminating the
@L=map{[/./g]}@Lpostprocessing. - update 189 save 3 bytes by postfixing
ifusingmapinstead offor.
JavaScript (ES6), 298 334 bytes
(t,s)=>[a=[],t.match(/\d+(.)(\d+\1)*/gi).map(l=>a[c=l.match`[A-Z]`+"",n=c.charCodeAt(),c==s?i=n:n]=l[r="replace"](/\d+./g,p=>(p.slice(-1)<"a"?"1":"0").repeat(parseInt(p))),i=o=-1),...a.join``,a[i]?a[i]=a[i][r](/^1/,2):0].map(_=>a.map((l,y)=>a[y]=l[r](/1/g,(c,x)=>((a[y-1]||s)[x]|(a[y+1]||s)[x]|l[x-1]|l[x+1])>1?(x>o?o=x:0,2):c)))&&o+1
Explanation
Basically this solution treats the track as a maze. It finds where all the tiles that are possible for the runner to reach are and returns the greatest value of the X index it found.
The first thing it does is decode the input string into an array of lines. Instead of using letters though, it turns a capital letter into a 1 and a lowercase letter into a 0. The resulting map will look something like this:
11100011
0011100
100111
After this it makes the first tile of the starting track a 2 (only if it is already 1) and loops through every tile checking adjacent tiles for a 2. If a 1 has an adjacent 2 it becomes a 2. The above map will become this if the runner started on the first line:
22200011
0022200
100222
The highest X index for a 2 becomes the result.
I made a very minor oversight when I did the initial version of this and it cost me 36 bytes to hack at it until it worked, so there's probably a lot of improvements that could be made to this. *sigh*
Ungolfed
(t,s)=>
[
// Decode run-length encoded string into an array of track lanes
a=[], // a = array of track line strings, 0 = air, 1 = tiles
t.match(/\d+(.)(\d+\1)*/gi) // regex magic that separates pairs by their letter
.map(l=> // for each line of pairs
a[ // add the tiles to the array
c=l.match`[A-Z]`+"", // c = pair character
n=c.charCodeAt(), // n = index of line
c==s?i=n:n // if this line is the starting line, set i
]=l[r="replace"](/\d+./g,p=> // match each pair, p = pair
(p.slice(-1)<"a"
?"1":"0").repeat( // repeat 0 for air or 1 for ground
parseInt(p) // cast of match would return NaN because of the
) // letter at the end but parseInt works fine
),
i= // i = index of starting line, initialise as invalid
o=-1 // o = output (max value of x)
),
// Find all positions that are possible for the runner to get to
...a.join``, // add every letter of the track lines to an array
a[i]?a[i]=a[i][r](/^1/,2):0 // set the starting tile to 2 if it is already 1
].map(_=> // loop for the amount of tiles, this is usually way
// more than necessary but allows for hard to reach
// tiles to be parsed
a.map((l,y)=> // for each line l at index y
a[y]=l[r](/1/g,(c,x)=> // for each character c at index x
// Replace a 1 with 2 if there is a 2 to above, below, left or right of it
((a[y-1]||s)[x]|(a[y+1]||s)[x]|l[x-1]|l[x+1])>1?
(x>o?o=x:0,2):c // set o to max value of x for a 2 tile
)
)
)
&&o+1 // return o + 1
Test
Bonus: Output includes the parsed map!
var solution = (t,s)=>[a=[],t.match(/\d+(.)(\d+\1)*/gi).map(l=>a[c=l.match`[A-Z]`+"",n=c.charCodeAt(),c==s?i=n:n]=l[r="replace"](/\d+./g,p=>(p.slice(-1)<"a"?"1":"0").repeat(parseInt(p))),i=o=-1),...a.join``,a[i]?a[i]=a[i][r](/^1/,2):0].map(_=>a.map((l,y)=>a[y]=l[r](/1/g,(c,x)=>((a[y-1]||s)[x]|(a[y+1]||s)[x]|l[x-1]|l[x+1])>1?(x>o?o=x:0,2):c)))&&o+1
function generateMap() { var start = 0; a.some((l, i) => l ? start = i : 0); var end = 0; a.map((l, i) => l && i <= 90 ? end = i : 0); for(var output = "", i = start; i < end + 1; i++) output += String.fromCharCode(i) + ") " + (a[i] || "") + "\n"; return output; }
Track = <input type="text" id="track" value="2A1b1B2C1D3E" /><br />
Starting Letter = <input type="text" id="start" value="A" /><br />
<button onclick="result.textContent=solution(track.value,start.value)+'\n\n'+generateMap()">Go</button>
<pre id="result"></pre>