Números de um cavaleiro de Numpad


33

Para dígitos diferentes de zero em um teclado padrão

789
456
123

considere colocar um cavaleiro do xadrez em qualquer dígito e movê-lo com qualquer número de saltos normais em forma de L, traçando um número inteiro decimal positivo. Quais números inteiros positivos podem ser expressos dessa maneira?

Uma delas é 38, já que o cavaleiro poderia começar 3e se mover para a esquerda e para cima 8. 381e 383também são possíveis.

3em si é possível se nenhum salto for dado (o que é permitido). 5também, mas nenhum outro dígito pode ser alcançado a partir do 5, portanto, é o único número em que o dígito 5aparece.

Escreva um programa ou função que receba um número inteiro decimal positivo (você pode tomá-lo como uma string, se desejar) e imprima ou retorne um valor verdadeiro se o número puder ser expresso por um cavaleiro em um teclado numérico da maneira descrita, mas, caso contrário, gera um valor falso .

O código mais curto em bytes vence. Desempate é resposta anterior

Exemplos

Verdade:

1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 18, 38, 61, 81, 294, 349, 381, 383, 729, 767, 38183, 38383, 18349276, 183492761, 618349276

Falsy:

10, 11, 50, 53, 55, 65, 95, 100, 180, 182, 184, 185, 186, 187, 188, 189, 209, 305, 2009, 5030, 3838384, 4838383, 183492760

2
O que há com os cavaleiros de xadrez hoje ? :-D
Luis Mendo

1
Dica: Se você escrever os números como uma linha de quebra automática, o cavaleiro estará sempre pulando quatro espaços no sentido horário ou quatro espaços no contador. Não sei se isso é útil.
Fund Monica's Lawsuit

3
@LuisMendo Wrapping. Por exemplo, se você tratar é uma lista interminável de 78963214, repetidas vezes sem conta. Conte as distâncias - sempre são quatro, de um jeito ou de outro. Eu deveria ter sido mais claro e dito explicitamente que você deve escrevê-lo em ordem circular.
Fund Monica's Lawsuit

@QPaysTaxes Ah, eu pensei que você quis dizer círculo, mas 123...9. Desculpe
Luis Mendo

@LuisMendo Não se preocupe. Como eu disse, eu deveria ter sido mais claro sobre o que eu quis dizer.
Fund Monica's Lawsuit

Respostas:


16

Geléia, 19 15 14 bytes

Doȷ’d3ạ2\P€=2P

Experimente online! ou verifique todos os casos de teste .

Como funciona

Doȷ’d3ạ2\P€=2P  Main link. Argument: n (integer)

D               Convert n to base 10 (digit array).
  ȷ             Yield 1000.
 o              Logical OR. This replaces each 0 with 1000.
   ’            Decrement each digit.
    d3          Divmod; replace each digit k with [k:3, k%3].
      ạ2\       Pairwise reduce by absolute difference.
                For each pair of adjacent digits [i, j], this computes
                [abs(i:3 - j:3), abs(i%3 - j%3)].
         P€     Compute the product of each result.
                n is a Numpad's Knight Number iff all products yield 2.
           =2   Compare each product with 2.
             P  Multiply the resulting Booleans.

18

Python 2, 52 bytes

f=lambda n:n<6or`n%100`in'18349276167294381'*f(n/10)

Verifica se há dois dígitos consecutivos na sequência '18349276167294381'. Para obter dígitos consecutivos, em vez de fazê-lo zip(`n`,`n`[1:]), a função verifica repetidamente os dois últimos dígitos e remove o último dígito.


13

Retina , 58 40 bytes

Agradecemos ao Sp3000 por sugerir esta idéia:

M&!`..
O%`.
A`16|18|27|29|34|38|49|67
^$

Experimente online! (Ligeiramente modificado para executar todo o conjunto de testes de uma vez.)

Imprime 1para verdade e 0para resultados falsos.

Explicação

M&!`..

Encontre todas as correspondências sobrepostas de .., ou seja, todos os pares consecutivos de dígitos, e junte-as a feeds de linha.

O%`.

Sort the digits in each line, so that we only need to check half as many pairs.

A`16|18|27|29|34|38|49|67

Remove all lines which correspond to a valid move.

^$

Count the matches of this regex. That is, if all lines were removed, this matches the resulting empty string once, otherwise it fails to match and gives zero instead.



7

Ruby, 57 bytes

Anonymous function. Argument is a string.

->n{(0..n.size).count{|i|!"16729438183492761"[n[i,2]]}<1}

Program with the test suite:

f=->n{(0..n.size).count{|i|!"16729438183492761"[n[i,2]]}<1}

a=%w{1 2 3 4 5 6 7 8 9 16 18 38 61 81 294 349 381 383 729 767 38183 38383 18349276 183492761 618349276
10 11 50 53 55 65 95 100 180 182 184 185 186 187 188 189 209 305 2009 5030 3838384 4838383 183492760}

a.each {|e|p [e, f[e]]}

I just encoded all the possible knight moves into a string and checked if every 2 digits within the input existed in that string.


