Urutan grid crossing

17

Jika Anda mengambil selembar kertas grafik dan menggambar garis miring yang berjalan mtepat ke kanan dan ke natas, Anda melintasi n-1garis horizontal dan m-1vertikal dalam beberapa urutan. Tulis kode untuk menampilkan urutan itu.

Misalnya, m=5dan n=3memberi:

Persimpangan kisi untuk m = 5, n = 3

Kemungkinan terkait: Menghasilkan ritme Euclidian , Fibonacci tilings , FizzBuzz

Input: Dua bilangan bulat positif m,nyang relatif prima

Keluaran: Kembalikan atau cetak persimpangan sebagai urutan dua token yang berbeda. Misalnya, itu bisa menjadi string Hdan V, daftar Truedan False, atau 0's dan 1' s dicetak pada baris terpisah. Mungkin ada pemisah antara token selama itu selalu sama, dan tidak, katakanlah, sejumlah ruang variabel.

Kasus uji:

Kasing uji pertama memberikan output kosong atau tidak ada output.

1 1 
1 2 H
2 1 V
1 3 HH
3 2 VHV
3 5 HVHHVH
5 3 VHVVHV
10 3 VVVHVVVHVVV
4 11 HHVHHHVHHHVHH
19 17 VHVHVHVHVHVHVHVHVVHVHVHVHVHVHVHVHV
39 100 HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHH

Dalam format (m,n,output_as_list_of_0s_and_1s):

