Scrivi una funzione che restituisce un oggetto iterabile di tutti i punti validi a 4 direzioni adiacenti a (x, y)


17

Una necessità molto comune nelle classi di algoritmi e nell'informatica in generale è quella di iterare in senso 4 su una griglia o matrice (come in BFS o DFS). Ciò sembra tradursi spesso in un sacco di codice goffo e dettagliato con molta aritmetica e confronti all'interno dei cicli. Ho visto molti approcci diversi a questo, ma non riesco a scuotere la sensazione che ci sia un modo più conciso per farlo.

La sfida è scrivere una funzione pura che, data la larghezza e l'altezza di un piano finito che ha n, morigine nel punto (0,0), e le coordinate (x,y)che possono rappresentare qualsiasi punto valido all'interno di quel piano, restituisce un oggetto iterabile di tutti i punti all'interno del piano che sono in 4 direzioni adiacente a (x,y).

L'obiettivo è definire quella funzione nel minor numero di byte possibile.

Alcuni esempi per aiutare a illustrare input / output validi:

n = 5 (y-axis), m = 3 (x-axis) (zero-based)

matrix = [
    [A, B, C],
    [D, E, F],
    [G, H, I],
    [J, K, L],
    [M, N, O],
]

(x, y) => [valid iterable points]

E: (1, 1) => [(1, 0), (2, 1), (1, 2), (0, 1)]
A: (0, 0) => [(1, 0), (0, 1)]
L: (2, 3) => [(2, 2), (2, 4), (1, 3)]
N: (1, 4) => [(1, 3), (2, 4), (0, 4)]
n = 1 (y-axis), m = 1 (x-axis) (zero-based)

matrix = [
    [A],
]

(x, y) => [valid iterable points]

A: (0, 0) => []
n = 2 (y-axis), m = 1 (x-axis) (zero-based)

matrix = [
    [A],
    [B],
]

(x, y) => [valid iterable points]

A: (0, 0) => [(0, 1)]
B: (0, 1) => [(0, 0)]

Ed ecco un esempio (questo in Python) di una funzione che soddisfa le condizioni:

def four_directions(x, y, n, m):
    valid_coordinates = []
    for xd, yd in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
        nx, ny = x + xd, y + yd
        if 0 <= nx < m and 0 <= ny < n:
            valid_coordinates.append((nx, ny))
    return valid_coordinates

L'esempio sopra ha definito una funzione con nome, ma sono accettabili anche funzioni anonime.

Gli ingressi n, m, x, ysono tutti numeri interi a 32 bit senza segno nei seguenti intervalli:

n > 0
m > 0
0 <= x < m
0 <= y < n

L'output deve assumere la forma di un iterabile (tuttavia la lingua scelta lo definisce) di (x, y) coppie.

Ulteriori chiarimenti:

I numeri complessi (e altre rappresentazioni / serializzazioni) sono OK fintanto che il consumatore dell'iterabile può accedere xe ycome numeri interi che conoscono solo la loro posizione.

Gli indici non basati su zero sono accettabili, ma solo se la lingua scelta è una lingua non indicizzata su zero. Se la lingua utilizza una combinazione di sistemi di numerazione, per impostazione predefinita viene utilizzato il sistema di numerazione della struttura dei dati più comunemente usato per rappresentare una matrice. Se questi sono ancora tutti concetti estranei nella lingua data, qualsiasi indice di partenza è accettabile.


6
Benvenuti nel sito! Questa sfida è abbastanza buona per i nostri standard, ma ci sono un paio di cose che vanno contro il nostro stile. Per uno preferiamo di gran lunga sfide che non si limitano a una sola lingua, se possibile. È molto più divertente quando tutti possono competere. Generalmente segniamo il code-golf in byte rispetto ai caratteri, sono gli stessi per la maggior parte degli scopi ma ci sono un paio di cose economiche che puoi fare se le risposte sono segnate in caratteri. Spero che tu ti diverta qui!
Post Rock Garf Hunter,

Siamo sicuri che (x,y)si trova nel rettangolo, giusto?
xnor

