Kereta Lego Gear

13

Terinspirasi oleh tantangan rasio roda gigi Lego oleh Keith Randall.

Saya juga berencana membangun robot lego raksasa yang pada akhirnya akan dapat menghancurkan robot lain dalam kompetisi yang tidak pernah disebutkan sebelumnya. * Dalam proses membangun robot, saya akan menggunakan banyak kereta roda gigi untuk menghubungkan bagian-bagian berbeda dari robot. Saya ingin Anda menulis kepada saya program terpendek yang akan membantu saya membangun kereta roda gigi rumit yang diperlukan untuk tugas yang begitu rumit. Saya, tentu saja, hanya akan menggunakan roda gigi dengan jari-jari 1, 2, 3, dan 5 unit-sewenang-wenang.

Setiap gigi di gir kereta memiliki koordinat bilangan bulat tertentu pada kisi 2D. Gigi pertama terletak di (0,0) dan gigi akhir akan berada di koordinat non-negatif. Lokasi dan ukuran roda gigi pertama dan terakhir akan diberikan sebagai input, program Anda harus memberi tahu roda gigi mana yang harus diisi untuk mengisi celah tersebut.

Selain itu, program Anda harus menggunakan jumlah roda gigi minimum yang mungkin dalam kereta roda gigi. Lebih sedikit roda gigi / kereta = lebih banyak kereta ** = robot pemusnah yang lebih besar dan lebih baik.

Input akan terdiri dari satu baris:

X,Y,B,A

X dan Y adalah koordinat gigi akhir. Gigi pertama selalu berada di (0,0). B dan A adalah jari-jari roda gigi akhir dan awal, masing-masing. Untuk menambah kesulitan, Anda perlu memastikan bahwa roda gigi keluaran berputar ke arah yang benar. Jika A dan B memiliki tanda yang sama, maka gir keluaran perlu berputar ke arah yang sama, dan gir gir harus digunakan. Jika mereka memiliki tanda-tanda yang berlawanan, maka sejumlah gigi perlu digunakan.

Keluaran harus berupa daftar lokasi X, lokasi Y, dan jari-jari setiap gigi tambahan, satu gigi per baris. Jika ada beberapa solusi roda gigi minimal, cetak hanya satu pilihan Anda. Urutan roda gigi dalam output tidak masalah.

Contoh (solusi yang lebih setara mungkin):

in
4,0,1,1
out
2,0,1

in
7,7,-2,-2
out
4,3,3
OR
0,7,5
OR
the above reflected over y=x line

in
7,8,-1,2
out
7,0,5
7,6,1
OR
7,0,5
1,8,5

in
7,7,2,-2
out
4,-3,3
7,1,2
12,1,3
12,7,3
OR
any permutation of the above, or reflected over y=x line
Now you're thinking with gear trains!

Inilah solusi untuk contoh di atas, divisualisasikan:

masukkan deskripsi gambar di sini

Sejauh yang saya tahu, tidak ada masalah tidak mungkin kecuali dua gigi input tumpang tindih atau langsung terhubung. Anda tidak perlu berurusan dengan ini.

Ini kode golf, jawaban terpendek menang.


* KOTH masa depan, siapa pun?

** CHOO CHOO !!

PhiNotPi
sumber
Saya ingin agar jari-jari awal dan akhir bisa negatif.
wizzwizz4
9
Selamat datang di Tantangan Lego Gear Kereta Phi. Setelah 4 tahun di Sandbox, semoga saja sepadan dengan beratnya.
sebuah spaghetto
@ wizzwizz4 Membuat perubahan.
PhiNotPi
Apakah ini benar-benar di kotak pasir selama 4 tahun?
Rɪᴋᴇʀ
@RikerW Lebih mirip 3 1/3.
PhiNotPi

Jawaban:

1

C #, 660 byte

