Set treno semplificato


27

Esistono molti tipi diversi di set di treni, che vanno dai binari in legno come Brio, al controllo completamente digitale, perfette repliche metalliche minuscole di treni reali, ma richiedono tutti un binario da progettare, utilizzando idealmente il maggior numero possibile di pezzi.

Quindi, il tuo compito è determinare se, dato l'ingresso dei pezzi disponibili, è possibile costruire un circuito chiuso completo usando tutti gli elementi e, in caso contrario, quanti pezzi rimarranno dal circuito massimo possibile.

Poiché si tratta di un set di treni semplificato, ci sono solo 3 elementi: curva grande, curva piccola e diritto. Questi sono tutti basati su una griglia quadrata:

Griglia quadrata che mostra grande curva e piccola curva

  • "Big Curve" è un angolo di 90 gradi, che copre 2 unità in ogni dimensione
  • "Little Curve" è un angolo di 90 gradi, che copre un'unità in ogni direzione
  • "Straight" è un elemento dritto, lungo 1 unità

Ciò significa che il circuito minimo possibile è formato da 4 piccole curve - è un cerchio, di raggio 1 unità. Questo può essere esteso aggiungendo coppie di elementi diritti per formare vari ovali. Ci sono altri circuiti possibili aggiungendo più curve o mescolando i tipi di curva.

Questo set di treni non include alcun incrocio o metodo per l'attraversamento dei binari, quindi non è valido per due elementi collegarsi alla stessa estremità di un altro elemento (nessuna formazione Y) o incrociarsi l'uno con l'altro (nessuna formazione X) . Inoltre, è un insieme di treni, quindi qualsiasi formazione che non consente il passaggio di un treno non è valida: gli esempi includono rettilinei che si incontrano ad angoli di 90 gradi (deve esserci sempre una curva tra rettilinei perpendicolari) e curve che si incontrano ad angoli di 90 gradi (le curve devono fluire).

Vuoi anche usare il maggior numero possibile di pezzi, ignorando il loro tipo, quindi sceglierai sempre un circuito con più bit. Infine, hai solo un treno, quindi qualsiasi soluzione che si traduce in più circuiti è inaccettabile .

Ingresso

Un array di tre numeri interi, tutti maggiori o uguali a 0, corrispondenti al numero di curve grandi, curve piccole e rettilinei disponibili o parametri passati al programma, nello stesso ordine.

Produzione

Un numero corrispondente al numero di pezzi rimasti quando viene costruito il circuito massimo possibile per gli elementi forniti.

Dati di test

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

Gli appunti

  • 2 rettilinei e una piccola curva equivalgono a una grande curva, ma usano più pezzi, quindi sono preferiti - non dovrebbe mai essere una situazione in cui questa combinazione viene lasciata, se ci sono grandi curve nel circuito
  • Di solito 4 piccole curve possono essere scambiate con 4 rettilinei, ma non se ciò causasse l'intersezione del circuito
  • Anche il set di treni è idealizzato: gli elementi del binario occupano le larghezze mostrate, quindi è valido per le curve passare attraverso un singolo quadrato della griglia senza intersecarsi, in alcuni casi. La griglia definisce solo le dimensioni dell'elemento. In particolare, è possibile posizionare due grandi curve in modo che il quadrato della griglia in alto a sinistra del diagramma di esempio sia anche il quadrato in basso a destra di un'altra grande curva che corre da sinistra verso l'alto (con il diagramma che mostra uno che corre da destra a fondo)
  • Una piccola curva può adattarsi allo spazio vuoto sotto una grande curva (griglia in basso a destra sopra). Una seconda grande curva potrebbe anche usare quello spazio, spostato di uno e uno in basso rispetto al primo
  • Una piccola curva non può adattarsi allo stesso spazio della griglia all'esterno di una grande curva, principalmente perché non c'è modo di connettersi ad essa che non si intersecano illegalmente

Quindi l'output per [5,0,0]o [0,5,0]sarebbe 1. È corretto? Potresti aggiungere un simile test?
Arnauld,

@arnauld Sì, è corretto. Dovrebbe essere sempre il numero rimanente di elementi dopo aver creato il circuito più lungo possibile.
Matteo,

Potresti confermare che questa è una soluzione per [8,0,0], con due elementi 2x2 sovrapposti al centro della griglia?
Arnauld,

Sì, questa è la soluzione prevista per quel test.
Matteo,

Non sono chiaro su come funzioni l'autointersezione. Potresti essere più esplicito nel definire cosa è permesso e cosa è proibito?
Mago del grano

Risposte:


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)};

Provalo online!

Nota: l'ingresso è in realtà la variabile q all'inizio. [2,6,4] richiederà anche un bel po 'di tempo in quanto si tratta di una soluzione di forza bruta senza ottimizzazioni.

In realtà l'ho fatto perché non mi è stata data risposta da oltre un anno ed ero solo un po 'curioso se fosse possibile.


Codice originale:

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);

per prima cosa dovrei includere un grafico delle tessere che ho usato.

piastrelle utilizzate

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.

Scusate se la scrittura è difficile da leggere Non sono abituato a spiegare come funziona il mio codice.

PS In realtà ho anche creato alcune funzioni per disegnare le mappe su un png, ma ovviamente queste sono state rimosse per risparmiare almeno un po 'di spazio.


Sono impressionato - avrei rinunciato a sperare in questo! Sarebbe interessato a scrivere un articolo
Matteo,

@Matthew vedrò quando avrò il tempo di scriverne uno. In realtà potrebbe volerci un po 'di tempo. Ma sì, normalmente questi sono i miei tipi di puzzle preferiti da fare. Anche se non è breve, è divertente dimostrare che è possibile.
Cieric,

@Matthew ha aggiunto il commento.
Cieric,

C'è un motivo per cui hai scelto di utilizzare p[a.n]-=1invece di p[a.n]--?
Jonathan Frech,

Inizializzare in qquesto modo non è un metodo di input consentito . Più comunemente, rendilo un argomento di funzione o leggilo da stdin.
Ørjan Johansen,
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.