4
Per impostazione predefinita, CGCC consente programmi completi e funzioni come invii. Questo aiuta a consentire alle lingue che non hanno necessariamente un concetto di funzioni di competere anche
Jo King,

3
Un output sarebbe STDOUT, piuttosto che un oggetto codice. Questo in genere può essere qualsiasi output con delimitatori chiari, quindi è inequivocabile e segue i formati di output standard
Jo King,

2
È consentito rappresentare le coordinate come numeri complessi anziché come tuple intere?
Gioele,

Risposte:


12

Python 2 , 66 byte

lambda m,n,x,y:[(x-1,y),(x+1,y)][~x:m-x]+[(x,y-1),(x,y+1)][~y:n-y]

Provalo online!

Elenca i quattro vicini, quindi utilizza la suddivisione in elenchi per rimuovere quelli non consentiti.


Python 2 , 71 byte

lambda m,n,x,y:[(k/n,k%n)for k in range(m*n)if(k/n-x)**2+(k%n-y)**2==1]

Provalo online!

Invece di controllare quali dei quattro vicini sono in-bound, lo facciamo nel modo più lento di controllare tutti i punti in-bound per quelli che sono vicini, ovvero avere una distanza euclidea esattamente 1 da (x,y). Usiamo anche il classico trucco div-mod per scorrere su una griglia , risparmiando la necessità di scrivere due cicli come for i in range(m)for j in range(n).

Ho provato a usare l'aritmetica complessa per scrivere la condizione della distanza, ma è risultato più lungo da scrivere abs((k/n-x)*1j+k%n-y)==1.


Python 2 , 70 byte

lambda m,n,x,y:[(x+t/3,y+t%3-1)for t in-2,0,2,4if m>x+t/3>=0<y+t%3<=n]

Provalo online!


11
Congratulazioni per il 100k!
Arnauld,

4

Ottava , 90 byte

Questo utilizza un approccio geometrico: per prima cosa creiamo una matrice di zeri della dimensione desiderata e impostiamo 1a nella posizione desiderata. Quindi contiamo con il kernel

[0, 1, 0]
[1, 0, 1]
[0, 1, 0]

che produce una nuova matrice della stessa dimensione con quella dei 4 vicini del punto originale. Quindi abbiamo find()gli indici delle voci diverse da zero di questa nuova matrice.

