Perangkat Kereta Sederhana

27

Ada banyak jenis rangkaian kereta, mulai dari trek kayu seperti Brio, hingga kontrol digital sepenuhnya, replika logam kecil dari kereta nyata, tetapi semuanya membutuhkan trek yang dirancang, idealnya menggunakan sebanyak mungkin karya Anda.

Jadi, tugas Anda adalah menentukan apakah, dengan masukan dari potongan-potongan yang tersedia, adalah mungkin untuk membangun sirkuit tertutup lengkap menggunakan semua elemen, dan jika tidak, berapa banyak potongan akan dibiarkan dari rangkaian maksimum yang dimungkinkan.

Karena ini adalah rangkaian kereta yang disederhanakan, hanya ada 3 elemen: kurva besar, kurva kecil, dan lurus. Ini semua didasarkan pada kotak persegi:

Kotak persegi menunjukkan kurva besar dan kurva kecil

  • "Kurva Besar" adalah sudut 90 derajat, yang mencakup 2 unit di setiap dimensi
  • "Kurva Kecil" adalah sudut 90 derajat, mencakup satu unit di setiap arah
  • "Lurus" adalah elemen lurus, panjang 1 unit

Ini berarti bahwa rangkaian minimum yang dimungkinkan terbentuk dari 4 kurva kecil - ini adalah lingkaran, dari jari-jari 1 unit. Ini dapat diperpanjang dengan menambahkan pasangan elemen lurus untuk membentuk berbagai oval. Ada sirkuit lain yang mungkin dengan menambahkan lebih banyak kurva, atau dengan mencampur jenis kurva.

Rangkaian kereta ini tidak termasuk persimpangan, atau metode apa pun untuk dilintasi trek, sehingga tidak berlaku untuk dua elemen untuk terhubung ke ujung yang sama dari elemen lain (tidak ada formasi Y) atau untuk saling silang (tidak ada formasi X) . Selain itu, ini adalah rangkaian kereta api, jadi setiap formasi yang tidak memungkinkan kereta untuk lewat tidak valid: contohnya termasuk pertemuan lurus di sudut 90 derajat (harus selalu ada kurva antara lurus tegak lurus) dan kurva pertemuan di sudut 90 derajat (kurva harus mengalir).

Anda juga ingin menggunakan sebanyak mungkin potongan, mengabaikan jenisnya, sehingga Anda akan selalu memilih sirkuit yang memiliki bit lebih banyak. Akhirnya, Anda hanya memiliki satu kereta, sehingga solusi apa pun yang menghasilkan banyak sirkuit tidak dapat diterima .

Memasukkan

Entah array tiga bilangan bulat, semuanya lebih besar dari atau sama dengan 0, yang sesuai dengan jumlah kurva besar, kurva kecil, dan lurus yang tersedia, atau parameter yang diteruskan ke program Anda, dalam urutan yang sama.

Keluaran

Sejumlah sesuai dengan jumlah potongan yang tersisa ketika rangkaian maksimum yang mungkin untuk elemen yang disediakan dibangun.

Uji data

Minimal circuit using big curves
Input: [4,0,0]
Output: 0

Slightly more complicated circuit
Input: [3,1,2]
Output: 0

Incomplete circuit - can't join
Input: [3,0,0]
Output: 3

Incomplete circuit - can't join
Input: [3,1,1]
Output: 5

Circuit where big curves share a centre
Input: [2,2,0]
Output: 0

Bigger circuit
Input: [2,6,4]
Output: 0

Circuit where both concave and convex curves required
Input: [8,0,0] or [0,8,0]
Output: 0

Circuit with left over bit
Input: [5,0,0] or [0,5,0]
Output: 1

Catatan

  • 2 lurus dan sedikit kurva sama dengan kurva besar, tetapi gunakan lebih banyak potongan, jadi lebih disukai - jangan pernah menjadi situasi di mana kombinasi ini dibiarkan, jika ada kurva besar di sirkuit
  • 4 kurva kecil biasanya dapat ditukar selama 4 lurus, tetapi tidak jika ini akan menyebabkan sirkuit untuk memotong sendiri
  • Set kereta juga diidealkan - elemen trek mengambil lebar yang ditunjukkan, sehingga valid untuk kurva untuk melewati kotak persegi tunggal tanpa berpotongan, dalam beberapa kasus. Grid hanya mendefinisikan dimensi elemen. Secara khusus, dua kurva besar dapat ditempatkan sehingga kotak kuadrat di kiri atas diagram contoh juga akan menjadi kuadrat kanan bawah dari kurva besar lain yang berjalan dari kiri ke atas (dengan diagram menunjukkan satu kurva berjalan dari kanan ke bawah)
  • Kurva kecil dapat masuk dalam ruang kosong di bawah kurva besar (kotak kanan bawah persegi di atas). Kurva besar kedua juga bisa menggunakan ruang itu, bergeser satu melintang dan satu turun dari yang pertama
  • Kurva kecil tidak dapat masuk pada ruang grid yang sama dengan bagian luar kurva besar - sebagian besar karena tidak ada cara untuk menyambungkannya yang tidak berpotongan secara ilegal
