Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
share|improve this question
1  
Perhaps classification? – lirtosiast Jan 7 at 1:42
21  
+1 for nice keyboard art – user81655 Jan 7 at 1:55
3  
Is that a double-nested kbd? – Cᴏɴᴏʀ O'Bʀɪᴇɴ Jan 7 at 4:04
    
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... – Adám Jan 7 at 13:35
    
@NBZ Is it Blitz Basic? – wizzwizz4 Jan 7 at 18:43

16 Answers 16

up vote 6 down vote accepted

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.

share|improve this answer
4  
o.0 starts squeezing Japt – nicael Jan 7 at 21:25
    
this puts me to shame – JuanPotato Jan 7 at 23:14
    
:( I forgot about newline! @nicael you're back to being on top. – Luke Jan 7 at 23:45
    
Now we're dead even! – Luke Jan 7 at 23:49
    
You need to escape null bytes in Pyth. – lirtosiast Jan 7 at 23:49

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>

share|improve this answer
1  
> NaN XOR 2 = 2 — ??? – lirtosiast Jan 7 at 3:05
1  
@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. – user81655 Jan 7 at 3:10

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.

share|improve this answer
    
Glava = Guava + Java? – Downgoat Jan 7 at 3:32
1  
@Doᴡɴɢᴏᴀᴛ Glava = Golf + Java ( it was Conor's idea) – GamrCorps Jan 7 at 3:38
    
Indeed! @Doᴡɴɢᴏᴀᴛ – Cᴏɴᴏʀ O'Bʀɪᴇɴ Jan 7 at 4:04

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

share|improve this answer
    
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 "~`!@#$%^&*()_-=+". – Luke Jan 7 at 3:36
    
From @benstopics, this does fail for regex metacharacters – FryAmTheEggman Jan 7 at 14:53

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)

share|improve this answer
    
Nice, shortest so far! – ETHproductions Jan 7 at 15:21
    
@Eth yup, at least once I should post something short :D – nicael Jan 7 at 15:25
    
    
@Eth Heh, !1 is something that matches "false", finally I know how to do it, thanks :) – nicael Jan 7 at 15:32
    
@Eth halp, needs 5 bytes to beat Pyth. – nicael Jan 7 at 23:04

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 ¯\_(ツ)_/¯

share|improve this answer

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.

share|improve this answer
    
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.). – ChatterOne Jan 7 at 8:20
    
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. – Mark Jan 7 at 8:29
    
Oh, I see. Well, that also explains why you don't chomp the input. – ChatterOne Jan 7 at 8:39
1  
If I chomped the input, I wouldn't be able to return '3' for the return key. – Mark Jan 7 at 8:42
1  
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 :) – Dom Hastings Jan 7 at 9:51

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 \`

share|improve this answer

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.

share|improve this answer
    
Welcome to Programming Puzzles and Code Golf! Use comments to make @JuanPotato get it. However, that needs 50 rep. So you need to work. – zyabin101 Jan 7 at 14:32

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.

share|improve this answer

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.

share|improve this answer
    
just noticed it crashes with an empty input(new line/carriage return). will fix when I can – Andrew Jan 8 at 17:33

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).

share|improve this answer

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
share|improve this answer

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.

share|improve this answer

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.
share|improve this answer

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);
}
share|improve this answer
1  
I can't see this working for ~ or `? – Ash Burlaczenko Jan 7 at 9:56
    
@AshBurlaczenko, thanks! I missed that key. Fixed with no change to my score. – Hand-E-Food Jan 10 at 9:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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