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\$
6
  • \$\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\$ Sep 14, 2014 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, 2014 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, 2014 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\$
    – alexia
    Sep 16, 2014 at 11:41
  • \$\begingroup\$ Technically yes it is correct, but I don't think makes for a catchy title. \$\endgroup\$ Sep 16, 2014 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\$
8
  • \$\begingroup\$ Dammit, you can't let anyone else win, no ? :P \$\endgroup\$
    – Optimizer
    Sep 14, 2014 at 21:49
  • \$\begingroup\$ I don't think we'll get a better CJam answer than this \$\endgroup\$ Sep 15, 2014 at 8:30
  • 1
    \$\begingroup\$ What just happened there? \$\endgroup\$
    – War
    Sep 15, 2014 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, 2014 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, 2014 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\$
6
  • \$\begingroup\$ I was waiting for this. Well, next week... \$\endgroup\$ Sep 14, 2014 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, 2014 at 12:37
  • \$\begingroup\$ 4{ri_A/-A%}* is one byte shorter. \$\endgroup\$
    – Ingo Bürk
    Sep 14, 2014 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, 2014 at 12:42
  • 3
    \$\begingroup\$ Or 4{Ar:--A%}*. \$\endgroup\$
    – jimmy23013
    Sep 14, 2014 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\$
8
  • \$\begingroup\$ No pre defined variable with value 10 in Golfscript ? \$\endgroup\$
    – Optimizer
    Sep 14, 2014 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, 2014 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, 2014 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, 2014 at 12:51
  • 1
    \$\begingroup\$ heh, even the shortest of languages have their short comings :P \$\endgroup\$
    – Optimizer
    Sep 14, 2014 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\$
2
  • 1
    \$\begingroup\$ You can save a byte: 9i[?A%nd]dxxxx \$\endgroup\$
    – Dennis
    Sep 15, 2014 at 19:22
  • \$\begingroup\$ @Dennis - Fantastic! Now I'm neck-and-neck with golfscript and APL! \$\endgroup\$ Sep 15, 2014 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\$
8
  • \$\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\$ Sep 15, 2014 at 21:10
  • \$\begingroup\$ You could also save 2 bytes by using a*.9 instead of a-a/10 \$\endgroup\$
    – rev
    Sep 16, 2014 at 11:57
  • \$\begingroup\$ @steveverrill Like it. So focussed on putting everything in the for loop that I missed that \$\endgroup\$
    – Alchymist
    Sep 16, 2014 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, 2014 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, 2014 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\$
4
  • \$\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, 2014 at 21:24
  • \$\begingroup\$ Yup, thanks for that! \$\endgroup\$ Sep 15, 2014 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, 2014 at 20:17
  • \$\begingroup\$ I guess you're right. \$\endgroup\$ Sep 16, 2014 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\$
3
  • \$\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, 2014 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\$ Sep 15, 2014 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, 2014 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\$
2
  • \$\begingroup\$ You can search [tips] and get various tips about golfing to get you started :) \$\endgroup\$
    – Optimizer
    Sep 15, 2014 at 14:27
  • \$\begingroup\$ Cool, thanks! Checking out some tips helped me shaving off 13 bytes :) \$\endgroup\$ Sep 16, 2014 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\$
2
  • 1
    \$\begingroup\$ Could you provide an example data input/output, can't seem to get it to run on Ideone \$\endgroup\$ Sep 14, 2014 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, 2014 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\$
3
  • \$\begingroup\$ I love your 1+. \$\endgroup\$
    – Neil
    Sep 14, 2014 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, 2014 at 4:40
  • 1
    \$\begingroup\$ a-a[0] instead of 1+a[1]-a[0] should work as well. \$\endgroup\$
    – Dennis
    Sep 15, 2014 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\$
4
  • \$\begingroup\$ input() doesn't work in my Python 2 interpreter. \$\endgroup\$ Sep 14, 2014 at 11:46
  • \$\begingroup\$ @SohamChowdhury did you use commas? \$\endgroup\$
    – feersum
    Sep 14, 2014 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\$ Sep 14, 2014 at 11:48
  • 3
    \$\begingroup\$ I agree, input should be space de-limited \$\endgroup\$ Sep 14, 2014 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\$
5
  • 1
    \$\begingroup\$ This may be 14 characters, but it is 24 bytes. \$\endgroup\$
    – Ingo Bürk
    Sep 14, 2014 at 17:46
  • \$\begingroup\$ @IngoBürk codegolf.stackexchange.com/questions/2078/… \$\endgroup\$
    – TwiNight
    Sep 14, 2014 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, 2014 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, 2014 at 20:35
  • \$\begingroup\$ I could've sworn the default was UTF-8. 14 bytes it is, then. \$\endgroup\$
    – Ingo Bürk
    Sep 15, 2014 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
  • 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, 2014 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\$
5
  • \$\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, 2014 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, 2014 at 15:17
  • 1
    \$\begingroup\$ (CC @TeunPronk) \$\endgroup\$
    – Dennis
    Sep 15, 2014 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\$ Sep 16, 2014 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, 2014 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\$
7
  • \$\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\$ Sep 16, 2014 at 12:05
  • \$\begingroup\$ Good idea using $_GET but it displays 57%10 and I need (5-7)%10 \$\endgroup\$ Sep 16, 2014 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\$ Sep 16, 2014 at 14:12
  • \$\begingroup\$ Yeah the second ones works, need to do $_GET['n'] tho. Have edited my answer. \$\endgroup\$ Sep 16, 2014 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\$ Sep 16, 2014 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\$
2
  • \$\begingroup\$ Why was this downvoted? It works perfectly fine. (Btw, the eval('-'.join(x)) trick is brilliant.) \$\endgroup\$
    – flornquake
    Sep 16, 2014 at 11:53
  • \$\begingroup\$ @flornquake Thanks! \$\endgroup\$
    – DLosc
    Sep 22, 2014 at 21:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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