An old test for programmers, taken from here (Note: in italian).

Along a road (denoted by '_'), there is a Magical Piper (denoted by 'P') and several mice (represented by the two characters 'o' and '~', that denote respectively the head and the tail of the small rodents).

Write a program that prints how many mice are going towards the Piper and how many mice are going away from him.

The input is a string, the output are two numbers, the first the number of mice that go towards the Piper, the second the number of mice that go away from the Piper.

The input can be also a list or vector of characters, and the output a vector or list of two numbers. You can assume that the input is always correct.

Both programs as well as functions are allowed.


input: __o~P_o~~o

output: 1 2

input: __P~oo~o~_o~~o__

output: 3 2

input: ~oPo~

output: 2 0

input: o~P~o

output: 0 2

This is code golf, so the shortest program in any language wins.

Note: In the question, I've removed the requirement of an error message, given the majority prefer it this way. Sorry for people that already coded the error test!

  • 8
    \$\begingroup\$ I'd prefer if there weren't error checking, but the input was guaranteed to be well formed \$\endgroup\$ – xnor Feb 6 at 9:33
  • 4
    \$\begingroup\$ @xnor, I maintaned the error to be true to the original text, but if you think that it is more interesting for this site to assume always correct input, I will change the question. \$\endgroup\$ – Renzo Feb 6 at 10:14
  • 1
    \$\begingroup\$ As for me, it would be indeed more interesting with error-checking. \$\endgroup\$ – Andriy Makukha Feb 6 at 12:09
  • 1
    \$\begingroup\$ @KevinCruijssen, added to the question, thanks! \$\endgroup\$ – Renzo Feb 6 at 15:18
  • 1
    \$\begingroup\$ Ah, ok. In any case I think the best thing to do is to left everything as it is now. \$\endgroup\$ – Renzo Feb 6 at 23:33

25 Answers 25


Ruby, 128 .. 51 49 bytes

->w{%w(o ~).map{|c|w.scan(/_*._*(.)/).count [c]}}

Try it online!

No error checking.


  • Ignore all underscores
  • All mice going towards the piper have the head in an odd-numbered (0-based) position.
  • All mice heading away from the piper have the tail in an odd-numbered position.
  • Take every 2nd character (skipping underscores), count heads and tails.

Ruby (with error checking), 109 99 97 bytes

->w{w.chars+w.scan(/[o~]./)-%w(o ~ _ ~o o~)==[?P]?%w(o ~).map{|c|w.scan(/_*._*(.)/).count [c]}:q}

Try it online!

Thanks Value Ink for -2 bytes on both.

  • 1
    \$\begingroup\$ [?o,?~].map [...] .count [c] saves 2 bytes. \$\endgroup\$ – Value Ink Feb 8 at 0:14

05AB1E, 13 11 10 bytes


Port of @GB's Ruby answer, so make sure to upvote him!!
-1 byte thanks to @Grimmy by taking the input as character-list.

Try it online or verify all test cases.


'_K        '# Remove all "_" from the (implicit) input-list
   ā        # Push a list in the range [1, length] (without popping the list)
    È       # Check for each whether it's even
     Ï      # Only keep the characters at these even 1-based indices
      a     # Check for each remaining character whether it's a letter or not
            # (1 if 'o'; 0 if '~')
       TS   # Push 10 as digit-list: [1,0]
         ¢  # And count each in the list of 0s and 1s
            # (after which this pair of counts is output implicitly as result)

JavaScript (Node.js),  80 66 65 58  57 bytes

Returns [towards, away].


Try it online!


An efficient way to determine whether the character is a mouse body part is to take the ASCII code modulo \$3\$.

Quite conveniently, we can also distinguish between P and _ or between o and ~ by simply testing the parity of the corresponding ASCII codes.

 character  | 'P' | '_' | 'o' | '~'
 ASCII code |  80 |  95 | 111 | 126
 modulo 3   |   2 |   2 |   0 |   0
 modulo 2   |   0 |   1 |   1 |   0


s =>                       // s = input string
  Buffer(s)                // turn s into a buffer
  .map(c =>                // for each ASCII code c:
    c % 3 ?                //   if c modulo 3 is not equal to 0:
      i ^= ~c              //     invert the least significant bit of i if c is even
                           //     (must be 80, for 'P')
    :                      //   else:
      a[c & 1] += ++i & 1, //     update a[0] if c is even (126 -> '~')
                           //     or a[1] if c is odd (111 -> 'o')
                           //     increment i and add its parity
    a = [i = 0, 0]         //   start with a = [0, 0] and i = 0
  ) && a                   // end of map(); return a[]

