RogerBW's Blog

Perl Weekly Challenge 91: Number Jump 18 December 2020

I’ve been doing the Perl Weekly Challenges. The latest involved breaking down numbers and following sequences. (Note that this is open until 20 December 2020.)

TASK #1 › Count Number

You are given a positive number $N.

Write a script to count number and display as you read it.

The examples make this clearer. For each subsequence of identical digits, emit (the length of that subsequence) followed by (the digit), the whole lot to be concatenated into a single string. (As usual, the question of why one might want to do this is elided.)

This is the Perl weekly challenge so I do it with regular expressions.

sub cn {
  my $n=shift;
  my @j=$n =~ /((.)\2*)/g;

This is a little bit awkward, because I end up capturing both the full subsequence ("333") and the individual character ("3").

  my @out;
  while (@j) {
    push @out,length(shift @j);
    push @out,shift @j;
  }
  return join('',@out);
}

Raku returns a bunch of match objects, so I can stringify them and just pull out the full subsequence.

  my @j=$n ~~ m:g/((.)$0*)/;
  my @out;
  for @j -> $match {
    my $q=$match.Str;
    @out.push(chars($q));
    @out.push(substr($q,0,1));
  }

(Why $0 rather than $1? I have no idea.)

Python is more like Perl, though it gives me a list of lists rather than a flat list.

    m=re.findall(r'((.)\2*)',n)
    out=list()
    for mch in m:
        out.append(str(len(mch[0])))
        out.append(mch[1])

and Ruby looks remarkably like Python. (Obviously the use of the intermediate variable j is a holdover from the Perl code; for all the other languages I could use the regexp evaluation directly as a loop iterator.)

def cn(n)
  j=n.scan(/((.)\2*)/)
  out=Array.new
  j.each do |x|
    out.push(x[0].length)
    out.push(x[1])
  end
  return out.join
end

Rust is a bit different, because its built-in regexp library doesn't do backreferences (which makes it faster, and they aren't often needed). There's an external library which can do them, but I wanted to keep things simple. So instead I just iterate through the string, noting when the character changes. Yeah, probably the if count>0 clause should have gone in a subroutine rather than being duplicated.

fn cn(n: String) -> String {
    let mut out="".to_string();
    let mut ch='x';
    let mut count=0;
    for c in n.chars() {
        if c == ch {
            count += 1;
        } else {
            if count>0 {
                out.push_str(&(count.to_string()));
                out.push_str(&(ch.to_string()));
            }
            ch=c;
            count=1;
        }
    }
    if count>0 {
        out.push_str(&(count.to_string()));
        out.push_str(&(ch.to_string()));
    }
    return out;
}

TASK #2 › Jump Game

You are given an array of positive numbers @N, where value at each index determines how far you are allowed to jump further.

Write a script to decide if you can jump to the last index. Print 1 if you are able to reach the last index otherwise 0.

Again this is made clearer by the examples. Start at index 0. Add to the current index the value at that index. Repeat. If you will eventually reach the final index, return 1, otherwise return 0.

The examples give two outcomes: a successful completion (1,2,1,2), or a system which will hit a value of 0 (not, I note, a positive number!), producing an infinite loop (2,1,1,0,2). Another possible outcome is a jump beyond the end of the array, which I assume must also return 0: (2,1).

Well, that's pretty straightforward:

sub jg {
  my $n=shift;
  my $mx=$#{$n};
  my $p=0;
  while (1) {
    $p+=$n->[$p];

The success case: landed on the final entry.

    if ($p == $mx) {
      return 1;

The failure cases: run off the end or landed on a zero. If we were allowed negative numbers I'd also check for the case $p < 0. If the setter intended that running off the end counted as a success, the changes would be obvious.

    } elsif ($p > $mx || $n->[$p] == 0) {
      return 0;
    }
  }
}

The other languages are basically the same except for minor differences of syntax.

Full code on github.

Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.

Search
Archive
Tags 1920s 1930s 1940s 1950s 1960s 1970s 1980s 1990s 2000s 2010s 3d printing action aeronautics aikakirja anecdote animation anime army astronomy audio audio tech aviation base commerce battletech beer boardgaming book of the week bookmonth chain of command children chris chronicle church of no redeeming virtues cold war comedy computing contemporary cornish smuggler cosmic encounter coup covid-19 cycling dead of winter doctor who documentary drama driving drone ecchi economics espionage essen 2015 essen 2016 essen 2017 essen 2018 essen 2019 existential risk falklands war fandom fanfic fantasy feminism film firefly first world war flash point flight simulation food garmin drive gazebo genesys geocaching geodata gin gkp gurps gurps 101 gus harpoon historical history horror hugo 2014 hugo 2015 hugo 2016 hugo 2017 hugo 2018 hugo 2019 hugo 2020 hugo-nebula reread in brief avoid instrumented life julie enfield kickstarter learn to play leaving earth linux liquor lovecraftiana mecha men with beards museum music mystery naval non-fiction one for the brow opera parody paul temple perl perl weekly challenge photography podcast politics postscript powers prediction privacy project woolsack pyracantha python quantum rail raku ranting raspberry pi reading reading boardgames social real life restaurant reviews romance rpg a day rpgs ruby rust science fiction scythe second world war security shipwreck simutrans smartphone south atlantic war squaddies stationery steampunk stuarts suburbia superheroes suspense television the resistance thirsty meeples thriller tin soldier torg toys trailers travel type 26 type 31 type 45 vietnam war war wargaming weather wives and sweethearts writing about writing x-wing young adult
Special All book reviews, All film reviews
Produced by aikakirja v0.1