Oh, that lookup string would also save me 17 bytes. Do you mind if I use that for my Retina answer?
Martin Ender

Go for it! Just give credit, I guess.
Value Ink

Thanks, but I ended up with an even shorter solution based on a suggestion by Sp3000 :)
Martin Ender

6

grep 58 bytes

grep "^((?=18|16|29|27|34|38|49|43|61|67|72|76|81|83|94|92).)*.$"

Because really, if you cannot beat grep...


2
Neither 5 nor 185 emit 1 with your command line, while 5 is in the truthy, and 185 in the falsy list.
Guntram Blohm supports Monica

1
@GuntramBlohm fixed -- got lost in regular negation
Yakk

6

Haskell 46 bytes

q=zip<*>tail
all(`elem`q"16729438183492761").q

Usage example: all(`elem`q"16729438183492761").q $ "183492761" -> True

How it works: It uses the lookup string found in @Kevin Lau's answer. q makes a list of pairs of adjacent chars from a string, e.g. q "1672" -> [('1','6'),('6','7'),('7','2')]. The function returns true if all pairs from the input appear in the pairs from the lookup string. q turns single digit inputs into the empty list, so elem always succeeds.


Why does zip<*>tail work like a flipped version of zip=<<tail? I think I don't understand what applicatives generalize.
xnor

@xnor: I just use it. <*> is defined as (<*>) f g x = f x (g x).
nimi

6

JavaScript (ES6), 65 62 bytes

s=>[...s].every((c,i)=>!i|"16729438183492761".match(s[i-1]+c))

Returns true or false. I'd previously tried a recursive solution, which takes 63 bytes, and map and even reduce but they took me 73 bytes.

Edit: Saved 3 bytes thanks to @user81655.


Couldn't do better, my best try was at 88 bytes. Bravo!
Naouak

@user81655 You mean match works instead of ~search (but either way, that's really underhanded) and | can replace || (but not in the recursive version, sadly.)
Neil

@user81655 I was referring to the way that !i|...match works because the match result, if successful, is an array of a single string of two digits, which the | operator ends up coercing into a valid integer.
Neil

@Neil Ah, right.
user81655

6

C, 85 81 bytes

Golfed:

i;f(char*b){i=*b++-49;return*b?(*b=="8749x7214"[i]||*b=="6983x1632"[i])&&f(b):1;}

Old non-recursive version (85 bytes):

i;f(char*b){for(;(i=*b++-49),*b&&*b=="8749x7214"[i]||*b=="6983x1632"[i];);return!*b;}

Old code with white-space and main program:

i;
f(char*b){
    for (; (i=*b++-49), *b     // i = index of digit + 1 in following arrays
        &&*b=="8749x7214"[i]   // 1st possible jump for 1..9
        ||*b=="6983x1632"[i];  // 2nd possible jump for 1..9
    );
    return !*b;
}

main(){
    char b[16];
    while(scanf("%s", b) == 1) printf("%d",f(b));
    return 0;
}

This accepts space-delimited numbers via standard input and outputs 0 if not-numpad-knight, or 1 otherwise.

The new 81-byte recursive version shaves 4 bytes.


5

MATL, 38 37 29 bytes

This uses @QPaysTaxes idea.

I:8JK5:7Pvj!Uttnqh?)d|2:EQm}h

The output is a 2D, complex, non-empty array. It is truthy if all its values have nonzero real part, and falsy otherwise.

Try it online!


1
Is this even allowed??
CalculatorFeline

The question asks for a truthy or a falsy value, not a whole array.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2
@CatsAreFluffy This is our definition of truthy/falsy. As in MATLAB/Octave, arrays are truthy in MATL iff all of its elements are truthy. (example)
Dennis

CC @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Dennis


4

MATL, 25 24 33 26 bytes

Shaved off 1 byte thanks to @LuisMendo!
@Dennis found a bug, and then fixed it! Thanks!

'bSVYXbTUZW'j47-)d2^48\1=A

Takes integer as input. Outputs 1/0.

Try it online!


@LuisMendo Right on both counts, thanks!
beaker

@Dennis Updated, and hopefully correct. Thanks for your help.
beaker

I don't think you need the A at the end. MATL's vectors are truthy iff they do not contain a 0.
Dennis

4

C, 140 92 bytes

c;L(char*i){while(*i&&(!c||*i=="6743x1212"[c-49]||*i=="8989x7634"[c-49]))c=*i++;return !*i;}

Assuming ASCII

Detailed Try it here

// valid transition from x to n[x-'1'][0 or 1]

int n[9][2] =
{
    {'6','8'},{'7','9'},{'4','8'},
    {'3','9'},{'x','x'},{'1','7'},
    {'2','6'},{'1','3'},{'2','4'}
};

// i is a pointer to where to start on a string

bool L(char * i)
{
    char c = 0;

    // move if not \0 and (not-first-char or is a valid move)

    while((*i) && (!c || (*i)==n[c-'1'][0] || (*i)==n[c-'1'][1]))
    {
        c = (*i++);
    }

    return !(*i); // success if it's \0
}

