Conjunto de tren simplificado

27

Existen muchos tipos diferentes de juegos de trenes, que van desde pistas de madera como Brio, hasta el control totalmente digital de pequeñas réplicas metálicas perfectas de trenes reales, pero todos requieren un diseño de pista, idealmente usando la mayor cantidad de piezas posible.

Por lo tanto, su tarea es determinar si, dada la entrada de las piezas disponibles, es posible construir un circuito cerrado completo utilizando todos los elementos, y si no, cuántas piezas quedarán del máximo circuito posible.

Como se trata de un conjunto de trenes simplificado, solo hay 3 elementos: curva grande, curva pequeña y recta. Todos estos se basan en una cuadrícula cuadrada:

Cuadrícula cuadrada que muestra curva grande y curva pequeña

  • "Big Curve" es una esquina de 90 grados, que cubre 2 unidades en cada dimensión
  • "Little Curve" es una esquina de 90 grados, que cubre una unidad en cada dirección
  • "Recto" es un elemento recto, 1 unidad de largo

Esto significa que el circuito mínimo posible está formado por 4 pequeñas curvas: es un círculo, de radio 1 unidad. Esto puede extenderse agregando pares de elementos rectos para formar varios óvalos. Hay otros circuitos posibles agregando más curvas o mezclando los tipos de curva.

Este conjunto de trenes no incluye cruces ni métodos para que las pistas se crucen, por lo que no es válido que dos elementos se conecten al mismo extremo de otro elemento (sin formaciones Y) o se crucen entre sí (sin formaciones X) . Además, es un conjunto de trenes, por lo que cualquier formación que no permita que un tren pase no es válida: los ejemplos incluyen rectas que se encuentran en ángulos de 90 grados (siempre debe haber una curva entre rectas perpendiculares) y curvas que se encuentran en ángulos de 90 grados (las curvas deben fluir).

También desea utilizar tantas piezas como sea posible, ignorando de qué tipo son, por lo que siempre optará por un circuito que tenga más bits. Finalmente, solo tiene un tren, por lo que cualquier solución que dé como resultado múltiples circuitos es inaceptable .

Entrada

Ya sea una matriz de tres enteros, todos mayores o iguales a 0, correspondientes a la cantidad de curvas grandes, curvas pequeñas y rectas disponibles, o parámetros pasados ​​a su programa, en el mismo orden.

Salida

Un número correspondiente al número de piezas sobrantes cuando se construye el circuito máximo posible para los elementos proporcionados.

Datos de prueba

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

Notas

  • 2 rectas y una pequeña curva son equivalentes a una curva grande, pero use más piezas, por lo que son preferibles, nunca debería ser una situación en la que se deje esta combinación, si hay curvas grandes en el circuito
  • Por lo general, se pueden intercambiar 4 pequeñas curvas por 4 rectas, pero no si esto haría que el circuito se intersecara
  • El conjunto de trenes también está idealizado: los elementos de la vía ocupan los anchos mostrados, por lo que es válido que las curvas pasen a través de un único cuadrado de la cuadrícula sin cruzarse, en algunos casos. La cuadrícula solo define las dimensiones del elemento. En particular, se pueden colocar dos curvas grandes para que el cuadrado de la cuadrícula en la parte superior izquierda del diagrama de ejemplo también sea el cuadrado inferior derecho de otra curva grande que se ejecuta de izquierda a arriba (con el diagrama que muestra una que se ejecuta de derecha a abajo)
  • Una pequeña curva puede caber en el espacio vacío debajo de una gran curva (cuadrícula inferior derecha arriba). Una segunda gran curva también podría usar ese espacio, desplazada una a través y otra hacia abajo desde la primera
  • Una curva pequeña no puede caber en el mismo espacio de la cuadrícula que el exterior de una curva grande, principalmente porque no hay forma de conectarse a ella que no se cruce ilegalmente
Mateo
fuente
Entonces la salida para [5,0,0]o [0,5,0]sería 1. ¿Es eso correcto? ¿Podría agregar un caso de prueba?
Arnauld
@arnauld Sí, eso es correcto. Siempre debe ser el número restante de elementos después de construir el circuito más largo posible.
Mateo
¿Podría confirmar que esta es una solución [8,0,0], con dos elementos de 2x2 superpuestos en el centro de la cuadrícula?
Arnauld
Sí, esa es la solución esperada para ese caso de prueba.
Mateo
No tengo claro cómo funciona la auto-intersección. ¿Podría ser más explícito al definir qué está permitido y qué está prohibido?
Wheat Wizard

Respuestas:

9

[JavaScript (Node.js)], 1220 bytes

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

Pruébalo en línea!

Nota: La entrada es en realidad la variable q al inicio. [2,6,4] también llevará bastante tiempo ya que esta es una solución de fuerza bruta sin optimizaciones.

Realmente hice esto porque no ha sido respondido en más de un año y tenía curiosidad de saber si era posible.


Código original

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

Primero debo incluir un gráfico de los mosaicos que utilicé.

azulejos utilizados

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.

Lo siento si la redacción es difícil de leer, no estoy acostumbrado a explicar cómo funciona mi código.

PD: Realmente también hice algunas funciones para dibujar los mapas en un png, pero por supuesto se eliminaron para ahorrar al menos algo de espacio.

Cierico
fuente
Estoy impresionado, ¡había perdido la esperanza en este caso! Estaría interesado en una redacción
Matthew
@Matthew Veré cuando tenga tiempo de escribir uno. En realidad, podría tomar un poco de tiempo. Pero sí, normalmente estos son mis tipos favoritos de rompecabezas. Incluso si no es corto, es divertido demostrar que es posible.
Cieric
@Matthew agregó la escritura.
Cieric
¿Hay alguna razón por la que elegiste usar en p[a.n]-=1lugar de p[a.n]--?
Jonathan Frech
Inicializar qasí no es un método de entrada permitido . Lo más común es convertirlo en un argumento de función o leerlo desde stdin.
Ørjan Johansen