39
\$\begingroup\$

Given any of the following characters (or a newline):

`1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?

Your program must output the row that it is on the keyboard


Because my keyboard is (almost) out of battery, your code must be as short as possible


The keyboard your program should use (for the row lookup), should look like:


Row 1:~` !1@2 #3$4 %5^6 &7*8 (9)0 _-+=                          

Row 2:                         Q W E R T Y U I O P {[ }]    |\   
Row 3:                              A S D F G H J K L :; "' return  
Row 4:                                 Z X C V B N M <, >. ?/                 
Row 5:                                                    space                                                   

Where   return is a newline. Empty keys don't mean anything.

Examples

"$"
1

"R"
2

"a"
3

"?"
4

"\n"
3

" "
5

where \n is a newline character.

Specifications

  • Your program should be case insensitive
  • Your program only needs to handle the characters on the keyboard shown
\$\endgroup\$
14
  • 3
    \$\begingroup\$ Perhaps classification? \$\endgroup\$
    – lirtosiast
    Jan 7, 2016 at 1:42
  • 3
    \$\begingroup\$ Is that a double-nested kbd? \$\endgroup\$ Jan 7, 2016 at 4:04
  • \$\begingroup\$ I remember years ago using some language that returned keypresses as as 100×row+position... Would have been perfect for this, but unfortunately I don't remember what it was. Maybe some form of BASIC... \$\endgroup\$
    – Adám
    Jan 7, 2016 at 13:35
  • \$\begingroup\$ @NBZ Is it Blitz Basic? \$\endgroup\$
    – wizzwizz4
    Jan 7, 2016 at 18:43
  • 1
    \$\begingroup\$ @wizzwizz4 Have you tried BlitzPlus? it's free and looks like it's what you want. \$\endgroup\$ Jan 25, 2016 at 22:42

21 Answers 21

12
\$\begingroup\$

JavaScript (ES6), 105 102 101 bytes