those lookup tables are huge. You can improve your score a lot if you get rid of all the delimiters {,}[] and encode it as a char* string instead. Also, note that your #define is not being cost-effective when you use it only twice: removing it would save you 4 bytes.
tucuxi

@tucuxi thanks for the tips, I managed to bring it down to 92, having \0 within the array caused undefined behavior so I replaced it with x
Khaled.K

Nice - also, don't forget to use <s>oldscore</s> newscore when editing to reflect score improvements, and <!-- language-all: lang-c --> before your code starts to fix syntax highlighting. I also managed to reduce my byte-count somewhat by dropping the loop altogether
tucuxi

Your 'detailed' looks very different from a plain expansion of the golfed code (where's n in the short version?). Also, you probably ought to mention that you're assuming ASCII encoding - you'll get different numbers on EBCDIC machines.
Toby Speight

@TobySpeight the detailed version is supposed to show how it was built basically, yes I'm assuming ASCII which is the common case in C.
Khaled.K

3

Julia, 51 49 bytes

n->diff(["@1634@8725"...][digits(n)+1]).^2%48⊆1

Verification

julia> f=n->diff(["@1634@8725"...][digits(n)+1]).^2%48⊆1
(anonymous function)

julia> all(map(f,(1,2,3,4,5,6,7,8,9,16,18,38,61,81,294,349,381,383,729,767,38183,38383,18349276,183492761,618349276)))
true

julia> any(map(f,(10,11,50,53,55,65,95,100,180,182,184,185,186,187,188,189,209,305,2009,5030,3838384,4838383,183492760)))
false

3

Actually, 30 bytes

;#pXZdX`Σ"67294381";'1+R+íu`Mπ

Takes input as a string. Outputs a positive integer for true and 0 for false.

Try it online!

Explanation:

;#pXZdX`Σ"67294381";'1+R+íu`Mπ
                                 (implicit) push input
;#pXZdx                         push zip(n[:-1], n[1;]) (pairs of digits)
       `Σ"67294381";'1+R+íu`M   map:
        Σ                         join digits
         "67294381";'1+R+         push "16729438183492761" (the magic string used in many other solutions)
                         íu       0-based index (-1 if not found), increment so 0 is not found and >=1 is the 1-based index
                             π  product

3

PowerShell v2+, 105 96 bytes

param($a)((1..$a.length|%{'27618349294381672'.IndexOf($a[$_-1]+$a[$_])+1})-join'*'|iex)-or$a-eq5

Iterates through the input (which must be encapsulated with "") by verifying that the index of any sequential pair of characters is in the valid lookup string. I see Kevin Lau had something similar, but I came up with this independently. Each of those indices are added with +1, as the .IndexOf() function will return -1 if the string isn't found. This will turn "not found"s into 0.

We then -join all the resultant integer values with * and pipe that to iex (similar to eval). This will mean if any one of the indices is not found, the entire expression will result in 0. That is encapsulated in parens and -or'd with $a-eq5 for the special case of input "5" to achieve our resultant output.

Test Runs

PS C:\Tools\Scripts\golfing> 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 18, 38, 61, 81, 294, 349, 381, 383, 729, 767, 38183, 38383, 18349276, 183492761, 618349276 | %{.\numpad-knight-numbers.ps1 "$_"}
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True
True

PS C:\Tools\Scripts\golfing> 10, 11, 50, 53, 55, 65, 95, 100, 180, 182, 184, 185, 186, 187, 188, 189, 209, 305, 2009, 5030, 3838384, 4838383, 183492760 | %{.\numpad-knight-numbers.ps1 "$_"}
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False

2

C, 78 bytes

char*a="9614397052";f(x){int b=x/10;return!b||abs(a[x%10]-a[b%10])%6==1&f(b);}

Since everyone else has taken the input as a string, I tried doing it in integers. It works recursively from the least-significant digit (a%10); if it's the only digit, then return true. Otherwise, return true only if the tens digit (b%10) can't be reached from the units digit, and (recursively), the rest of the input satisfies the same test.

The test for reachability works by encoding the knight's tour linearly, and converting each digit to its position (zero to seven) on the tour. For digits 0 and 5, we assign position nine, which is disconnected from the other positions. Then, mutually reachable numbers differ by one (mod eight); i.e. a[x%10]-a[b%10] is either ±1 or ±7. So we test the absolute difference (mod 6) against 1.

This solution works for any character encoding that is valid for C (i.e. digits have contiguous codes from 0 to 9).


1

Java 8, 179 167 Bytes

Places the number pad ints (minus 5 and 0) in a circle. l holds the circle index of these ints. If the difference of two indices is +/- 3 mod 8, then there is a knights move between the ints corresponding to those indices. Note that x is an int[].

x->{if(x.length<2)return 1;int[] l={0,0,1,2,7,0,3,6,5,4};int o=l[x[1]];for(int i:x){int n=l[i];if(i%5==0||(Math.abs(n-o)!=3&&Math.abs(n-o)!=5))return 0;o=n;}return 1;}

Update

  • -11 [16-12-10] Switched to a lambda
  • -1 [16-12-10] Use <2 instead of ==1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.