Numpad Word Search

20

2

Given an integer from 1 to 999 inclusive, output a truthy value if it appears horizontally, vertically, or diagonally, either forwards or backwards, anywhere in the 3x3 square of digits 1-9 on a standard number pad:

789
456
123

If the number does not appear, output a falsy value.

The exact 65 numbers you need to output truthy for are:

1
2
3
4
5
6
7
8
9
12
14
15
21
23
24
25
26
32
35
36
41
42
45
47
48
51
52
53
54
56
57
58
59
62
63
65
68
69
74
75
78
84
85
86
87
89
95
96
98
123
147
159
258
321
357
369
456
654
741
753
789
852
951
963
987

Everything else is falsy.

The shortest code in bytes wins.

Calvin's Hobbies

Posted 2016-12-04T11:23:40.920

Reputation: 84 000

Relevant OEIS. – Fatalize – 2016-12-04T14:41:32.923

The input may contain 0, it can be a string. – Calvin's Hobbies – 2016-12-04T19:43:52.387

I see Luis Mendo showing up with a MATL answer in the near future heh. – Magic Octopus Urn – 2016-12-05T13:32:50.707

Answers

16

JavaScript (ES6), 83 ... 74 73 bytes

Takes input as a string.

n=>1/([a,b,c]=[...n].map(v=>--v+v/3|0))||45242>>(a^b)&(~c&&n<99|b*2==a+c)

Saved 3 bytes thanks to ETHproductions

How it works

We transform the number pad by applying an offset to each digit according to the row it belongs to:

  • +1 for the top row
  • 0 for the middle row
  • -1 for the bottom row.

All codes below are represented in hexadecimal.

7 8 9      8 9 A  (+1)
4 5 6  =>  4 5 6  (unchanged)
1 2 3      0 1 2  (-1)

Let's consider all XOR combinations of these new key codes. Contiguous keys are highlighted with brackets.

XOR|  0   1   2   4   5   6   8   9   A 
---+------------------------------------
 0 |  0  [1]  2  [4] [5]  6   8   9   A 
 1 | [1]  0  [3] [5] [4] [7]  9   8   B 
 2 |  2  [3]  0   6  [7] [4]  A   B   8 
 4 | [4] [5]  6   0  [1]  2  [C] [D]  E 
 5 | [5] [4] [7] [1]  0  [3] [D] [C] [F]
 6 |  6  [7] [4]  2  [3]  0   E  [F] [C]
 8 |  8   9   A  [C] [D]  E   0  [1]  2 
 9 |  9   8   B  [D] [C] [F] [1]  0  [3]
 A |  A   B   8   E  [F] [C]  2  [3]  0 

We can see that two keys are contiguous if and only if XORing their codes leads to one of the following values:

1, 3, 4, 5, 7, C, D, F

This list can be packed into the following binary mask:

  FEDCBA9876543210
  ----------------
0b1011000010111010 = 0xB0BA = 45242

Hence the test to determine if two key codes (a, b) correspond to two contiguous keys:

45242 >> (a ^ b) & 1

For three key codes (a, b, c), we need this additional test:

b * 2 == a + c

Example:

a = 0xA
b = 0x6
c = 0x2

0xB0BA >> (0xA ^ 0x6) & 1 == 0xB0BA >> 0xC & 1 == 1
=> 0xA and 0x6 are contiguous key codes

0x6 * 2 == 0xA + 0x2
=> 0xA, 0x6 and 0x2 are contiguous key codes on the same row, column or diagonal

Demo

This snippet outputs the list of truthy values.

let f =

n=>1/([a,b,c]=[...n].map(v=>--v+v/3|0))||45242>>(a^b)&(~c&&n<99|b*2==a+c)

console.log([...Array(1000).keys()].filter(n=>n && f(n+'')).join(' '))

Arnauld

Posted 2016-12-04T11:23:40.920

Reputation: 111 334

Coercion is your friend here: a-.5 returns true for any array a containing (zero or) one integer. n=>([a,b,c]=[...n].map(v=>--v+v/3|0))-.5||n%10&&n<100|b*2==a+c&&45242&1<<(a^b) – ETHproductions – 2016-12-04T20:38:33.820

@ETHproductions Ah, nice! 1/a is even shorter and should work just as well, I think. – Arnauld – 2016-12-04T20:56:26.640

5

Python3, 72 bytes

lambda n,s="123 456 789 741 852 963 42 753 86 26 159 84 ":n in s+s[::-1]

Input is taken as a string.

Golfing suggestions welcome! :D

Yytsi

Posted 2016-12-04T11:23:40.920

Reputation: 3 582

Does this take the number as a string? – FlipTack – 2016-12-04T18:29:02.777

@Flp.Tkc Yes it does. I'll mention that in the post. Thanks! – Yytsi – 2016-12-04T18:54:47.313

@TuukkaX there is an additional space in string s, you can save 1 byte. – Gurupad Mamadapur – 2016-12-05T15:38:35.117

@GurupadMamadapur I don't see why I would change my current 72 bytes solution to your 74 bytes solution... :D And if you refer to my string s, which has an whitespace after 84, then you're incorrect, since it's required. If it wouldn't contain a whitespace, the resulted string would have a chain '8448', which would lead to failed testcases. Thanks for the suggestions though! – Yytsi – 2016-12-05T22:53:44.820

