Players of the traditional board game Go measure their skill in a system of ranks:

  • Players new to the game are ranked 30th kyū (written 30k) and progress counting down to 1st kyū (written 1k). These are considered the student ranks.
  • A player may promote from 1st kyū to 1st dan rank (written 1d), and then progress counting up to 7th dan rank (written 7d). These are the master ranks.
  • Exceptionally skilled players past 7d may promote to the 1st professional dan rank 1p, and progress counting up to 9th professional dan rank (written 9p). This is the highest rank.

In short: ranks are ordered 30k < 29k < ··· < 1k < 1d < 2d < ··· < 7d < 1p < 2p < ··· < 9p.


Given two strings among {30k, …, 1k, 1d, …, 7d, 1p, …, 9p} as input, output the higher rank of the two. (If they are equal, simply output either input.)

(As usual, I/O is flexible — your answer may be a function or a full program, reading input in any reasonable fashion and producing output in any reasonable fashion.)

This is : the objective is to minimize your code's byte count.

Test cases

(Format: input1 input2 output.)

29k 9k    9k
21k 27k   21k
6d 1p     1p
5d 17k    5d
1k 1d     1d
1d 1d     1d
1d 2d     2d
9p 1d     9p
2d 30k    2d
1p 1k     1p
1d 1p     1p
1p 2d     1p
7p 8p     8p
30k 30k   30k
  • \$\begingroup\$ Can the inputs require leading zeroes? I.e. 04k \$\endgroup\$ – Amphibological Jul 7 '18 at 21:04
  • 6
    \$\begingroup\$ No; while I'm flexible about I/O methods, I'm afraid I won't allow any variation in the input strings themselves — I think they are a perfect level of "interesting" as-is. (I won't allow 4 k or 4K or so, either.) \$\endgroup\$ – Lynn Jul 7 '18 at 21:10
  • 2
    \$\begingroup\$ Are we allowed to take the inputs as (int, string) pairs? \$\endgroup\$ – Mnemonic Jul 7 '18 at 21:15
  • 9
    \$\begingroup\$ No; again, the spirit of the challenge is to manipulate the exact text strings 30k, 29k, 1k, 1d et cetera, so I won't allow any variation there. \$\endgroup\$ – Lynn Jul 7 '18 at 21:26

35 Answers 35


R, 83 bytes


Try it online!

Inspired by this answer by Zahiro Mor and digEmAll's comments on the answer. OP has not replied to comments so I am posting it separately, adding my own do.call twist to it to save additional bytes.

do.call takes arguments to the function as a list, which we do not need to eval before passing - a parse is sufficient. Still, as.list costs a lot of bytes...

Still not as golfy as digEmAll's chartr answer!


[R], 87 [bytes]


using JayCe's golfing: f=function(v,k=-1,d=1,p=10)v[eval(parse(t=paste(gsub('(\\D)','*\\1',v),collapse='<')))+1]

[R], 150 [bytes]

a long answer I find interesting could save a lot of bytes if not sticking to the eval method. inputs are s1 and s2:

f=function(s)eval(parse(t=sub("\\D+",paste0("*",c(-1,1,8)[match(tail(el(strsplit(s,"")),1), c("k","d","p"))]),s)));c(s1,s2)[as.numeric(f(s1)<f(s2))+1]
  • 2
    \$\begingroup\$ The eval approach can be improved like this -> Try it online! \$\endgroup\$ – digEmAll Jul 8 '18 at 17:19
  • 1
    \$\begingroup\$ nice! evaluating the inequality..... I did not think of that :) \$\endgroup\$ – Zahiro Mor Jul 9 '18 at 11:29
  • \$\begingroup\$ You can update your answer based on @digEmAll's comment - nice approach! \$\endgroup\$ – JayCe Aug 17 '18 at 0:53
  • 1
    \$\begingroup\$ And it's golfable to 87 chars due to R's lexical scoping rules. \$\endgroup\$ – JayCe Aug 17 '18 at 1:56

Pyth, 15 bytes

Also uses Arnauld's method.


Try it here!


Jelly, 20 bytes


Try it online!


Kotlin, 256 bytes

{f:String,s:String->{val e={s:String->if(s.length==2)"0$s"
else s}
val d=e(f)
val n=e(s)
val r=when(d[2]){'k'->if(n[2]=='k')if(d<n)f
else s
else s
else f
else if(n[2]=='k')f
else s
else f
else f}

Try it online!

  • \$\begingroup\$ 46 \$\endgroup\$ – ASCII-only Apr 3 at 2:03

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.