JavaScript (Node.js),  112  102 bytes

A version with error checking, as per the original rules of the challenge.


Try it online!

  • 1
    \$\begingroup\$ @KevinCruijssen Thanks! But I was already editing to another 57. \$\endgroup\$ – Arnauld Feb 6 at 15:21
  • \$\begingroup\$ Then I'll post it as a separated answer. :) \$\endgroup\$ – Kevin Cruijssen Feb 6 at 15:22

Python 2, 47 bytes

Port of G B's Ruby answer.

lambda s:map(s.replace('_','')[::2].count,'~o')

Try it online!


Python 2, 252 \$\cdots\$ 71 72 bytes

Saved 29 bytes thanks to JoKing!!!
Saved 2 bytes thanks to ovs!!!
Saved a byte thanks to ReinstateMonica!!!
Saved 21 bytes thanks to KevinCruijssen!!!
Added a byte to fix a bug kindly pointed out by JoKing.

def f(s):
 for c in s:
 return r

Try it online!

Inputs a string and outputs a list.

  • \$\begingroup\$ @JoKing Very clever stuff - thanks! :-) \$\endgroup\$ – Noodle9 Feb 6 at 14:31
  • 1
    \$\begingroup\$ 93 bytes with '~'==c -> c>'o' and i=1-i -> i^=1. \$\endgroup\$ – ovs Feb 6 at 14:51
  • \$\begingroup\$ def f(s,i=1,r=[0,0]): also saves a byte over assigning i and r in the function \$\endgroup\$ – Reinstate Monica Feb 6 at 16:09
  • \$\begingroup\$ @ovs Nice golfs - thanks! :-) \$\endgroup\$ – Noodle9 Feb 6 at 16:25
  • 3
    \$\begingroup\$ And an additional -19 bytes by removing the if'P'==c:r=r[::-1] line completely and modifying the other line a bit. Since P is guaranteed to be at an even index if we ignore all _, the character P will always result in an i=0 increase, so it won't matter for the r[c>'o']+=i;. Now it's basically a port of my Java 8 answer. :) \$\endgroup\$ – Kevin Cruijssen Feb 6 at 18:14

J, 27 19 bytes


Try it online!

This took inspiration from both Kevin's answer and GB's answer.


