22
\$\begingroup\$

Given a standard combination lock like the one in the picture. The way to unlock it is to align the 4 numbers in the code on the combination line. After years of loyal service you have been fired from the lock factory and have decided to exact revenge by not jumbling up the locks before you send them off, thus leaving every lock with the combination to unlock it on the combination line.

Combination lock

You also know that by looking at the order of the numbers in the other lines it is possible to work out what numbers must be on the combination line (and therefore the combination to unlock it is).

If every line on the lock is given a number starting from line 0 for the combination line (the line which unlocks the lock) to line 9. For example, if the numbers on line 4 are 5336, then the combination to unlock it would be 1992.

Unfortunately the locks have already been packaged and your view of each lock is obscured, so you can only see numbers on different lines of the lock.

The Challenge

Given 4 pairs of digits, where the first digit of the integer represents the line number and the second digit represents the the number which appears on that line, work out the combination to the lock. For example if you input:

57 23 99 45

Then it should output:

2101

Or

25 78 63 15

and

3174

Assume the input will always be 4 positive integers in the form `25 64 72 18.

This is , so the shortest programs in number of bytes wins.

Also this is my first question, so any feedback is appreciated.

\$\endgroup\$
  • \$\begingroup\$ I think you need to clarify the input. You say "Given 4 pairs of integers" and then give an example 57 23 99 45. That's not four pairs of integers: it's four integers. And some answers are assuming they get that as a string, whereas others are assuming that it comes ready-parsed as 4 ints. \$\endgroup\$ – Peter Taylor Sep 14 '14 at 13:04
  • \$\begingroup\$ I disagree, the fact that it said four pairs of integers made the format of the input clear, 57 is the integer pair 5 and 7, not the integer 57. My first assumption was that the line was 57 and the combination was 23. \$\endgroup\$ – Qwerty01 Sep 14 '14 at 13:45
  • 1
    \$\begingroup\$ How about "pairs of digits?" That would be much more clear and precise (and also works with leading 0s). \$\endgroup\$ – fluffy Sep 15 '14 at 2:58
  • \$\begingroup\$ Technically, the correct term would be permutation lock. Most "combination locks" are actually permutation locks, because the order of the digits makes a difference. \$\endgroup\$ – nyuszika7h Sep 16 '14 at 11:41
  • \$\begingroup\$ Technically yes it is correct, but I don't think makes for a catchy title. \$\endgroup\$ – Rory McPerlroy Sep 16 '14 at 11:50

20 Answers 20

32
\$\begingroup\$

CJam, 9 8 bytes

ea9fbAf%

Reads the digit pairs as command-line arguments. To try the code online, change ea to lS/ to read from simulated STDIN.

Example run

$ cjam <(echo ea9fbAf%) 57 23 99 45; echo
2101
$ cjam <(echo ea9fbAf%) 25 78 63 15; echo
3174

How it works

The character code of the digit d is 48 + d. Thus, considering the two-digit string xy a base 9 number yields 9 * (48 + x) + (48 + y) = 10 * (48 + x) + y - x ≡ y - x (mod 10).

ea       " Push the array of command-line arguments.                                      ";
  9fb    " Mapped base 9 conversion; replace each string 'xy' with (9 * ord(x) + ord(y)). ";
     Af% " Take the results modulo 10.                                                    ";
\$\endgroup\$
  • \$\begingroup\$ Dammit, you can't let anyone else win, no ? :P \$\endgroup\$ – Optimizer Sep 14 '14 at 21:49
  • \$\begingroup\$ I don't think we'll get a better CJam answer than this \$\endgroup\$ – Rory McPerlroy Sep 15 '14 at 8:30
  • 1
    \$\begingroup\$ What just happened there? \$\endgroup\$ – War Sep 15 '14 at 14:39
  • 1
    \$\begingroup\$ @DigitalTrauma: Sure, go ahead. The string "99" is actually interpreted as the array [57 57] by b; "xy"9b is implemented as 9 * ord(x) + ord(y). I should add that to my answer. \$\endgroup\$ – Dennis Sep 15 '14 at 17:28
  • 4
    \$\begingroup\$ 10,000 barely covers all 2-character programs if we restrict possible solutions to printable ASCII. \$\endgroup\$ – Dennis Sep 16 '14 at 13:57
13
\$\begingroup\$

CJam, 13 12 11 characters

Thanks to user23013, its now down to 11 characters :)

4{Ar:--A%}*

Explanations:

4{       }*     "Run the code block 4 times";
   r            "Read the next input token (whitespace separated)";
    :-          "Subtract 2nd number from the first treating r as a 2 numbered string";
  A   -         "Subtract the result of above from 10";
       A%       "Take modulus of 10 and store it on stack";

Try it online

I know it can be golfed more. But this is my first real attempt on CJam and I am limited by experience :)


Alternatively, the other methods to do the same thing in 1 extra character:

l~]{_A/-A%}/     // My previous solution

or

4{ri_A/-A%}*     // As pointed out by Ingo

or

ea{i_A/-A%}/     // If input is passed through command line
\$\endgroup\$
  • \$\begingroup\$ I was waiting for this. Well, next week... \$\endgroup\$ – Soham Chowdhury Sep 14 '14 at 11:40
  • \$\begingroup\$ The first three characters could alternatively be l~]. I feel like parsing the input should be possible with less than three, but I've never used CJam before :/ \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 12:37
  • \$\begingroup\$ 4{ri_A/-A%}* is one byte shorter. \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 12:39
  • 1
    \$\begingroup\$ Ah, or what you made from my earlier comment. Well now there are two 12 byte solutions! :) \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 12:42
  • 3
    \$\begingroup\$ Or 4{Ar:--A%}*. \$\endgroup\$ – jimmy23013 Sep 14 '14 at 13:37
6
\$\begingroup\$

Golfscript (14 13)

Try it online here

It's pretty much the same as Optimizer's solution, but in a different language. It's hard to approach it in a different way because the problem is fairly simple, so the tie definitely goes to Optimizer, whose entry was earlier anyway.

~]{.10:^/-^%}/

For the same number of bytes you can do

~]{.10/- 10%}/
\$\endgroup\$
  • \$\begingroup\$ No pre defined variable with value 10 in Golfscript ? \$\endgroup\$ – Optimizer Sep 14 '14 at 12:44
  • \$\begingroup\$ @Optimizer Unfortunately, no. Too bad, because having the input on the stack already would be the advantage over CJam. \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 12:47
  • \$\begingroup\$ Yeah, it can be 10 characters in CJam (with input on stack) or 11 in Golfscript (with pre defined variable) \$\endgroup\$ – Optimizer Sep 14 '14 at 12:49
  • \$\begingroup\$ I could have 12 in Golfscript as well if only I didn't have to leave the space in - 10. \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 12:51
  • 1
    \$\begingroup\$ heh, even the shortest of languages have their short comings :P \$\endgroup\$ – Optimizer Sep 14 '14 at 12:52
6
\$\begingroup\$

GNU dc, 14 bytes

Borrowing @Dennis's clever base 9 trick:

9i[?A%nd]dxxxx

Input integers read from STDIN, one per line.

Explanation:

9i                # Set input radix to 9
  [     ]         # push a macro, defined thus:
   ?              #   read number from STDIN and push
    A             #   push literal 10
     %            #   calculate number mod 10
      n           #   print, with no newline
       d          #   duplicate macro
         d        # duplicate macro
          xxxx    # execute the macro 4 times    

Output:

$ for i in 57 23 99 45; do echo $i; done | dc ./combolock.dc
2101$ 
$ for i in 25 78 63 15; do echo $i; done | dc ./combolock.dc
3174$ 
$ 

Previous Answer, 18 bytes:

Because I thought I could get closer to the "golfing" languages with this (but didn't):

[A?A~--A%n]dddxxxx
\$\endgroup\$
  • 1
    \$\begingroup\$ You can save a byte: 9i[?A%nd]dxxxx \$\endgroup\$ – Dennis Sep 15 '14 at 19:22
  • \$\begingroup\$ @Dennis - Fantastic! Now I'm neck-and-neck with golfscript and APL! \$\endgroup\$ – Digital Trauma Sep 15 '14 at 19:41
6
\$\begingroup\$

C 64 63 56 or 61

If the input can be piped from file

main(a){while(scanf("%d",&a)>0)putchar(48+(a-a/10)%10);}

If the input should be typed to stdin

i;main(a){for(;i++-4;putchar(48+(a-a/10)%10))scanf("%d",&a);}

Reads the four numbers in a loop and then processes each by subtracting the first digit from the value and printing the result modulo 10.

Savings thanks to various comments below and also using putchar instead of printf

\$\endgroup\$
  • \$\begingroup\$ Cool. You can save a comma by putting the scanf outside the for() like this a,i;main(){for(;i++-4;printf("%d",(a-a/10)%10))scanf("%d",&a);} \$\endgroup\$ – Level River St Sep 15 '14 at 21:10
  • \$\begingroup\$ You could also save 2 bytes by using a*.9 instead of a-a/10 \$\endgroup\$ – rev Sep 16 '14 at 11:57
  • \$\begingroup\$ @steveverrill Like it. So focussed on putting everything in the for loop that I missed that \$\endgroup\$ – Alchymist Sep 16 '14 at 14:52
  • 1
    \$\begingroup\$ @AcidShout Sorry - it doesn't work. For example 78 * .9 = 70.2, while 78 - 78/10 = 71. Also using .9 promotes the argument to a double so I can't take the mod. \$\endgroup\$ – Alchymist Sep 16 '14 at 14:57
  • \$\begingroup\$ You could save a few bytes by using a while loop and declaring a as an argument of main: main(a){while(scanf("%d",&a)>0)printf("%d",(a-a/10)%10);} \$\endgroup\$ – Dennis Sep 16 '14 at 15:01
5
\$\begingroup\$

Python 3 , 64

Straightforward.

print(''.join([(i-i//10)%10 for i in map(int,input().split())]))

It can be shorter if I'm allowed to print, say, [2, 1, 0, 1] instead (46):

print([i%10-i//10 for i in map(int,input().split())])
\$\endgroup\$
  • \$\begingroup\$ You can save some by taking str((i-i//10)%10) directly instead of using a second map(). I started with generators too for mine, but found that an actual for loop ended up being shorter. \$\endgroup\$ – DLosc Sep 14 '14 at 21:24
  • \$\begingroup\$ Yup, thanks for that! \$\endgroup\$ – Soham Chowdhury Sep 15 '14 at 7:29
  • \$\begingroup\$ Why are you using list-comprehensions? Use genexps to save 2 characters: print(''.join((i-i//10)%10for i in map(int,input().split()))). Also if spaces are allowd in the output you can avoid join and use tuple-unpacking: print(*((i-i//10)%10for i in map(int,input().split()))). \$\endgroup\$ – Bakuriu Sep 15 '14 at 20:17
  • \$\begingroup\$ I guess you're right. \$\endgroup\$ – Soham Chowdhury Sep 16 '14 at 6:58
4
\$\begingroup\$

C, 92

#define a(n) ,(10+v[n][1]-*v[n])%10
main(int c,char**v){printf("%d%d%d%d"a(1)a(2)a(3)a(4));}

Input from commandline. Subtracts the first ASCII code of each argument from the second, adds 10 and takes modulo 10.

I think this is the first time I've written a printf with four %s and no comma (the comma is in the #define.)

\$\endgroup\$
  • \$\begingroup\$ #define f scanf("%c%c ",&a,&b);putchar(48+(9*a+b)%10) followed by a,b;main(){f;f;f;f;} would be 18 bytes shorter. \$\endgroup\$ – Dennis Sep 15 '14 at 4:27
  • \$\begingroup\$ @Dennis that's a great improvement, but it's basically a completely different program. I think if anyone posts it, it should be you, not me. I'm not sure if the space in scanf is necessary, given that scanf is supposed to parse whitespace only as a separator. Alchymist has an even better idea in C. But it looks like you've already won it with your Cjam answer. \$\endgroup\$ – Level River St Sep 15 '14 at 10:08
  • \$\begingroup\$ Yeah, I started by noticing that the space after a(n) can be omitted, then I noticed that putting printf("%d%,...) around your macro would save a few bytes and finally I got a little carried away... -- The space is needed since %c reads a character, any character, so on the second run it would store 32 in a. -- Beating CJam with C should prove to be hard. printf() is already as long as my answer... \$\endgroup\$ – Dennis Sep 15 '14 at 13:21
4
\$\begingroup\$

Java - 203 bytes

Just because there has to be a Java entry, I saw a nice opportunity to give this code golfing a chance (first submission ever).

class M{public static void main(String[] a){String r="";for(int i=0;i<4;i++){int l=Byte.valueOf(a[i].substring(1));int f=Byte.valueOf(a[i].substring(0,1));r+=(l-f<0)?l-f+10:l-f;}System.out.print(r);}}

If there's room for some improvements, I'd glad to know about them ;-)

\$\endgroup\$
  • \$\begingroup\$ You can search [tips] and get various tips about golfing to get you started :) \$\endgroup\$ – Optimizer Sep 15 '14 at 14:27
  • \$\begingroup\$ Cool, thanks! Checking out some tips helped me shaving off 13 bytes :) \$\endgroup\$ – Sander Sep 16 '14 at 7:28
3
\$\begingroup\$

Lua - 46 characters

while''do a,b=io.read(1,1,1)print((b-a)%10)end

Reads three characters at a time (grant me the small mercy of inputing a space at the end), and eventhough a and b are string-y... b-a MAGICALUALY allows them to conceive a healthy baby integer. Does the wrap-around check while printing.

How I run it:

\$\endgroup\$
  • 1
    \$\begingroup\$ Could you provide an example data input/output, can't seem to get it to run on Ideone \$\endgroup\$ – Rory McPerlroy Sep 14 '14 at 12:09
  • \$\begingroup\$ @Harry12345 Ah, sorry about that. Anarchy Golf is setting my mind on how I implement stdinput. I could probably code it better, but meh, lua is terrible. I posted an example of me running the program. \$\endgroup\$ – AndoDaan Sep 14 '14 at 12:45
3
\$\begingroup\$

JavaScript ES6 – 53 43 bytes

f=n=>n.replace(/.. ?/g,a=>(1+a[1]-a[0])%10)

Fairly straightforward function, uses regex to get the numbers. Try it out at http://jsfiddle.net/efc93986/1/. If functions are not allowed, a standalone program at 52 bytes:

alert(prompt().replace(/.. ?/g,a=>(1+a[1]-a[0])%10))

As ES6 currently only works on Firefox, the following code works on any modern browser, at 70 bytes:

alert(prompt().replace(/.. ?/g,function(a){return(1+a[1]-a[0])%10}))
\$\endgroup\$
  • \$\begingroup\$ I love your 1+. \$\endgroup\$ – Neil Sep 14 '14 at 19:34
  • 1
    \$\begingroup\$ The question says to assume valid input, so you can use ...? instead of /\d+ ?. The space after return can be omitted. Also, since no specific I/O was specified, you should be able to use a function. \$\endgroup\$ – Dennis Sep 15 '14 at 4:40
  • 1
    \$\begingroup\$ a-a[0] instead of 1+a[1]-a[0] should work as well. \$\endgroup\$ – Dennis Sep 15 '14 at 20:34
2
\$\begingroup\$

Python 2 - 33 bytes

for i in input():print(i-i/10)%10

Accepts comma-delimited user input. E.g. Input:

29,26, 31, 88

Output:

7
4
8
0

If output is required to exactly match the example then it is much longer. 47 bytes:

print"%d"*4%tuple((i-i/10)%10 for i in input())
\$\endgroup\$
  • \$\begingroup\$ input() doesn't work in my Python 2 interpreter. \$\endgroup\$ – Soham Chowdhury Sep 14 '14 at 11:46
  • \$\begingroup\$ @SohamChowdhury did you use commas? \$\endgroup\$ – feersum Sep 14 '14 at 11:47
  • 2
    \$\begingroup\$ Oh, no, I didn't. It works now. On a side note, I think you need to take space-delimited input per the spec. \$\endgroup\$ – Soham Chowdhury Sep 14 '14 at 11:48
  • 3
    \$\begingroup\$ I agree, input should be space de-limited \$\endgroup\$ – Rory McPerlroy Sep 14 '14 at 12:35
2
\$\begingroup\$

APL, 14

10|{--/⍎¨⍕⍵}¨⎕

Explaination
takes input from screen. Space-separated values are parsed as an array.
{...}¨ for each number, feed it into function.
⍎¨⍕⍵ takes the argument, create an array of its digits.
--/ calculates units minus tens.
10| mod 10.

\$\endgroup\$
  • 1
    \$\begingroup\$ This may be 14 characters, but it is 24 bytes. \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 17:46
  • \$\begingroup\$ @IngoBürk codegolf.stackexchange.com/questions/2078/… \$\endgroup\$ – TwiNight Sep 14 '14 at 20:03
  • \$\begingroup\$ but for code golf we count in UTF-8, not some special charset. That'd just be a loophole and could be abused very easily. \$\endgroup\$ – Ingo Bürk Sep 14 '14 at 20:18
  • 1
    \$\begingroup\$ @IngoBürk As per meta.codegolf.stackexchange.com/a/961/6972 answers can be encoded in any encoding unless the OP states otherwise. There is indeed an IBM codepage for APL characters which is a single-byte mapping, which is exactly what Dyalog used to use before Unicode 3.0. If you insist on Unicode, what if I invent a new language that uses non-Unicode characters? How would you count bytes for that? \$\endgroup\$ – TwiNight Sep 14 '14 at 20:35
  • \$\begingroup\$ I could've sworn the default was UTF-8. 14 bytes it is, then. \$\endgroup\$ – Ingo Bürk Sep 15 '14 at 3:52
2
\$\begingroup\$

J - 20 15

The non-verb form (as statement instead of function definition) it's 5 characters shorter:

10|-~/|:10#.inv

The verb form which is a nice train:

10|[:-~/[:|:10#.inv]

This verb used on the example inputs:

   10|-~/|:10#.inv 57 23 99 45
2 1 0 1
   10|-~/|:10#.inv 25 78 63 15
3 1 7 4

rotd =: 10|[:-~/[:|:10#.inv] NB. verb form

   rotd 25 78 63 15
3 1 7 4
   rotd 57 23 99 45
2 1 0 1
\$\endgroup\$
2
\$\begingroup\$

Haskell 60 58

main=interact$show.map((\x->mod(x-x`div`10)10).read).words

Single character digits, a real nemesis in Haskell golfing.

\$\endgroup\$
2
\$\begingroup\$

Perl: 38 40

print abs($_-int$_/10)%10for split" ",<>

Output:

% perl code.pl
57 23 99 45
2101

25 78 63 15                                     
3174
\$\endgroup\$
  • 1
    \$\begingroup\$ 1. Underscores are markdown syntax, so your code got a little messed up. To prevent this, indent code with four spaces. 2. abs isn't necessary; x - x/10 cannot be negative. 3. If you use the flags -040pe (usually counted as 5 bytes) to iterate over space-delimited input, you can shorten your code to $_=($_-int$_/10)%10. 4. If you prefer to avoid command-line flags, you can still save a few bytes by setting $/=$; and removing the call to split. \$\endgroup\$ – Dennis Sep 17 '14 at 3:24
1
\$\begingroup\$

Ruby, 35 bytes

$*.map{|n|a,b=n.bytes;$><<(b-a)%10}

Explanation

Input is taken as command line arguments. String#bytes returns an Array of Integers (ASCII character codes). Only the difference between the last and first character code is of importance, not the Integers themselves.

\$\endgroup\$
1
\$\begingroup\$

C# & LinqPad: 104

Util.ReadLine<string>("").Split(' ').Select(s =>(s[1]-s[0])).Aggregate("",(r,a)=>r+(a<0?10+a:a)).Dump();
\$\endgroup\$
1
\$\begingroup\$

C++ 118

int main()
{
int a,b,c;
for(int i=0; i<4; i++)
{
cin>>a;
b=a/10;
a=a%10;
c=a-b;
if(c<0)c+=10;
cout<<c;
}
}
\$\endgroup\$
  • \$\begingroup\$ 1. Not sure about other compilers, but GCC requires #include<iostream> and std:: before cin and cout. 2. You don't need the conditional if you omit a=a%10. 3. You don't need the variables b and c, the linefeeds and (with a few modification) the brackets around the for loop. \$\endgroup\$ – Dennis Sep 15 '14 at 15:15
  • 1
    \$\begingroup\$ @SeanD: Please don't approve edits that modify code. In this particular case, the edit made the answer invalid. It also removed the first line, which should be present in all answers. \$\endgroup\$ – Dennis Sep 15 '14 at 15:17
  • 1
    \$\begingroup\$ (CC @TeunPronk) \$\endgroup\$ – Dennis Sep 15 '14 at 15:17
  • \$\begingroup\$ @Dennis usually answers on this site don't include preprocessor lines. I omitted the lines #include<iostream>and using namespace std; \$\endgroup\$ – bacchusbeale Sep 16 '14 at 5:55
  • \$\begingroup\$ I know there not usually included in the byte count, but I think they should be present in the answer. \$\endgroup\$ – Dennis Sep 16 '14 at 13:22
1
\$\begingroup\$

PHP - 90 characters

Thought I'd give code golf a try so here it is, my first attempt - can probably be golfed more.

<?php $a=array(57,23,99,45);foreach($a as$b){echo abs(substr($b,0,1)-substr($b,1,1)%10);}

58 characters (courtesy of Ismael Miguel)

for($i=0,$a=$_GET[n];$i<8;)echo abs($a[$i++]-$a[$i++]);

Access file using

file.php?n=57239945
\$\endgroup\$
  • \$\begingroup\$ Try this code: <? for($i=0;$i<4;)echo abs($_GET[n][$i]%10); which is 44 chars long. Access from a browser using file.php?n[]=xx&n[]=yy&n[]=xy&n[]=yx. (untested code) \$\endgroup\$ – Ismael Miguel Sep 16 '14 at 12:05
  • \$\begingroup\$ Good idea using $_GET but it displays 57%10 and I need (5-7)%10 \$\endgroup\$ – Rory McPerlroy Sep 16 '14 at 13:34
  • \$\begingroup\$ Try this one: <? for($i=0,$a=$_GET[n];$i<4;++$i)echo abs($a[$i][0]-$a[$i++][1]%10);. Sadly, it's 65 bytes long. (forgot the $i increment on the last one) Or you could try <? for($i=0;$i<8;)echo abs($_GET[n][$i++]-$_GET[n][$i++]%10); and access the browser using file.php?n[]=x&n[]=y&n[]=x&n[]=y&n[]=x&n[]=y&n[]=x&n[]=y, being 61 bytes long. \$\endgroup\$ – Ismael Miguel Sep 16 '14 at 14:12
  • \$\begingroup\$ Yeah the second ones works, need to do $_GET['n'] tho. Have edited my answer. \$\endgroup\$ – Rory McPerlroy Sep 16 '14 at 14:27
  • \$\begingroup\$ Well, it isn't required. It simply issues a warning. That is fine for this website. But try this one: <? for($i=0,$a=$_GET[n];$i<8;)echo abs($a[$i++]-$a[$i++]);. The %10 is useless and this one simply looks better. Also, you can access it using file.php?n[]=xyxyxyxy. This solution is 58 bytes long. \$\endgroup\$ – Ismael Miguel Sep 16 '14 at 14:30
0
\$\begingroup\$

Python 3, 60

for x in input().split():print(-eval('-'.join(x))%10,end='')

Input and output exactly as specified, although it doesn't print a trailing newline. Two interesting tricks here: 1) replacing two calls to int() with one call to eval(), and 2) using join() to get a-b, then negating it for b-a as required. Fortunately Python's modulo operator gives positive values even if the first argument is negative!

\$\endgroup\$
  • \$\begingroup\$ Why was this downvoted? It works perfectly fine. (Btw, the eval('-'.join(x)) trick is brilliant.) \$\endgroup\$ – flornquake Sep 16 '14 at 11:53
  • \$\begingroup\$ @flornquake Thanks! \$\endgroup\$ – DLosc Sep 22 '14 at 21:34

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.