(1, 1, [])
(1, 2, [0])
(2, 1, [1])
(1, 3, [0, 0])
(3, 2, [1, 0, 1])
(3, 5, [0, 1, 0, 0, 1, 0])
(5, 3, [1, 0, 1, 1, 0, 1])
(10, 3, [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1])
(4, 11, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0])
(19, 17, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
(39, 100, [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0])
Tidak
sumber
2
Hari ini di PPCG: Algoritma Menggambar Garis golf Bresenham
Sparr
Berdasarkan format alternatif yang Anda tambahkan, dapat / haruskah input diulang sebagai bagian dari output? Kalau tidak, saya tidak mengerti mengapa input dan output adalah bagian dari daftar yang sama.
Reto Koradi
@RetoKoradi Tidak, Anda tidak harus memasukkan input. Saya memasukkannya ke dalam tuple untuk mempermudah proses uji kasus.
xnor
Saya dapat memprediksi jawabannya, tetapi tidak ada salahnya untuk bertanya: Apakah dapat diterima untuk menggunakan karakter spasi sebagai salah satu token keluaran? Konsekuensinya adalah bahwa mungkin ada ruang memimpin / tertinggal yang signifikan dalam output. Tidak akan ada ruang lain, jadi semua ruang akan menjadi signifikan.
Reto Koradi
@RetoKoradi Tidak, karena spasi tambahan tidak terlihat.
xnor

Jawaban:

7

Ruby, 92; Burung unta 0.7.0 , 38

f=->m,n{((1..m-1).map{|x|[x,1]}+(1..n-1).map{|x|[1.0*x*m/n,0]}).sort_by(&:first).map &:last}
:n;:m1-,{)o2W}%n1-,{)m n/*0pW}%+_H$_T%

Output untuk keduanya menggunakan 1 dan 0 (mis. 101101).


Berikut penjelasan dari burung unta:

:n;:m    store n and m as variables, keep m on the stack
1-,      from ex. 5, generate [0 1 2 3]
{...}%   map...
  )        increment, now 5 -> [1 2 3 4]
  o        push 1 (the digit 1 is special-cased as `o')
  2W       wrap the top two stack elements into an array
           we now have [[1 1] [2 1] [3 1] [4 1]]
n1-,     doing the same thing with n
{...}%   map...
  )        increment, now 3 -> [1 2]
  m n/*    multiply by slope to get the x-value for a certain y-value
  0        push 0
  pW       wrap the top two stack elements (2 is special-cased as `p')
+        concatenate the two arrays
_H$      sort-by first element (head)
_T%      map to last element (tail)

Dan penjelasan tentang bagaimana semuanya bekerja, menggunakan kode Ruby sebagai panduan:

f = ->m,n {
    # general outline:
    # 1. collect a list of the x-coordinates of all the crossings
    # 2. sort this list by x-coordinate
    # 3. transform each coordinate into a 1 or 0 (V or H)
    # observation: there are (m-1) vertical crossings, and (n-1) horizontal
    #   crossings. the vertical ones lie on integer x-values, and the
    #   horizontal on integer y-values
    # collect array (1)
    (
        # horizontal
        (1..m-1).map{|x| [x, 1] } +
        # vertical
        (1..n-1).map{|x| [1.0 * x * m/n, 0] }  # multiply by slope to turn
                                               # y-value into x-value
    )
    .sort_by(&:first)  # sort by x-coordinate (2)
    .map &:last        # transform into 1's and 0's (3)
}
Gagang pintu
sumber
5

Python, 53

Ini menggunakan output daftar Benar / Salah. Tidak ada yang istimewa di sini.

lambda m,n:[x%m<1for x in range(1,m*n)if x%m*(x%n)<1]
feersum
sumber
4

Pyth - 32 24 byte

Jmm,chk@Qddt@Qd2eMS+hJeJ

Mengambil input melalui stdin dengan format [m,n]. Mencetak hasilnya ke stdout sebagai daftar 0 dan 1, di mana 0 = V dan 1 = H.

Uji secara online


Penjelasan:

J                           # J = 
 m             2            # map(lambda d: ..., range(2))
  m        t@Qd             # map(lambda k: ..., range(input[d] - 1))
   ,chk@Qdd                 # [(k + 1) / input[d], d]
                eMS+hJeJ    # print map(lambda x: x[-1], sorted(J[0] + J[-1])))
Tyilo
sumber
Anda dapat menyimpan byte dengan menggunakan operator peta sintaksis untuk saat Anda memetakan akhir. eMsama dengan med.
Maltysen
Selain itu, Anda bisa mengeluarkannya @"VH"karena Anda diizinkan mencetak 0dan 1bukannya Vdan H.
Maltysen
Anda dapat menyimpan byte lain dengan menggunakan penugasan sebaris dengan J. Inilah yang saya miliki sejauh ini pada 25 byte: pyth.herokuapp.com/...
Maltysen
@ Malaltysen, terima kasih saya pikir Anda dapat menghapus jkkarena hasilnya bisa daftar.
Tyilo
Anda bisa melihat komentar saya tentang penugasan sebaris.
Maltysen
4

Kode mesin IA-32, 26 byte

Hexdump kode:

60 8b 7c 24 24 8d 34 11 33 c0 2b d1 74 08 73 03
03 d6 40 aa eb f2 61 c2 04 00

Saya mulai dari kode C berikut:

void doit(int m, int n, uint8_t* out)
{
    int t = m;
    while (true)
    {
        if (t >= n)
        {
            t -= n;
            *out++ = 1;
        }
        else
        {
            t += m;
            *out++ = 0;
        }
        if (t == n)
            break;
    }
}

Itu menulis output ke buffer yang disediakan. Itu tidak mengembalikan panjang output, tetapi itu tidak benar-benar diperlukan: panjang output selalu m + n - 2:

int main()
{
    char out[100];
    int m = 10;
    int n = 3;
    doit(m, n, out);
    for (int i = 0; i < m + n - 2; ++i)
    {
        printf("%d ", out[i]);
    }
}

Untuk mengubah kode C menjadi kode mesin, saya pertama-tama melakukan beberapa penyesuaian, untuk membuat salah satu if/elsecabang kosong, dan membandingkannya dengan 0alih - alih n:

void doit(int m, int n, char* out)
{
    int t = n;
    while (true)
    {
        int r = 0;
        t -= m;
        if (t == 0)
            break;
        if (t >= 0)
        {
        }
        else
        {
            t += m + n;
            ++r;
        }
        *out++ = r;
    }
}

Dari sini, menulis kode inline-assembly sangat mudah:

__declspec(naked) void __fastcall doit(int x, int y, char* out)
{
    _asm
    {
        pushad;                 // save all registers
        mov edi, [esp + 0x24];  // edi is the output address
        lea esi, [ecx + edx];   // esi is the sum m+n
    myloop:                     // edx is the working value (t)
        xor eax, eax;           // eax is the value to write (r)
        sub edx, ecx;
        jz myout;
        jae mywrite;
        add edx, esi;
        inc eax;
    mywrite:
        stosb;                  // write one value to the output
        jmp myloop;
    myout:
        popad;                  // restore all registers
        ret 4;                  // return (discarding 1 parameter on stack)
    }
}
anatolyg
sumber
Saya ingin tahu - mengapa algoritma ini berfungsi?
xnor
@xnor Secara informal, ini melacak urutan fizzbuzz . Inilah t"jarak ke buzz". Jika jarak setidaknya n, pergi fizz, lain pergi buzz; perbarui jarak; ulangi sampai 0.
anatolyg
3

Python - 125 byte

Menggunakan algoritma yang sangat sederhana, hanya menambah koordinat dan mendeteksi ketika melintasi garis dan dicetak. Saya ingin menerjemahkan ke Pyth.

a,b=input()
i=1e-4
x=y=l=o=p=0
k=""
while len(k)<a+b-2:x+=i*a;y+=i*b;k+="V"*int(x//1-o//1)+"H"*int(y//1-p//1);o,p=x,y
print k

Loop sementara memeriksa jumlah lines dan kemudian memeriksa apakah ada nilai yang melewati batas int dengan mengurangi.

Mengambil input like 39, 100dari stdin dan mencetak like HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHke stdout dalam satu baris.

Maltysen
sumber
3

CJam, 15 byte

Ll~_:*,\ff{%!^}

Coba di sini.

Mencetak 01untuk V dan 10untuk H.

Penjelasan

L          e# An empty list.
l~         e# Evaluate the input.
_:*,       e# [0, m*n).
\          e# The input (m and n).
ff{%!      e# Test if each number in [0, m*n) is divisible by m and n.
^}         e# If divisible by m, add an 10, or if divisible by n, add an 01 into
           e# the previous list. If divisible by neither, the two 0s cancel out.
           e# It's just for output. So we don't care about what the previous list
           e# is -- as long as it contains neither 0 or 1.

Garis diagonal melintasi garis horizontal untuk setiap 1 / n dari seluruh garis diagonal, dan melintasi garis vertikal untuk setiap 1 / m.

jimmy23013
sumber
Apakah Anda akan menambahkan penjelasan untuk ini? Ini sangat menarik, tetapi setidaknya dari pandangan cepat awal saya tidak mengerti mengapa itu berhasil. Dari bermain dengannya, saya perhatikan bahwa itu hanya bekerja untuk nilai-nilai yang merupakan bilangan prima relatif (yang diberikan dalam deskripsi masalah), sementara tambang bekerja untuk semua nilai. Jadi matematika yang mendasarinya jelas sangat berbeda.
Reto Koradi
Setelah membiarkannya tenggelam, saya yakin saya mengerti setidaknya bagian algoritma. Harus mempelajari logika generasi keluaran nanti.
Reto Koradi
@RetoKoradi Diedit.
jimmy23013
2

TI-BASIC, 32

Prompt M,N
For(X,1,MN-1
gcd(X,MN
If log(Ans
Disp N=Ans
End

Mudah. Menggunakan urutan 0dan 1, dipisahkan oleh linebreak. Kelebihan TI-BASIC adalah gcd(perkalian dua byte dan tersirat, tetapi kelemahannya adalah loop For termasuk nilai akhir dan 5 byte yang dihabiskan untuk input.

lirtosiast
sumber
2

Python, 47

lambda m,n:[m>i*n%(m+n)for i in range(1,m+n-1)]

Seperti algoritma anatolyg , tetapi diperiksa langsung dengan moduli.

Tidak
sumber
1

Haskell, 78 byte

import Data.List
m#n=map snd$sort$[(x,0)|x<-[1..m-1]]++[(y*m/n,1)|y<-[1..n-1]]

Contoh penggunaan:

*Main> 19 # 17
[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
*Main> 10 # 3
[0,0,0,1,0,0,0,1,0,0,0]

Cara kerjanya: buat daftar nilai-x semua penyeberangan vertikal (x,0)untuk xdalam [1,2, ..., m-1] ( 0menunjukkan vertikal) dan tambahkan daftar nilai-x semua penyeberangan horizontal (y*m/n,1)untuk ydi [1,2, ..., n-1] ( 1menunjukkan horizontal). Sortir dan ambil elemen kedua dari pasangan.

Kutukan hari ini: sekali lagi saya harus menghabiskan 17 byte pada importkarena sortdalam Data.Listdan tidak di perpustakaan standar.

nimi
sumber
1

KDB (Q), 44 byte

{"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}

Penjelasan

Temukan semua x nilai sumbu dari titik potong dan urutkan mereka. Jika mod 1 bernilai nol "V", bukan nol adalah "H".

Uji

q){"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}[5;3]
"VHVVHV"
WooiKent Lee
sumber
1

CJam, 26 24 byte

l~:N;:M{TN+Mmd:T;0a*1}*>

Cobalah online

Sangat mudah, cukup banyak implementasi langsung dari algoritma tipe Bresenham.

Penjelasan:

l~    Get input and convert to 2 integers.
:N;   Store away N in variable, and pop from stack.
:M    Store away M in variable.
{     Loop M times.
  T     T is the pending remainder.
  N+    Add N to pending remainder.
  M     Push M.
  md    Calculate div and mod.
  :T;   Store away mod in T, and pop it from stack
  0a    Wrap 0 in array so that it is replicated by *, not multiplied.
  *     Emit div 0s...
  1     ... and a 1.
}*      End of loop over M.
>       Pop the last 1 and 0.

Yang terakhir 01perlu muncul karena loop pergi ke titik akhir, yang bukan bagian dari output yang diinginkan. Perhatikan bahwa kita tidak bisa hanya mengurangi jumlah loop dengan 1. Jika tidak, untuk N > M, semua 0s dari iterasi terakhir akan hilang, sementara kita hanya perlu menyingkirkan yang terakhir 0.

Reto Koradi
sumber
1
Anda dapat menggunakan >untuk ;W<.
jimmy23013
@ jimmy23013 Ide bagus. Karena saya tahu bahwa saya memiliki 1di atas tumpukan, saya mungkin juga menggunakannya secara produktif.
Reto Koradi