Keyboard Ping Pong
(This question was inspired by this post.)
Challenge
Given a string of letters, determine if the word "ping-pongs" across the keyboard. (Letters alternating between sides of the keyboard)
Use any established Latin-script keyboard layout that you would like (QWERTY, AZERTY, etc.) but please specify your choice in your answer.
Here is a graphic of the ping pong sides with QWERTY layout. The left hand side consists of the leftmost 5 letters, with the right hand side consisting of the remaining letters.
Test Cases (QWERTY)
skepticism - true
ENDOWMENT - true
quantity - true
dispel - true
kayaks - true
a - true
aa - false
test - false
WRONG - false
thiswillfail - false
ε - false
Comments:
- Strings of length
1should return true. Represents an ace! - Strings of length
0should return false. A point would not be scored in a real ping pong game. - Should be case-insensitive
This question is tagged code-golf, so the shortest answer in bytes wins!
12 Answers 12
Python, (削除) 69 (削除ここまで) (削除) 62 (削除ここまで) (削除) 60 (削除ここまで) (削除) 58 (削除ここまで) (削除) 55 (削除ここまで) 54 bytes
-7 bytes thanks to @xnor. I independently arrived at a similar solution (only the first -4 though) since I didn't notice their comment for a while.
-1 byte thanks to @Albert.Lang
Takes input as a bytestring
lambda x,n=35782400:len({(n:=~n)>>j%32&1for j in x})%2
-
1
-
1
-
1\$\begingroup\$ -1:
lambda x,n=35782400:len({(n:=~n)>>j%32&1for j in x})%2\$\endgroup\$Albert.Lang– Albert.Lang2024年07月10日 05:28:23 +00:00Commented Jul 10, 2024 at 5:28 -
-
sed -r, 30 bytes
/[^h-puy]{2}|[h-puy]{2}|^$/IQ1
nearly a port of @Xcali's answer. I originally had my own but my regex was worse. errors with exit code of 1 if it's invalid, exits normally if it's ping pong
I just saw that we can use any keyboard we want, so here's my keyboard, colemak:
sed, 30 bytes
/[^eh-uy]{2}|[eh-uy]{2}|^$/IQ1
here's dvorak, the most popular alternate layout:
sed, 42 bytes
/[aeijkopquxy]{2}|[^aeijkopquxy]{2}|^$/IQ1
and here's workman, the third choice for weird people:
sed, 40 bytes
/[^efi-lnopuy]{2}|[efi-lnopuy]{2}|^$/IQ1
-
\$\begingroup\$ (if you were wondering, I did go through the rest of the keyboards on that wiki page, but none were as short as qwerty and colemak.) \$\endgroup\$guest4308– guest43082024年07月08日 17:18:28 +00:00Commented Jul 8, 2024 at 17:18
Charcoal, 23 bytes
∧θNo...01⊕Lθ⭆θNo+⪫...h¦qωuy↧ι
Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - if the word is ping-pong, nothing if not. Explanation:
θ Input word
∧ Logical And
No Count of
θ Input word
⭆ Map over characters and join
No Count of
ι Current letter
↧ Lowercased
...h q In range `h`...`q` (exclusive)
⪫ ω Joined
+ Concatenated with
uy Literal string `uy`
01 In literal string `01`
... Cyclically extended to length
θ Input word
L Length
⊕ Incremented
Implicitly print
JavaScript (ES6), 51 bytes
Expects an array of characters. Returns 0 for "ping-pong" or 1 for "empty or not ping-pong".
a=>a<1|a.some(q=c=>q-(q=/[h-puy]/i.test(c)^(a^=1)))
JavaScript (ES6), 39 bytes
@Xcali used a much more straightforward solution which can be ported as follows. Expects a string and returns a Boolean value (false for "ping-pong").
s=>/^$|[h-puy]{2}|[^h-puy]{2}/i.test(s)
Python 3.8 (pre-release), (削除) 89 (削除ここまで) (削除) 83 (削除ここまで) 76 bytes
-6 bytes by walrusing 'yuiophjklnm'.
-7 bytes by Mukundan314.
lambda x:x and all((i in(r:='yuiophjklnm'))^(j in r)for i,j in zip(x,x[1:]))
-
\$\begingroup\$ -7 bytes \$\endgroup\$Mukundan314– Mukundan3142024年07月08日 16:33:59 +00:00Commented Jul 8, 2024 at 16:33
Google Sheets, 76 bytes
=SORT(AND(1=LEN(IFERROR(SPLIT(REGEXREPLACE(A2,"(?i)[h-puy]"," 0ドル ")," ")))))
Google Sheets, 47 bytes
Using @Xcali's idea
=REGEXMATCH(A2,"(?i)[h-puy]{2}|[^h-puy]{2}|^$")
05AB1E, (削除) 20 (削除ここまで) 19 bytes
žV5δôøJIlδå€üαßIgΘM
Input as a list of characters.
Uses the QWERTY keyboard.
Try it online or verify all test cases.
Explanation:
žV # Push ["qwertyuiop","asdfghjkl","zxcvbnm"]
δ # Map over each string:
5 ô # Split it into parts of size 5
ø # Zip/transpose; swapping rows/columns
J # Join the inner lists together:
# ["qwertasdfgzxcvb","yuiophjklnm"]
I # Push the input-list
l # Lowercase each inner character
δ # Double-vectorized over the two lists:
å # Contains-check
€ # Map over each inner list:
ü # For each overlapping pair in this list:
α # Take the absolute difference of the pair
ß # Pop and push the flattened minimum
# (1 if all are truthy; 0 if any are falsey; "" if empty)
Ig # Push the length of the input-list
Θ # Check whether this length is exactly 1
M # Push a copy of the largest value of the stack
# (which is output implicitly as result)
Haskell, (削除) 70 (削除ここまで) 66 bytes
- -4 bytes thanks to xnor
h=(`elem`"yuiophjklnm").toLower
f(x:y:z)=h x/=h y&&f(y:z)
f x=x>[]
- First we map each letter to a boolean based on the hand (the helper function)
- Then we assert the sequence is alternate
- The base cases of 0 and 1 elements are handled by the last line
-
1\$\begingroup\$ Nice answer! It looks like you can save a few bytes by applying the helper function directly to the elements, and writing
x>[]in the base case: Try it online! \$\endgroup\$xnor– xnor2024年07月11日 04:22:07 +00:00Commented Jul 11, 2024 at 4:22
Vyxal, 121 bitsv2 , 15.125 bytes
[⇩ƛk•5vẇ∑vFT;f ̄AI
Bitstring:
0110100000110010000101110000101100010110000010110110100110101011010101011111000101101010010111000001110111100000010110110
Outputs a space for true, an empty string for false. The footer in the link converts the result to 0 or 1 for convenience. Uses the qwerty layout.
Explained
[⇩ƛk•5vẇ∑vFT;f ̄AI
[ # Only execute the following if the input isn't the empty string.
# Why else do you think false is represented as the empty string? :p
# It was easier to special case it
⇩ƛ # To each character in the lowercased input:
k• # Push a list of each row of qwerty
5vẇ # Split each into [first 5 characters, rest]
∑ # And fold the list by addition. This gives a list of [left keys, right keys]
vFT # Determine whether the character is a left or right key.
vF # Filter out the key from each side
f ̄ # Flatten that and get the forward differences
# This will be used to determine whether there's a pattern of left/right or right/left.
# A 0 in this list means that two characters in a row are from the same side.
A # Check whether all numbers are non-0, as per the above explanation of why. This will return either 0 or 1
I # Push that many spaces. This is to be consistent with the empty string output.
💎
Created with the help of Luminespire.
Jelly, 13 bytes
ŒlØqiþ§>5IẠ«L
A monadic Link that accepts a list of characters from A-Za-z and yields 1 if ping-pong or 0 otherwise.
Try it online! Or see the test-suite.
Nibbles, 23 nibbles (11.5 bytes)
`^,`'`=@=$`D2~ fe00f740
Outputs 0 (falsy) if the input is a ping-pong string, or a nonzero value (truthy) if it isn't.
Can be adapted for various keyboard layouts by adjusting the 32-bit mask (here fe00f740 for left-hand keys on a QWERTY layout). This can't be shortened, even if all the left-hand keys are bunched together, as it needs to be 32 bits long to achieve case-insensitivity by modular indexing.
`^,`'`=@=$`D2~ fe00f740
`=@ # split input into chunks of same
= # modular index of
$ # codepoint of each character
# in
`D2 fe00f740 # binary digits of fe00f740
# (1 for left-hand letters, 0 otherwise);
`' # now transpose this
, # and get the length
# (0 if input was empty,
# 1 if input was ping-pong string,
# >1 if any adjacent input characters were typed with the same hand)
`^ ~ # and bitwise-xor it with 1
QWERTASDFGZXCVBand other letters, ignoring case." \$\endgroup\$