using System.Linq;using System;class P{int p=1,x,y,r;P l;static void Main(){var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V";var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();int i=0,t,s=7,u,v,w,p=I[3]*I[2];for(var D=new[]{new P{r=Math.Abs(I[3]),l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3}}}.ToList();i>=0;){P c=D[i++],l=c.l;for(;(l=l?.l)!=null&&(s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;);if(s==0&&l.p>2&p*c.p<0)for(i=-1;c.l.p<3;c=c.l)Console.WriteLine(c.x+","+c.y+","+c.r);for(t=0;s>0&t<66;t++)for(u=Q[t++]-36,v=Q[t++]-36,s=1;s++<5&Q[t]%9==c.r;w=u,u=v,v=-w,D.Add(new P{l=c,r=Q[t]/9-4,x=c.x+u,y=c.y+v,p=-c.p}));}}}

Cobalah secara Online

Ini adalah banyak menyenangkan !! Program yang lengkap, menerima input dari STDIN, output ke STDOUT. Keluaran adalah roda gigi secara berurutan dari ujung hingga awal. Pemakaian:

Melakukan Pencarian Pertama Breadth sederhana, yang memecahkan masalah 4-gigi dalam waktu kurang dari satu detik. Faktor percabangan sebenarnya tidak terlalu besar, jadi itu harus baik untuk lebih banyak (tidak benar-benar mengujinya). Sayangnya menggunakan Linq.

The Qstring adalah tabel semua koneksi gigi diperbolehkan (yaitu sebuah r=3dan terhubung ke r=1jika dx=4dan dy=0) dalam satu kuadran, yang kemudian diputar untuk menemukan orang lain. Setiap set 3 byte adalah dx, dy, dan informasi radius untuk koneksi hukum. Pilihan (sebagai penyeimbang sangat disengaja: menyenangkan sekali untuk memilih karakter ASCII untuk properti bagus, daripada mati-matian mencoba mencari properti bagus untuk karakter ASCII yang dikenakan.

Saya mungkin bisa melakukan pekerjaan yang lebih baik membaca input, tapi saya belum beruntung, paling tidak karena Linq dibayar oleh kebutuhan untuk daftar. Saya juga sangat kecewa dengan kode rotate, saya merasa seperti itu bisa dilakukan dalam byte yang jauh lebih sedikit.

Kode yang diformat dan Dikomentari dengan Qgenerator:

using System.Linq; // seems to pay today
using System;

class P
{
    static void GenQ()
    {
        int t, k = 0, m = 0;
        Func<P, P, int> C = (P c, P l) => (t = c.x - l.x) * t + (t = c.y - l.y) * t - (t = c.r + l.r) * t; // ==0 -> touching, <0 -> not touching, >0 -> overlap

        string str = "";

        string T(int i) => "" + (char)('$' + i); // $ is zero, '$' == 36, so we can mod and div by 9, and greater than " so we don't have to escape it

        foreach (int r in new[] { 1, 2, 3, 5 }) // at 0,0 (current gear)
            foreach (int s in new[] { 1, 2, 3, 5 }) // gear to place
                for (int i = 0; i <= r + s; i++) // x
                    for (int j = 1; j <= r + s; j++, m++) // y
                        if (C(new P { r = r }, new P { r = s, x = i, y = j }) == 0) // 
                        {
                            str += T(i) + T(j) + T(r + s * 9);
                            k++;
                        }

        System.Console.WriteLine("K : " + k);
        System.Console.WriteLine("M : " + m);
        System.Console.WriteLine(str);
        System.Console.ReadKey(true);
        return;
    }

    int p=1, // parity
        x, // x
        y, // y
        r; // radias (TODO: store radias^2 ?)
    P l; // previous in search list

    static void Main()
    {
        //GenQ();

        // '$' == 36 (4*9)
        // 3char blocks: x,y,r+9*s
        var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V"; // quarter table

        // primative read ints
        var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();

        int i=0, // position in Due
            t, // check differential cache, position in Q
            s=7, // check cache, rotation counter (>0)
            u, // rotation x
            v, // rotation y
            w, // rotation x cache
            p=I[3]*I[2]; // parity (>0 -> same, even ; <0 -> different, odd)

        // due (not point using a queue, the search space grows exponentially)
        for(var D=new[]{
                new P{r=Math.Abs(I[3]), // start (p==1)
                    l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3} // terminal (detect with p==3)
                }}.ToList();
            i>=0;) // infinite number of configurations, no bounds, i is escape term
        {
            P c=D[i++], // current
                l=c.l; // check, initially the one before the previous (we know we are touching last already)

            // 'checks' c against l
            //Func<int>C=()=>(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t; // ==0 -> touching, >0 -> not touching, <0 -> overlap

            // check we arn't touching any before us (last thing we check is terminal)
            for(;(l=l?.l)!=null&& // for each before us (skipping the first one)
                (s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;); // check c against l and cache in s, ==0 -> touching, >0 -> not touching, <0 -> overlap

            if(s==0&& // touching last checked?
                l.p>2& // stopped on terminal?
                p*c.p<0) // correct parity? -> win
                for(i=-1; // escape
                    c.l.p<3;c=c.l) // for each that wasn't the first
                    Console.WriteLine(c.x+","+c.y+","+c.r);

            // enumerate possible additions, and queue them in due
            for(t=0;
                s>0& // not touching or overlapping anything (including terminal)
                t<66;t++) // 66 = Q.Length
                for(
                    u=Q[t++]-36, // '$'
                    v=Q[t++]-36,
                    s=1;s++<5& // rotate 4 times
                    Q[t]%9==c.r; // our raidus matches
                        w=u, // chache y value
                        u=v, // rotate
                        v=-w,
                        D.Add(new P // add
                        {
                            l=c,
                            r=Q[t]/9-4, // radius
                            x=c.x+u,
                            y=c.y+v,
                            p=-c.p // flip parity
                        }));
        }
    }
}
VisualMelon
sumber