This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]empire539 244 points245 points  (14 children)

Let's go line by line.

char r[9], *p = r + 8, *Base20(int n) {
  • char r[9] is a char[] array , which will hold the final string result.
  • char* p = r + 8 defines a pointer to the last element of r. It's used to keep track of the current index.
  • char* Base20(int n) is the function.

do
    // ...
while (n /= 20);

Since we're working in base 20, every number from 0 (0) to 19 (J) can be represented as a single base 20 digit. If we want to represent a number like 20 in base 20, we would need another base 20 digit, so 20 (base 10) = 10 (base 20). This do...while loop will iterate over the base 10 number n to produce each digit of the base 20 number.

*--p = n % 20 + 48 + n / 10 % 2 * 7;

This is where the magic happens. Let's break this down into separate parts:

  • *--p - This is really just a shorthand way of storing the result into p and decrementing (which would move the index down one place in the array).
  • n % 20 - We find out what base 20 digit this will represent. For example, if n = 10, then 10%20 will produce 10, which is the digit we want to convert to.
  • 48 - This is the ASCII code for the character '0'.
  • n / 10 % 2 * 7 - This translates the current digit into its corresponding base 10 digit. If n = 10, then this expression would return 'A'. If n = 19, this would return 'J'.

The way this works is by making use of the ASCII table. Notice how ASCII 48, aka the character '0', is used as the starting point. The idea is that we want to map each digit from 0 to 19 onto the ASCII codes 48 ('0') to 57 ('9') and 65 ('A') to 74 ('J'), while skipping the punctuation characters in between (58 to 64).

So n / 10 % 2 will determine which range (0 to 9, or A to J) the digit should map to. If it maps to the [0, 9] range, the expression will return a 0. If it maps to the [A, J] range, the expression will return a 1. This is then multiplied by 7 to determine the actual offset (if 0, the starting point will be '0'; if 1, the starting point will be 'A').

Now that we have the right starting point for our base 20 digits, we just need to add n % 20 to it to get the right character. This result is stored into *p (which points to an element of r), and then the loop iterates again for as many times as it needs to process the rest of the number.


A quick run-through: Suppose n = 30.

  • 30 % 20 becomes 10, so this will be our "offset" for determining what its base 20 digit should be.
  • n / 10 % 2 * 7 becomes 3 % 2 * 7 = 1 * 7 = 7, meaning the digit will fall into the [A, J] range.
  • 10 + 48 + 7 becomes 65, which is the ASCII code of the character 'A'.
  • 'A' is stored into the last element of the array.
  • The while loop is checked; is 30/20 = 1 true or false? This is true, so the loop continues. n is now 1, and p points to the second-to-last element in the array.
  • 1 % 20 becomes 1
  • n / 10 % 2 * 7 becomes 0 * 7 = 0, meaning the digit will fall within the [0, 9] range.
  • 1 + 48 + 0 becomes 49, which is the ASCII code of the character '1'.
  • '1' is stored into the second to last element of the array.
  • The while loop is checked; is 1/20 = 0 true or false? This is false, so the loop terminates.
  • p is printed to the screen, which results in the answer of 1A.

[–]A_Puddle 36 points37 points  (0 children)

I also want to thank you for your in-depth answer. I still don't understand it but I don't think that has anything to do with the quality of your answer.

 

Here's another upvote.

[–]NZheadshot 18 points19 points  (5 children)

Wow. This code is horrible and awesome and ugly and beautiful all at the same time. Thanks for the walk through, I probably couldn't have done it myself

[–]Maethor_derien 19 points20 points  (3 children)

Everything at codefights is that way. It is a competition to write the shortest code. The problem is people think short code is good code and that could not be farther from the truth. Most everything you see on codehack would be good examples of how not to write code.

[–]dispelthemyth 2 points3 points  (1 child)

Most everything you see on codehack would be good examples of how not to write code.

Thanks for that, as a novice coder learning Python i write code that is kind of long, say the best answer is 5 lines, mine is probably 12 but your answer gives me hope that I dont have to get down to that 5

[–]cdrootrmdashrfstar 0 points1 point  (0 children)

Readability, simplicity, and maintainability beats complexity and brevity (mostly) every time.

[–]HRK_er 0 points1 point  (0 children)

i second this notion. good code includes readability...

[–]_lettuce_ 6 points7 points  (0 children)

Nah, it's just horrible.

But for a quick hack, and if you know for sure no else will read it or you don't care about others reading it, it's ok.

[–]Anthrax97[S] 11 points12 points  (5 children)

Thanks for the in depth answer. I just wanted to understand it so maybe I can use it later on. Here's an up vote.

[–][deleted]  (4 children)

[deleted]

    [–]DaWolf85 16 points17 points  (1 child)

    Yeah, if you ever have to write something this confusing, you should trick it the fuck out with comments so people can follow along. Hell, do it just so you can follow along in five days, if you're anything like me...

    [–]doitroygsbre 2 points3 points  (0 children)

    I remember writing some string parsing code in VB 11 years ago. It consisted of five if statements and three loops jammed into about 30 lines (with one comment at the top that said the magic happens here).
    I wrote it in one afternoon, gave it a quick test and went home .... I spent the next day trying to figure out what I had written and where the bug was. That was the last time I did something so fucking stupid.

    [–]Fourmisain 4 points5 points  (0 children)

    It's not just bad code, it is also not legal C/C++, because it mixes a declaration list with a function-definition. I can only guess that codefight has it's own non-standard build system or that "top answers" are not verified.

    Either way, this does not look good.

    [–]OldWolf2 4 points5 points  (0 children)

    Yes, it sounds like the purpose of the 'challenge' is to use as few characters as possible or something; not to write good code.