function [i,j]=f(s,a,b);z=zeros(s);z(a,b)=1;[i,j]=find(conv2(z,(v=[1;-1;1])*v'<0,'same'));

Provalo online!

la convoluzione è la chiave del successo.


4
In effetti lo è, non importa quanto piccolo sia il carattere
Luis Mendo,


3

JavaScript (ES6), 74 byte

Approccio noioso.

(h,w,x,y)=>[x&&[x-1,y],~x+w&&[x+1,y],y&&[x,y-1],++y-h&&[x,y]].filter(_=>_)

Provalo online!


JavaScript (Node.js) , 74 byte

Meno noioso ma altrettanto lungo. Accetta input come ([h,w,x,y]).

a=>a.flatMap((_,d,[h,w,x,y])=>~(x+=--d%2)*~(y+=--d%2)&&x<w&y<h?[[x,y]]:[])

Provalo online!


JavaScript (V8) , 67 byte

Se tutti i metodi di output standard fossero consentiti, potremmo semplicemente stampare le coordinate valide con:

(h,w,x,y)=>{for(;h--;)for(X=w;X--;)(x-X)**2+(y-h)**2^1||print(X,h)}

Provalo online!


2

Gelatina ,  13  12 byte

2ḶṚƬNƬẎ+⁸%ƑƇ

Un collegamento diadica accettare una lista di due numeri interi (0-indicizzati) a sinistra, [row, column]e due interi a destra, [height, width]che produce una lista di liste di numeri interi, [[adjacent_row_1, adjacent_column_1], ...].

Provalo online!

Come?

2ḶṚƬNƬẎ+⁸%ƑƇ - Link: [row, column]; [height, width]   e.g. [3,2]; [5,3] (the "L" example)
2            - literal 2                                   2
 Ḷ           - lowered range                               [0,1]
   Ƭ         - collect up while distinct, applying:
  Ṛ          -   reverse                                   [[0,1],[1,0]]
     Ƭ       - collect up while distinct, applying:
    N        -   negate                                    [[[0,1],[1,0]],[[0,-1],[-1,0]]]
      Ẏ      - tighten                                     [[0,1],[1,0],[0,-1],[-1,0]]
        ⁸    - chain's left argument ([row, column])       [3,2]
       +     - add (vectorises)                            [[3,3],[4,2],[3,1],[2,2]]
           Ƈ - filter keep if:
          Ƒ  -   is invariant under:
         %   -     modulo ([height, width]) (vectorises)    [3,0] [4,2] [3,1] [2,2]
             - (...and [3,0] is not equal to [3,3] so ->)  [[4,2],[3,1],[2,2]]

È possibile sostituire ḶṚƬcon Ṭ€. 2ḶṚƬNƬẎrestituisce [[0, 1], [1, 0], [0, -1], [-1, 0]], mentre 2Ṭ€NƬẎrestituisce [[1], [0, 1], [-1], [0, -1]], e, poiché i singoli sono avvolti, +vettorializza solo con il primo elemento di per quelli, quindi agiscono come se il loro secondo elemento fosse 0(l'identità additiva). Di conseguenza, può cambiare solo l'ordine dell'output.
Erik the Outgolfer,

2

Perl 6 , 56 49 byte

-7 byte grazie a nwellnhof!

{grep 1>(*.reals Z/@^b).all>=0,($^a X+1,-1,i,-i)}

Provalo online!

Rimuove gli elementi fuori limite controllando se, quando diviso per i limiti dell'array, è compreso tra 0 e 1. Accetta input e output tramite numeri complessi in cui la parte reale è la xcoordinata e l'immaginario è il y. Puoi estrarli attraverso le funzioni .ime .re.



@nwellnhof Molto bello! Mi piacerebbe costruire su di esso per fare qualcosa di simile questo , ma divnon sembra lavorare per Nums
Jo Re

(*.reals>>.Int Zdiv@^b).noneo (*.reals Z/@^b)>>.Int.nonefunzionerebbe ma il cast di Int sembra troppo costoso.
nwellnhof,

1

J , 30 29 28 byte

(([+.@#~&,1=|@-)j./)~j./&i./

Provalo online!

Come:

  • Gira la mano destra m x narg in una griglia di numeri complessij./&i./
  • Lo stesso per l'arg sinistro (il nostro punto) j./
  • Crea una maschera che mostri dove la distanza tra il nostro punto e la griglia è esattamente 1 1=|@-
  • Usalo per filtrare la griglia, dopo aver appiattito entrambi #~&,
  • Trasforma il risultato in punti reali +.@


0

Carbone , 29 byte

Jθη#FIζFIε«Jικ¿№KV#⊞υ⟦ικ⟧»⎚Iυ

Provalo online! Il collegamento è alla versione dettagliata del codice. Accetta input nell'ordine x, y, larghezza, altezza. Spiegazione:

Jθη#

Stampa #a nella posizione fornita.

FIζFIε«

Passa sopra il rettangolo dato.

Jικ

Passa alla posizione corrente.

¿№KV#⊞υ⟦ικ⟧

Se c'è un adiacente # salva la posizione.

»⎚Iυ

Emette le posizioni rilevate alla fine del loop.

Risposta noiosa:

FIζFIε¿⁼¹⁺↔⁻ιIθ↔⁻κIηI⟦ικ

Provalo online! Il collegamento è alla versione dettagliata del codice. Funziona trovando matematicamente le posizioni adiacenti.


0

Haskell, 62 byte

utilizzando equazione del cerchio

f m n a b = [(x,y)|x<-[0..m-1],y<-[0..n-1],(x-a)^2+(y-b)^2==1]

Provalo online!

Approccio noioso: 81 byte

f m n x y=filter (\(x,y)->x>=0&&y>=0&&x<m&&y<n) [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.