@TuukkaX Yeah you're right about the extra whitespace, missed that one :) – Gurupad Mamadapur – 2016-12-06T09:12:48.573

That's crazy, great thought process there. – Magic Octopus Urn – 2016-12-07T22:26:24.647

@carusocomputing You probably meant to comment on Arnauld's answer. He did a great job at thinking a good bit-hacky solution! – Yytsi – 2016-12-08T06:22:43.733

4

Befunge, 169 161 159 bytes

38*:2+"*0>DTV{51"3*\3*"kV"3*\3*"{w"3*\3*"mr"v
v:\&+*83:++66:+"c":+"?":+"$":++66:+"W":*6\*4<
_v#:\_v#*-+%+55g00*+55g02\*-g02\*-g00\`9::::p02/+55p00%"d":
0<@.!!<

Try it online!

The first two lines are just pushing the list of test numbers onto the stack. This is done in order of size, since it can sometimes be easier to generate a number as an offset from the previous one in the series rather than generating it from scratch. Once we get to the larger numbers, we can also sometimes save a byte by generating them in pairs, e.g. "kV"3*\3* gives us 258 and 321 in nine bytes, where individually they would take five bytes each.

The main loop is on line three, executing right to left with wrap around. This just iterates through all the test numbers on the stack, comparing the value itself, value%100, and value/10. If any of those match the input number or the number <= 9 then we output 1 and exit. If there is no match, we continue looping. If we run out of test numbers on the stack then we output 0 and exit.

Thanks to Mistah Figgins for saving me a couple of bytes.

James Holderness

Posted 2016-12-04T11:23:40.920

Reputation: 8 298

I think you can change the last line to 0<@.!!< to save 2 bytes. This relies on the top of the stack being non-zero when the IP comes down onto the second arrow. Try it Online!

– MildlyMilquetoast – 2016-12-05T03:10:49.523

3

Jelly, 29 24 19 bytes

Saved 5 bytes thanks to @Dennis's suggestion of K and Ɠ.

9s3µUŒD;;Z;ŒDµ;UKƓẇ

Try it online!

Explanation

9Rs3µUŒD;;Z;ŒDµ;UKƓẇ  Main link. Argument: number
9s3                   Split [1..9] into [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
   µ                  New monadic chain
    U                 Reverse the rows
     ŒD               Take the diagonals of the result
       ;              Append the original rows
        ;Z            Append the original columns
          ;ŒD         Append the original diagonals
             µ        New monadic chain
              ;U      Append the reverse of everything
                K     Join by spaces
                 Ɠẇ   Check if a line from STDIN is in the result

PurkkaKoodari

Posted 2016-12-04T11:23:40.920

Reputation: 16 699

If you read the input from STDIN, 9s3µUŒD;;Z;ŒDµ;UKƓẇ saves 5 bytes. – Dennis – 2016-12-04T19:02:28.703

Do you need to reverse the rows? They can appear forward or backwards, so 123,456,789 should be the same as 789,456,123 – Riley – 2016-12-05T14:41:02.683

@Riley I reverse each row, not the rows as an array. I guess I could've been clearer there. Anyway, it's done in order to get half of the diagonals. – PurkkaKoodari – 2016-12-05T14:51:49.187

2

Ruby, 77 bytes

->n{!!((s='123 456 789 147 258 369 753 951 86 62 24 48 ')+s.reverse)["#{n}"]}

Vasu Adari

Posted 2016-12-04T11:23:40.920

Reputation: 941

You are creating a string that is '123 456 789 147 258 369 753 951 ' + the same string reversed, and checking whether the parameter is found on the string, right? If it's so, then this solution is invalid. For example, 86 and 24 will fail. – Yytsi – 2016-12-04T15:26:27.877

The rules say you need only output a truthy or falsey value, so you don't need !! or the attendant parentheses. – Jordan – 2016-12-05T01:22:11.657

0

bash, 75

printf %s\\n 123 456 789 741 852 963 42 753 86 26 159 84|tee >(rev)|grep $1

outputs something and returns 0 for all the values in that list

prints nothing and returns 1 in all other cases

izabera

Posted 2016-12-04T11:23:40.920

Reputation: 879

0

Java, 397 bytes

public class Numpad {public static void main(String[] args){Scanner input=new Scanner(System.in);int in=input.nextInt();int h=in/100;int u=in%10;int t=(in%100)/10;boolean out=false;input.close();if(in<10)out=true;else if( h==0){int decider=Math.abs(t-u);if((decider==1)||(decider==3)||(decider==4))out=true;}else{if ( Math.abs(h-t) == Math.abs(t-u))out=true;}System.out.println("RESULT : "+out);}}

Nefi knomore

Posted 2016-12-04T11:23:40.920

Reputation: 1

I am new to this .. kindly excuse any oblivionism. – Nefi knomore – 2016-12-07T04:37:07.617

Hello, and welcome to the site! I've edited your post so that the code section is displayed as code and added a byte count, which is standard for answers here. This competition is a [tag:code-golf] competition, meaning the ultimate goal is to make your code as short as possible. For example, you can use short variable names, and define a function instead of a full class. I'm not great at Java, but some more tips are available here. You should try to make your code shorter, and then [edit] the new version into your post.

– James – 2016-12-07T04:44:26.693