Matius
sumber
Jadi hasilnya untuk [5,0,0]atau [0,5,0]akan 1. Apakah itu benar? Bisakah Anda menambahkan test case seperti itu?
Arnauld
@arnauld Ya, itu benar. Harus selalu menjadi jumlah elemen yang tersisa setelah membangun sirkuit terpanjang yang mungkin.
Matius
Bisakah Anda mengonfirmasi bahwa ini adalah solusi untuk [8,0,0], dengan dua elemen 2x2 tumpang tindih di tengah grid?
Arnauld
Ya, itulah solusi yang diharapkan untuk test case itu.
Matius
Saya tidak jelas tentang bagaimana persimpangan diri bekerja. Bisakah Anda lebih eksplisit dalam mendefinisikan apa yang diizinkan dan apa yang dilarang?
Wheat Wizard

Jawaban:

9

[JavaScript (Node.js)], 1220 byte

f=r=>{var a=[{n:0,d:[[0,-1,"0000000101011"],[1,-1,"0011111111111"],[0,0,"0111101111111"],[1,0,"1100010000000"]],e:[2,-1,1]},{n:0,d:[[-1,-1,"1001111111111"],[0,-1,"0000010010110"],[-1,0,"0110000100000"],[0,0,"1101111011111"]],e:[-2,-1,3]},{n:1,d:[[0,0,"0011101111111"]],e:[1,0,1]},{n:1,d:[[0,0,"1001111011111"]],e:[-1,0,3]},{n:2,d:[[0,0,"1111101011111"]],e:[0,-1,0]}],e=r=>{var a=r.d,e=r.e,n=[];return a.forEach(r=>{var a=r[2];n.push([-r[1],r[0],""+a[10]+a[5]+a[0]+a[8]+a[3]+a[11]+a[6]+a[1]+a[9]+a[4]+a[12]+a[7]+a[2]])}),{d:n,e:[-e[1],e[0],e[2]]}};i=((r,a)=>{for(var n=0;n<r.d;n++,a=e(a));var p=!1;return a.d.forEach(a=>{var e=r[`${r.p.x+a[0]},${r.p.y+a[1]}`];void 0===e&&(e="00000000000000");for(var n="",d=0;d<13;d++)"1"===e[d]&&"1"===a[2][d]&&(p=!0),n+=e[d]===a[2][d]?e[d]:"1";r[`${r.p.x+a[0]},${r.p.y+a[1]}`]=n}),r.p.x+=a.e[0],r.p.y+=a.e[1],r.d=(r.d+a.e[2])%4,!p});var n=[],p=(r,e)=>{a.forEach(a=>{var d=Object.assign({},r);if(d.p=Object.assign({},r.p),!(e[a.n]<=0)&&i(d,a)){if(d.ps+=a.n,0==d.p.x&&0==d.p.y&&0==d.d)return void n.push(d);var s=Object.assign([],e);s[a.n]-=1,p(d,s)}})};p({p:{x:0,y:0},d:0,ps:""},Object.assign([],r));var d=0;n.forEach(r=>{r.ps.length>d&&(d=r.ps.length)}),console.log(r[0]+r[1]+r[2]-d)};

Cobalah online!

Catatan: Input sebenarnya adalah variabel q di awal. [2,6,4] juga akan memakan waktu cukup lama karena ini adalah solusi brute force tanpa optimisasi.

Saya benar-benar melakukan ini karena belum dijawab lebih dari setahun dan saya hanya ingin tahu apakah itu mungkin.


Kode Asli:

var q = [4, 2, 4];
var t = [
    {
        n: 0,
        d: [
            [0, -1, "0000000101011"],
            [1, -1, "0011111111111"],
            [0, 0, "0111101111111"],
            [1, 0, "1100010000000"]
        ],
        e: [2, -1, 1],

    },
    {
        n: 0,
        d: [
            [-1, -1, "1001111111111"],
            [0, -1, "0000010010110"],
            [-1, 0, "0110000100000"],
            [0, 0, "1101111011111"]
        ],
        e: [-2, -1, 3]
    },
    {
        n: 1,
        d: [
            [0, 0, "0011101111111"]
        ],
        e: [1, 0, 1]
    },
    {
        n: 1,
        d: [
            [0, 0, "1001111011111"]
        ],
        e: [-1, 0, 3]
    },
    {
        n: 2,
        d: [
            [0, 0, "1111101011111"]
        ],
        e: [0, -1, 0]
    },
];