We'll work through an example: __o~P_o~~o

  • '_'-.~] Remove the underscores:

  • _2=&'~'\ For every two characters, create a boolean mask where 1 indicates that the character in that position is ~:

    0 1  o~
    0 0  Po
    1 1  ~~
    0 0  o 
  • [:+/ Sum the colums:

    1 2

Retina, 31 bytes


Try it online!



Recursively replace all mice walking to the left with a 1. Mice walking to right stay as they are.


Swap 1 and ~ at all positions up to the P.


Every 1 stands for a mouse walking towards the Magical Piper. Count the 1's and output the result without changing the current string.


Count ~'s (implicit output). every ~ stands for a mouse walking away from the Magical Piper.

Retina, 23 18 bytes

port of G B's Ruby answer. 5 bytes shorter thanks to Neil.



Try it online!

  • 1
    \$\begingroup\$ It's golfier to delete even-numbered characters: Try it online! \$\endgroup\$ – Neil Feb 6 at 14:35
  • \$\begingroup\$ @Neil This looks much better. thanks a lot. \$\endgroup\$ – ovs Feb 6 at 14:46

JavaScript (Node.js), 57 54 bytes


Alternative JavaScript answer for the existing JavaScript answer (of equal byte-count at time of writing), which I figured was worth posting as separated answer. Loosely based on my Java 8 answer and inspired by @GB's Ruby answer.

-3 bytes thanks to @Arnauld.

Try it online.


s=>                 // Method with string as parameter and integer-array as result
  Buffer(s).map(c=> //  Loop over the characters in the String as codepoint integers:
    a[~c&1]+=       //   Increase the count at index (c+1)%2 by:
      c%19&&        //    If c modulo-19 is NOT 0:
            i++%2,  //     Add i%2 to the count, and increase i by 1 afterwards
    a=[i=0,0]       //  Start the counts at [0,0] and i at 0
  )&&a              //  After the loop, return this resulting pair of counts

The codepoints of the four used characters are 'P'=80, '_'=95, 'o'=111, '~'=126, which I'm using to my advantage:

  • The ~c&1 will result in index 0 for the character 'o' and index 1 for character '~'. (It will also result in index 1 for character 'P' and index 0 for character '_', but this won't cause any issues.)
  • The modulo-19 is to ignore '_' characters. Using the modulo-19 on the four codepoints results in 4,0,16,12 for P_o~ respectively, for which the '_' is falsey and the other three are truthy.

The i++%2 will only add 1 to the count for odd-indexed characters. All even-indexed characters won't affect the counts. Since the 'P' is guaranteed to be at an even-indexed position (when ignoring the '_' with c%19&&), the count for character 'P' will always increase by 0, and thus stay the same.

  • 1
    \$\begingroup\$ 54 bytes \$\endgroup\$ – Arnauld Feb 6 at 15:38
  • \$\begingroup\$ @Arnauld Thanks! I had the feeling a=[i=0,0] might have been possible somehow like in your answer, but couldn't figure it out. Now that I see the i++%2 I can't believe I hadn't thought of it just yet. And nice ~c&1 trick! \$\endgroup\$ – Kevin Cruijssen Feb 6 at 15:43

JavaScript (ES6)

Port of G B's Ruby answer.


C (gcc),  87  85 bytes

Saved 2 bytes thanks to @xibu

Prints the results as towards away.

a,b,p;f(char*s){for(a=b=p=0;*s;s++)*s%3?p|=~*s:p+*s++&1?b++:a++;printf("%d %d",a,b);}

Try it online!


a,                       // a = 'towards' counter
b,                       // b = 'away' counter
p;                       // p = piper flag
f(char *s) {             // f is function taking a pointer to a string s
  for(                   // main loop:
    a = b = p = 0;       //   start with a = b = p = 0
    *s;                  //   go on while the end of the string is not reached
    s++                  //   advance the pointer after each iteration
  )                      //
    *s % 3 ?             //   if the current character is not a mouse body part:
      p |= ~*s           //     set the piper flag if the ASCII code is even (80 -> 'P')
    :                    //   else:
      p + *s++ & 1 ?     //     test the parity of (p + current ASCII code) and advance
                         //     the string pointer to skip the next body part
                         //     if odd:
        b++              //       increment b
      :                  //     else:
        a++;             //       increment a
  printf("%d %d", a, b); // print the results
}                        //

C (gcc),  72  70 bytes

Saved 2 bytes thanks to @mypronounismonicareinstate

This version saves the results in an array passed as a 2nd argument. I don't know for sure if it's acceptable.


Try it online!

  • \$\begingroup\$ per I/O rules, the second variant is acceptable, but I think you should keep the original entry somewhere in the answer. \$\endgroup\$ – Krzysztof Szewczyk Feb 6 at 15:19
  • 1
    \$\begingroup\$ I think r[0] -> *r in the second program. \$\endgroup\$ – my pronoun is monicareinstate Feb 6 at 15:23
  • 1
    \$\begingroup\$ suggestion for -2 Bytes TIO \$\endgroup\$ – xibu Feb 6 at 16:25
  • \$\begingroup\$ The typeless variables are certainly not C++, is that a C feature? Also could you please explain what your code is doing? 🤔🤔🤔 \$\endgroup\$ – Varad Mahashabde Feb 13 at 14:40
  • \$\begingroup\$ @VaradMahashabde There's no such thing as a typeless variable in C, but the default type is int when it's not specified. (Of course, you should not do that in any serious piece of code.) I've added a commented version. You may also see my JS answer for more details about the ASCII code logic. \$\endgroup\$ – Arnauld Feb 14 at 9:04

05AB1E, 17 bytes


Try it online!


MATL, 25 bytes


Try it online!

  • 1
    \$\begingroup\$ @Arnauld is indeed correct. I.e. o~P~o should result in 0 2 and ~oPo~ should result in 2 0, but they both result in 1 1 in your answer. \$\endgroup\$ – Kevin Cruijssen Feb 6 at 13:20
  • \$\begingroup\$ Thanks for noticing! My bad \$\endgroup\$ – Luis Mendo Feb 6 at 13:54
  • \$\begingroup\$ Solved now, with a few more bytes \$\endgroup\$ – Luis Mendo Feb 6 at 14:50

Pyth, 14 bytes


Try it online!

A port of @GB's wonderful Ruby answer, go give him your upvotes!

Terrible explanation:

/       \~      // Count the occurrences of "~" in:
 J              // J=
  %2            // Every second character of
    -z\_        // every character of the input not in "_"
                // Implicit print
          /J\o  // Count the occurrences of "o" in J
                // Implicit print

Python 3.8, 62 bytes

lambda s:((v:=s.replace("_","")[::2]).count("o"),v.count("~"))

You can try it online. Link has two extra bytes to give a name to the function.

Port of this Ruby answer, so be sure to upvote it as well!

  • \$\begingroup\$ Your TIO link shows an error. \$\endgroup\$ – xnor Feb 6 at 15:47
  • \$\begingroup\$ @xnor thanks for catching that! corrected. \$\endgroup\$ – RGS Feb 6 at 15:50

Burlesque, 11 bytes


Try it online!

Using the algorithm of G B's answer

Burlesque, 24 bytes


Try it online!

Without error checking.

'P;;   # Split at P
^p<-   # Reverse those following the piper
_+     # Rejoin
'_;;   # Remove all road
m{2co} # Split each into pairs (i.e. mice)
FL     # Flatten array
f:     # Count mice

Burlesque, 44 bytes


Try it online!

With error checking. As above but with checks to see if lists are correct lengths and throw impossible action if not, halting execution.


Jelly, 14 13 10 bytes

A monadic link taking the string as input.


You can try it online.

Port of this Ruby answer so check it as well!

ḟ”_         remove all the underscores from the string

   m2       Then take a slice modulo 2 and
                for what remains
      Ɱ“~o  go over the characters ~ and o
     ċ      counting how many times they show up.

Output is [towards, away].

-3 bytes thanks to @Jonathan and @Nick.

  • 1
    \$\begingroup\$ You have the wrong quoting instruction on the right ( should be ). Save two bytes using modulo-indexing by two after dequeuing TIO \$\endgroup\$ – Jonathan Allan Feb 6 at 18:32
  • \$\begingroup\$ @JonathanAllan thanks! I looked for something like m2 but couldn't find it and so went for my lengthier version :p thanks! \$\endgroup\$ – RGS Feb 6 at 18:51

PHP, 108 bytes

for(;$b=$argn[$j++];){$b!='P'?:$p++;$b=='~'?($p&++$j?$m++:$n++):($b!='o'?:($p&++$j?$n++:$m++));}echo"$n $m";

Try it online!

Back to more serious golfing, ends like a port of Noodle9's original answer (but much more readable)


PHP, 156 bytes

$a=explode('P',$argn);for($i=2;$i--;$j=0)for($b=$a[$i];$b[$j];){$t=$b[$j].$b[++$j];if($t=='~o')$i&++$j?$n++:$m++;if($t=='o~')$i&++$j?$m++:$n++;}echo"$n $m";

Try it online!

Ok, this is really horrible and far from optimal, but I had real fun writing this unreadable atrocity. Forgive me :D (the reason behind the explode was to check validity for original post rule of only one P in the string)


PHP, 213 bytes

$a=explode('P',$argn);for($i=0;isset($a[$i]);$j=0,++$i<3?:die(0.))for($b=$a[$i];$b[$j];){strpos(" _~o",$b[$j])?:die(0.);$t=$b[$j].$b[++$j];$t=='~o'?($i&$j++?$m++:$n++):($t!='o~'?:($i&$j++?$n++:$m++));}echo"$n $m";

Try it online!

Caveat: won't display the zero results, but ,$n=0,$m=0 can be added after $i=0 to make it so.


GolfScript, 46 bytes 36 bytes


Significant improvement from my previous algorithm. Enough so that I'm willing to actually explain it.

1/                                     #Split the string into an array of chars
  {"_"=!},                             #Replace the prev array with one without underscores
          'P'%~                        #Split the array at the piper
               -1%                     #Reverse the second array (right side)
                                       #This has the function of making all correct mice
                                       #face the same way, which makes for easier matching
                  +                    #Concatenate
                   2/                  #Split the array into groups of two
                                       #so we only an array of mouse-strings!
                     .                 #Duplicate our array, since we have to count twice
                      {"~o"=},,        #First count all valid mice
                               .       #Duplicate that count
                                @,     #Bring back that second array and count the mice
                                  \-   #Subtract (correct mice) from (all mice)
                                       #which only leaves (correct mice) then (wrong mice)

PowerShell, 46 42 bytes

Inspired by G B


Try it online!

    | ascii | %6 | even | odd
  P |   80  |  2 |   2  |  3
  _ |   95  |  5 |   5  |  6
  o |  111  |  3 |   3  |  4
  ~ |  126  |  0 |   0  |  1

The 4 and 1 are odd-numbered positions from the G B answer. No error checking.

PowerShell, 46 bytes


Try it online!

  • 1
    \$\begingroup\$ Sorry for casting a down vote; it was an accident! Could you please edit it slightly so that downvote is unlocked? \$\endgroup\$ – Varad Mahashabde Feb 13 at 14:53

Unix TMG, 115 bytes

p:ignore(<<_>>)r<P>[a=^t][t=^a][a=^t]r parse(d);r:<o~>[t++]r|<~o>[a++]r|();a:0;t:0;d:decimal(t)decimal(a)={2< >1};


p:ignore(<<_>>)r<P>[a=^t][t=^a][a=^t]r parse(d);
d:decimal(t)decimal(a)={2< >1};

Python 3, 86 bytes


Try it online!

Takes in the string, and finds the location of the Piper. Then just counts the number of mice behind him facing forwards, plus the number of mice ahead of him facing backwards - this is the total number of mice facing towards him. The number of mice facing away is just the total number of mice (the total number of '~'s) minus the number facing him.

Uses c to replace the count function, for byte saving.

  • 2
    \$\begingroup\$ Your TIO link gives an error when input is provided. To alias count, you'd need to refer to str.count. \$\endgroup\$ – xnor Feb 6 at 15:49

Java 8, 72 71 bytes

s->{int i=1,r[]=new int[2];for(int c:s)r[~c&1]+=c!=95?i^=1:0;return r;}

Port of @GB's Ruby answer, so make sure to upvote him!!
-1 byte thanks to @Arnauld.

Try it online.


s->{               // Method with char-array parameter and int-array return-type
  int i=1,         //  Toggle integer, starting at 1
   r[]=new int[2]; //  Result int-array of size 2, filled with 0s by default
  for(int c:s)     //  Loop over the input char-array:
    r[~c&1]+=      //   Increase the count at index (c+1)%2 by:
      c!=95?       //    If the character is NOT '_':
            i^=1   //     Toggle the integer (1→0 or 0→1), and add that to the current count
                   //     this will only add 1 for every odd-indexed character, ignoring '_'
           :       //    Else:
            0;     //     Keep the count the same by increasing with 0
  return r;}       //  And finally return this resulting pair of counts

K (ngn/k), 18 bytes

{+/2!0N 2#0,x^"_"}

Try it online!

{ } function with argument x

x^"_" remove all _s

0, prepend a 0

0N 2# split in pairs

2! mod 2 as ascii codes: P→80→0, o→111→1, ~→126→0

+/ sum


C++ (gcc), 189 184 170 bytes

#include <string>
struct a{int t;int f;};a f(std::string s){a r={0,0};for(int i=0,d=1;i<s.length();++i)s[i]%3?s[i]%2?1:d=0:s[i++]%2?d?r.f++:r.t++:d?r.t++:r.f++;return r;}

Try it online!

Expanded Version (Full Program) :

// Example program
#include <iostream>
#include <string.h>
using namespace std;

struct pseudo_arr {int to_piper; int from_piper;};
pseudo_arr countRats(string s) {
  pseudo_arr rats = {0,0};
  int direction = 1;
  for(auto i = s.cbegin();i!=s.cend();++i) {
    // Exploitable properties of the 4 characters
    // 'P' == 80  - %3 == 2, %3 == 0
    // '_' == 95  - %3 == 2, %2 == 1
    // '~' == 126 - %3 == 0, %2 == 0
    // 'o' == 111 - %3 == 0, %2 == 1 
    switch(*i) {
      case 'P' : // char(80) == 'P'
        direction = 0; // Crossed piper, change direction
      case 'o' :
        // If see head, skip tail
        // if before piper then away, else towards
        direction ? rats.from_piper++ : rats.to_piper++;
      case '~' :
      // if see tail, skip head
        // if before piper then towards, else away
        direction ? rats.to_piper++ : rats.from_piper++;
  return rats;

int main() {
  string input;
  getline(cin, input);
  pseudo_arr rat_count = countRats(input);
  cout << rat_count.to_piper << " " << rat_count.from_piper;

Z80Golf, 28 bytes

00000000: 1680 cd03 8030 0578 ff79 ff76 fe5f 28f0  .....0.x.y.v._(.
00000010: 1930 ed0c fe7e 28e8 0d04 18e4            .0...~(.....

Try it online!

  ld d, $80
  call $8003
  jr nc, ok
  ld a, b
  rst $38
  ld a, c
  rst $38
  cp '_'
  jr z, start
  add hl, de
  jr nc, start
  inc c
  cp '~'
  jr z, start
  dec c
  inc b
  jr start

Prints two bytes: towards and away.

One maybe-clever trick here is using add hl, de as a sort of flip-flop mechanism. Since de is fixed to $8000, it will overflow and set the carry flag every other time.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.