c=>/[~`0-9!@#-&^(-+_=-]/.test(c)+/[asdfghjkl;:'"\n]/i.test(c)*3+/[zxcvbnm,<.>/?]/i.test(c)*4||++c*7^2

Explanation

In JavaScript test returns a boolean which acts the same as 1 or 0 so I multiply them by their row. Testing for row 2 took the most bytes so I used that one as the default if no others matched.

c=>
  /[~`0-9!@#-&^(-+_=-]/.test(c)   // row 1 regex
  +/[asdfghjkl;:'"\n]/i.test(c)*3 // row 3 regex
  +/[zxcvbnm,<.>/?]/i.test(c)*4   // row 4 regex
  ||++c                           // space ++ = 1, any character on row 2 ++ = NaN
    *7^2                          // 7 XOR 2 = 5, NaN XOR 2 = 2

Test

var solution = c=>/[~`0-9!@#-&^(-+_=-]/.test(c)+/[asdfghjkl;:'"\n]/i.test(c)*3+/[zxcvbnm,<.>/?]/i.test(c)*4||++c*7^2
<textarea id="input">-</textarea><br />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

\$\endgroup\$
2
  • 1
    \$\begingroup\$ > NaN XOR 2 = 2 — ??? \$\endgroup\$
    – lirtosiast
    Jan 7, 2016 at 3:05
  • 1
    \$\begingroup\$ @ThomasKwa That's just how JS works lol. If c="q", ++c = NaN, NaN*7 = NaN, NaN^2 converts the operands to integers (uncastables like NaN become 0) then does 0 XOR 2 which is 2. \$\endgroup\$
    – user81655
    Jan 7, 2016 at 3:10
6
\$\begingroup\$

Pyth, 62 66 65 bytes

?zh@+,4Zmid2c.Bi."0fÀÓ¸[9Ѷ¤KïLäHÉðbÀ`]ü©¬vS"16 2-CzCd3

Try it online.

Uses a packed string representing a number in hex which, when chopped into two-bit chunks, represents the row of every character except and ! as a value from 0 to 3. We leave out and ! so we don't have to store 4 or have a 0 at the start of this number, then add their row values using +,4Z. Once we've turned the string into row values, all we have to do is use the character code of the input to index into the array of values, and then add 1.

Newline is handled separately because it's interpreted by Pyth as an empty string and so has a character code of 0.

This would be shorter if I could figure out how to use base 256 in Pyth, but I can't quite make it work.

\$\endgroup\$
7
  • 4
    \$\begingroup\$ o.0 starts squeezing Japt \$\endgroup\$
    – nicael
    Jan 7, 2016 at 21:25
  • \$\begingroup\$ this puts me to shame \$\endgroup\$
    – Hasan
    Jan 7, 2016 at 23:14
  • \$\begingroup\$ :( I forgot about newline! @nicael you're back to being on top. \$\endgroup\$
    – Luke
    Jan 7, 2016 at 23:45
  • \$\begingroup\$ Now we're dead even! \$\endgroup\$
    – Luke
    Jan 7, 2016 at 23:49
  • \$\begingroup\$ You need to escape null bytes in Pyth. \$\endgroup\$
    – lirtosiast
    Jan 7, 2016 at 23:49
5
\$\begingroup\$

Glava 1.5, 164 bytes

Glava is a dialect of Java that makes Java code shorter. This code is unfortunately non-competitive as the commit (2 hours late...) used was made after this challenge, which fixed some vital bugs that would not allow this program to work.

p(A[0].matches("[`0-9-=~!@#$%^&*()_+]")?1:A[0].replace("\\n","\n").matches("(?i)[asdfghjkl;':\"\n]")?3:A[0].matches("(?i)[zxcvbnm,.\\/<>?]")?4:A[0].matches(" ")?5:2

This is a full program that takes input via command-line arguments. Works by simply testing for which row regex it matches, then outputs the corresponding number.

\$\endgroup\$
3
  • \$\begingroup\$ Glava = Guava + Java? \$\endgroup\$
    – Downgoat
    Jan 7, 2016 at 3:32
  • 2
    \$\begingroup\$ @Doᴡɴɢᴏᴀᴛ Glava = Golf + Java ( it was Conor's idea) \$\endgroup\$
    – GamrCorps
    Jan 7, 2016 at 3:38
  • \$\begingroup\$ Indeed! @Doᴡɴɢᴏᴀᴛ \$\endgroup\$ Jan 7, 2016 at 4:04
4
\$\begingroup\$

Python 3, 142

print(int(("~`!1@2#3$4%5^6&7*8(9)0_-+=""qwertyuiop{[}\|"+"]"*11+'asdfghjkl;:"\n'"'"*13+"zxcvbnm,<.>/""?"*14+" ").index(input().lower())/26)+1)

There is probably a shorter way that I am overlooking ¯\_(ツ)_/¯

\$\endgroup\$
4
\$\begingroup\$

Pyth, 98

|+++l:"~`0123456789!@#$%^&*()_-=+"z1*l:"asdfghjkl;:'\"\n"rz0 1 3*l:"zxcvbnm,<.>/? "rz0 1 4 l:dz1 2

not sure how to get the 0-9 range working for some reason :|, inspired by user81655's answer

\$\endgroup\$
2
  • \$\begingroup\$ You can use jkUT for the string with the range 0 to 9, not sure if there's a shorter way. You can also used packed strings to save a few bytes, e.g. ."!~WÏù¹_(<]úÝ" for "~`!@#$%^&*()_-=+". \$\endgroup\$
    – Luke
    Jan 7, 2016 at 3:36
  • \$\begingroup\$ From @benstopics, this does fail for regex metacharacters \$\endgroup\$ Jan 7, 2016 at 14:53
4
\$\begingroup\$

Bash, 108

No Bash answer? Bash answer. grep -Fin is definitely the right tool for this job.

This program is in two files.

k, 73 bytes

`1234567890-=~!@#$%^&*()_+
qwertyuiop[]\{}|
asdfghjkl;':"
zxcvbnm,./<>?

There are 5 lines, the last one is a space. If you have trouble reproducing the file, the base64 is:

YDEyMzQ1Njc4OTAtPX4hQCMkJV4mKigpXysKcXdlcnR5dWlvcFtdXHt9fAphc2RmZ2hqa2w7JzoiCnp4Y3Zibm0sLi88Pj8KIA==

b, 34 bytes

This is the program itself, it takes input as the only command line argument.

grep -Fin "$1" k|tail -n3|head -c1

Score: 34 + 73 + 1 (for k's filename) = 108 bytes

Ungolfed

grep --fixed-strings --ignore-case --line-number "$1" k|tail --lines=3|head --bytes=1

Explanation

  • grep - search a file for lines matching a string or regular expression, output only those lines
  • -F aka --fixed-strings - disable regular expressions so [ etc. are handled correctly
  • -i aka -y aka --ignore-case - case-insensitive matching
  • -n aka --line-number - show the line number and : before every line (e.g. 4:zxcvbnm,./<>?)
  • "$1" - search for the script's first command-line argument, the quotes are necessary to handle newline and space
  • k - search in file k
  • This grep command will match all five lines if the input is a newline, and only one line otherwise.
  • | - pipe, send standard output of one command to standard input of the next
  • tail - output the last N lines or characters of standard input
  • -n3 aka --lines=3 - output the last 3 lines
  • If the input wasn't a newline, there is only one line to process, which starts with the row number because of the -n flag on grep. Otherwise, this command takes only lines 3, 4 and 5 (the last 3 lines).
  • | - pipe
  • head - output the first N lines or characters of standard input
  • -c1 aka --bytes=1 - output the first character
  • If the input wasn't a newline, this takes the first character, which is the line number where the input is found. If the input is a newline, it takes the first character of lines 3, 4 and 5 combined, which is 3, which happens to be the correct row number for newline.
\$\endgroup\$
0
4
\$\begingroup\$

Japt, 73 70 66 bytes

2+`qØÆyuiop\{}[]|\\1dfghjkl;:
'1zxcvbnm,.<>?/\"1 `q1 ®bUv)<0} b!1

Try it online! (in the example, the input is literally a newline)

\$\endgroup\$
13
  • \$\begingroup\$ Nice, shortest so far! \$\endgroup\$ Jan 7, 2016 at 15:21
  • \$\begingroup\$ @Eth yup, at least once I should post something short :D \$\endgroup\$
    – nicael
    Jan 7, 2016 at 15:25
  • \$\begingroup\$ A couple bytes shorter \$\endgroup\$ Jan 7, 2016 at 15:29
  • \$\begingroup\$ @Eth Heh, !1 is something that matches "false", finally I know how to do it, thanks :) \$\endgroup\$
    – nicael
    Jan 7, 2016 at 15:32
  • \$\begingroup\$ @Eth halp, needs 5 bytes to beat Pyth. \$\endgroup\$
    – nicael
    Jan 7, 2016 at 23:04
4
\$\begingroup\$

Java, 300 bytes

import java.util.Scanner;public class A{public static void main(String[] args){String g="~`!1@2#3$4%5^6&7*8(9)0_-+=qQwWeErRtTyYuUiIoOpP[{]}\\|aAsSdDfFgGhHjJkKlL;:\'\"\r";Scanner i=new Scanner(System.in);int f=g.indexOf((i.nextLine().charAt(0)));System.out.print(f<0?4:(f<26?1:(f<53?2:(f<76?3:5))));}}

I'm not an expert, and this is my first attempt at golfing, but I figured, what the hell, why not? Above is the full program version, the actual code that goes into it would most likely take a decent amount of characters off.

\$\endgroup\$
4
  • \$\begingroup\$ just noticed it crashes with an empty input(new line/carriage return). will fix when I can \$\endgroup\$
    – Andrew
    Jan 8, 2016 at 17:33
  • \$\begingroup\$ Welcome to the community! \$\endgroup\$ Sep 28, 2016 at 18:25
  • \$\begingroup\$ Welcome (bit late since you posted in January xD). You can golf it quite a bit without changing your current approach like this: class A{public static void main(String[]a){int f="~'!1@2#3$4%5^6&7*8(9)0_-+=qQwWeErRtTyYuUiIoOpP[{]}\\|aAsSdDfFgGhHjJkKlL;:\'\"\r".indexOf(new java.util.Scanner(System.in).nextLine().charAt(0));System.out.print(f<0?4:f<26?1:f<53?2:f<76?3:5);}} (243 bytes) I removed some unnecessary parenthesis; shortened args; removed public ; directly used the String and Scanner; and removed the import now that java.util.Scanner is used once. \$\endgroup\$ Oct 25, 2016 at 9:26
  • \$\begingroup\$ 219 bytes you don't need to use Scanner for this \$\endgroup\$ Nov 26, 2017 at 17:33
3
\$\begingroup\$

Pyth, 105 bytes

J?<l-c".^$*+?{}[]\|()"1]z14+\\zrz0?qJd5?:"qwertyuiop[]\|"J)2?:"asdfghjkl;':\"\n"J)3?:"zxcvbnm,./<>?"J)4 1