r = (p) => {
    var d = p.d; var e = p.e; var o = [];
    d.forEach(i => {
        var d = i[2];
        o.push([-i[1], i[0], "" + d[10] + d[5] + d[0] + d[8] + d[3] + d[11] + d[6] + d[1] + d[9] + d[4] + d[12] + d[7] + d[2]])
    });
    return { d: o, e: [-e[1], e[0], e[2]] };
};

i = (g, p) => {
    //console.log(g.p, g.d);
    for (var i = 0; i < g.d; i++ , p = r(p));
    var c = false;
    p.d.forEach(d => {
        var v = g[`${g.p.x + d[0]},${g.p.y + d[1]}`];
        if (v === undefined) v = "00000000000000";
        var o = "";
        for (var i = 0; i < 13; i++) {
            if (v[i] === '1' && d[2][i] === '1')
                c = true;
            o += (v[i] === d[2][i]) ? v[i] : '1';
        }
        //console.log(o);
        g[`${g.p.x + d[0]},${g.p.y + d[1]}`] = o;
    });
    g.p.x += p.e[0];
    g.p.y += p.e[1];
    g.d = (g.d + p.e[2]) % 4;
    return !c;
};

var l = [];
var re = (g, p) => {
    t.forEach(piece => {
        var gr = Object.assign({}, g);
        gr.p = Object.assign({}, g.p);
        if (p[piece.n] <= 0)
            return;
        if (i(gr, piece)) {
            gr.ps += piece.n;
            if (gr.p.x == 0 && gr.p.y == 0 && gr.d == 0) {
                l.push(gr);
                return;
            }
            var ti = Object.assign([], p);
            ti[piece.n] -= 1;
            re(gr, ti);
        }
    });
};
var gr = { p: { x: 0, y: 0 }, d: 0, ps: "" };
re(gr, Object.assign([], q));

var c = 0;
var lo = 0;
l.forEach(g => {
    if (g.ps.length > lo) {
        require("./draw.js")(g, `outs/out${c++}.png`)
        lo = g.ps.length;
    }
});

console.log(q[0] + q[1] + q[2] - lo);

pertama saya harus menyertakan grafik dari ubin yang saya gunakan.

ubin yang digunakan

The sections of this tile were given a number and
used for comparison and overlap handling later.

So there first thing is the array t at the start. 
This is a collection of track pieces that contain
    n[ame]: the index of the input array.
    d[ata]: the offset from the current tile and the Tile bit values.
    e[nd]: the relative offset and rotation that the piece provides.

function r[otate] ( p[iece] )
    this outputs a piece that is rotated by 90 degrees
    by rearranging the tile bits and the end offset

function i[nsert] ( g[rid], p[iece] )
    this modifies the passed in grid trying to place down each tile of the piece.
    if it hits a point where 2 tiles intersect it sets a flag c[ollision]
    it then adjusts the current p[osition] and and d[irection] stored in the grid.
    then it returns !c[ollision]

function re[peat] ( g[rid], p[eices] )
    this iterates across all nodes which
        creates a copy of the g[rid] as gr[id].
        checks if the piece is available if not continue
        if the peice is added without a collision
            add piece name to gr[id].ps[piece string];
            it checks if its back at the start
                add gr[id] to l[ist]
                return as no more pieces can be added without a collision.
            clone peices remove the used peice ti[nput]
            call re[peate] (gr[id], ti[nput])

call re[peate] with empty grid

search l[ist] for longest piece string
and output input added together minus the length of the longest string.

Maaf jika penulisan sulit dibaca Saya tidak terbiasa menjelaskan cara kerja kode saya.

PS Saya sebenarnya juga membuat beberapa fungsi untuk menggambar peta ke png tapi tentu saja itu dihapus untuk menghemat setidaknya beberapa ruang.

Cieric
sumber
Saya terkesan - saya agak menyerah pada yang satu ini! Akan tertarik menulis
Matius
@ Matius, saya akan melihat ketika saya punya waktu untuk menulis satu. Sebenarnya mungkin butuh sedikit waktu. Tapi ya, biasanya ini adalah jenis puzzle favorit saya. Bahkan jika itu tidak singkat, itu menyenangkan untuk membuktikan itu mungkin.
Cieric
@Matthew menambahkan tulisan.
Cieric
Apakah ada alasan mengapa Anda memilih untuk menggunakan p[a.n]-=1bukan p[a.n]--?
Jonathan Frech
Inisialisasi qseperti itu bukan metode input yang diizinkan . Paling umum, baik membuatnya menjadi argumen fungsi atau membacanya dari stdin.
Ørjan Johansen