Explanation:

J?<l-c".^$*+?{}[]\|()"1]z14+\\zrz0     # Escape input if regex metachar
?qJd5                                  # Check space
?:"qwertyuiop[]\|"J)2                  # Check second row
?:"asdfghjkl;':\"\n"J)3                # Check third row
?:"zxcvbnm,./<>?"J)4                   # Check fourth row
1                                      # If none of these, must be on first row.

I decided to choose the first row as the "must be if nothing else" row because it required the most bytes to represent even after golfing.

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Programming Puzzles and Code Golf! Use comments to make @JuanPotato get it. However, that needs 50 rep. So you need to work. \$\endgroup\$
    – user48538
    Jan 7, 2016 at 14:32
3
\$\begingroup\$

Perl 6, 128 bytes

say 1+(/<[-\d=~!@#$%^&*()_+/`]>/,/<[qwertyuiop[\]\\{}|]>/,/<[asdfghjkl;':"\n]>/,/<[zxcvbnm,./<>?]>/,' ').first: @*ARGS.lc~~*,:k

I make a list of regexes containing character classes along with a string literal space. I then call the first method on the list (which is just the method version of the first higher order function), using smartmatch to compare the argument passed to the program against the current item in the list. Note that smartmatch does "the right thing" for both regexes and a string literal. The :k optional parameter to first causes the method to return the index of the matching item in the list, which I then add 1 to and output via say.

Note that when using this program you will have to properly escape certain characters like ` and space in your shell. For instance: perl6 keyboard.p6 \`

\$\endgroup\$
1
  • \$\begingroup\$ Since nobody said it yet, welcome to Programming Puzzles & Code Golf! \$\endgroup\$ Sep 28, 2016 at 18:24
3
\$\begingroup\$

Python 3, 89 bytes

print("qwertyuiop{}[]\\|asdfghjkl;:\"\n'''zxcvbnm,.<>/???? ".find(input().lower())//16+2)

As I can't comment yet, I'm posting the improvement for the current Python 3 answer separately.

Edit: All code in print now and further tweaked.

\$\endgroup\$
4
  • \$\begingroup\$ This is merely a snippet and therefore not a valid answer, you need to wrap it in a print statement (making it a full program) or turn it into a function. \$\endgroup\$
    – FlipTack
    Nov 26, 2017 at 16:42
  • \$\begingroup\$ @FlipTack: You're right. I've incorporated your suggestion. \$\endgroup\$ Nov 26, 2017 at 16:51
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Nov 26, 2017 at 17:01
  • \$\begingroup\$ @MartinEnder: Thank you! :-) \$\endgroup\$ Nov 26, 2017 at 17:30
2
\$\begingroup\$

JavaScript ES6, 114 bytes

n=>[`qwertyuiop{}[]|\\`,`asdfghjkl;:
'`,`zxcvbnm,.<>?/"`,` `].map(x=>+(x.indexOf(n.toLowerCase())<0)).indexOf(0)+2

Another JavaScript solution. The principle is to return the index of the input char in the array of rows plus 2 (so as the 0-9 row returns -1, i.e. not exists, -1+2=1. q is in the first string of the array, so it returns 0+2=2nd row).

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

Perl, 96 77 76 bytes

Run using perl -p. Make sure you're feeding it just single characters; for example, to run it from a file key.pl (to avoid mucking around with shell escape sequences) echo -n q|perl -p key.pl.

$_=/[\d~`!@#-&(-+_=-]/+/[adfghjkls"':;
]/i*3+/[bcnmvxz<>,.?\/]/i*4+/ /*5||2

Abusing the regex range functionality is fun.

\$\endgroup\$
8
  • \$\begingroup\$ To me this doesn't work, running it I get the index of the row + 3 (i.e. 3 instead of 0, 7 instead of 4, etc.). \$\endgroup\$
    – ChatterOne
    Jan 7, 2016 at 8:20
  • \$\begingroup\$ It's sensitive to how you provide the input. You're probably providing a character followed by a newline. I use echo to precisely control the input -- eg. echo -n q|perl -n key.pl, which correctly produces 2. \$\endgroup\$
    – Mark
    Jan 7, 2016 at 8:29
  • \$\begingroup\$ Oh, I see. Well, that also explains why you don't chomp the input. \$\endgroup\$
    – ChatterOne
    Jan 7, 2016 at 8:39
  • 1
    \$\begingroup\$ If I chomped the input, I wouldn't be able to return '3' for the return key. \$\endgroup\$
    – Mark
    Jan 7, 2016 at 8:42
  • 1
    \$\begingroup\$ Hey @Mark, you don't need the $_=~ for the matches, m// (which is what /.../ is) works on $_ automatically! Also if you use -p instead of -n you can use $_= instead of print to save a couple more bytes. Using a literal newline instead of \n can save you another byte too! That should reduce your code quite a bit! Might be worth adding an example usage as well so anyone testing knows you need to use echo -n :) \$\endgroup\$ Jan 7, 2016 at 9:51
2
\$\begingroup\$

PHP, 173 bytes

The idea here was to use the regex capturing group number as the row index. Probably some more optimizations in the regex itself.

$i=$argv[1];preg_match("%([!#-&\(-+-0-9=@^-`~])|([EIO-RT-UWY[-]eio-rt-uwy{-}])|([\"':-;ADF-HJ-LSadf-hj-ls])|([,.-/<>-?B-CM-NVXZb-cm-nvxz])%",$i,$m);echo array_flip($m)[$i];

The preg_match() call will create an array $m of matches, and if we were to print that, it'd look something like this (assuming z was the input):

Array ( [0] => 'z', [1] => '', [2] => '', [3] => '', [4] => 'z' )

Flipping that array, by swapping keys and values, moves left to right and only keeps the last distinct key, so we end up with:

Array ( 'z' => 4, '' => 3 )

Then we use the input character as the index in the array to get our result.

Try it out here.

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

C, 145 143 136 132 127 106 104 bytes

#define c"\x7ea6a6f8\x5777595"
f(a){return a-32?L"\x200000\0\xf3008020\xf2a00000"c c[a>>4]>>a%16*2&3:4;}

Try it online!

This uses index() from POSIX.1-2001 and is deprecated in POSIX.1-2008. This assumes ASCII and 32 bit ints.

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

Ruby, 82 bytes

->i{1+((0>r=i.ord-33)?r%5:"bc7xdutvz4ind3bwqf6mcu5vxiahnmlfs93c".to_i(36)>>2*r&3)}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

CJam, 125 bytes

q_" "={;5}{"`1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"    zxcvbnm,./ZXCVBNM<>?    "\#26/1+}?

Explanation

q                          e# read input
 _" "=                     e# decide if the input is a space
      {;5}                 e# if it is, push 5
          {"..."\#26/1+}?  e# if it isn't, push the correct row
\$\endgroup\$
0
\$\begingroup\$

SpecBAS - 178 bytes

1 a$="~`!1@2#3$4%5^6&7*8(9)0-_+=qQwWeErRtTyYuUiIoOpP{[}]|\aaaaAsSdDfFgGhHjJkKlL:;'"#34#13"zzzzzzzZxXcCvVbBnNmM<,>.?/"+" "*26
2 INPUT k$: IF k$="" THEN k$=#13
3  ?CEIL(POS(k$,a$)/26)

I used a long string where each row is 26 characters long (#34 is code for double quote and #13 is code for return).

Then print the result of rounding position/26.

\$\endgroup\$
0
\$\begingroup\$

C#6, 201 bytes

Nothing special here. I found it cheaper to just write both cases rather than use ToUpper() due to the string's fixed width.

using C=System.Console;class P{static void Main(string[]a)=>C.Write("`1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'\raASDFGHJKL:\"\nazxcvbnm,./zzzZXCVBNM<>?zzz ".IndexOf(a[0])/26+1);}

Indented:

using C=System.Console;
class P{
    static void Main(string[]a)=>
        C.Write("`1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'\raASDFGHJKL:\"\nazxcvbnm,./zzzZXCVBNM<>?zzz ".IndexOf(a[0])/26+1);
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I can't see this working for ~ or `? \$\endgroup\$ Jan 7, 2016 at 9:56
  • \$\begingroup\$ @AshBurlaczenko, thanks! I missed that key. Fixed with no change to my score. \$\endgroup\$ Jan 10, 2016 at 9:59
0
\$\begingroup\$

Python 2, 146 bytes

e="\n";lambda x:("`1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\""+e*4+"zxcvbnm,./ZXCVBNM<>?"+e*13+" ").index(x)/26+1
\$\endgroup\$
0
\$\begingroup\$

Excel, 132 bytes

=INT((FIND(A1,"`1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:""aaa zxcvbnm,./ZXCVBNM<>?zzzzzz ")-1)/26)+1

Attempts to use the case in-sensitive SEARCH() instead of FIND() revealed that Excel matches ~, * and ? to (tick). The matching of?means we can't useSEARCH()`, which would have shaved a massive 5 bytes...

\$\endgroup\$

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.