Cubificatore più efficiente


19

Cubically è troppo noioso per scrivere manualmente qualsiasi codice. La tua sfida è tradurre il testo ASCII in codice cubicamente sorgente.

cubica

Questo è solo un breve riassunto di Cubically; il repository ha una guida e dettagli più completi.

Cubically è un esolang che ho scritto qualche tempo fa, progettato per essere doloroso da usare. Contiene due pezzi di memoria, un cubo di Rubik 3x3x3 e un registro chiamato "blocco note".

Memoria

Il cubo di Rubik interno è inizializzato in questo modo:

   000
   000          top face
   000
111222333444    left, front, right, and back faces, respectively
111222333444
111222333444
   555
   555          down face
   555

Dopo aver eseguito una rotazione di 90 ° in senso orario sulla faccia destra, il cubo di memoria sarebbe simile al seguente:

   002
   002
   002
111225333044
111225333044
111225333044
   554
   554
   554

comandi

Un carattere non intero imposta il comando predefinito. Per ogni numero intero prima che il comando predefinito venga nuovamente impostato, il comando viene eseguito con quel numero intero. Ad esempio, x524y312esegui il comando xcon 5, quindi con 2, quindi con 4, quindi esegue il comando ycon 3, quindi con 1, quindi con 2.

I numeri interi che utilizzano i comandi rappresentano gli indici dei volti. Quindi x0si esibirà xsulla faccia UP (indicizzata 0). x1si esibirà xsulla faccia SINISTRA (1-indicizzata) e così via.

L'esecuzione di qualsiasi comando con 6eseguirà quel comando sul valore del blocco note. L'esecuzione di qualsiasi comando con un numero intero superiore a 6 comporterà un errore.

Ecco alcuni comandi di esempio:

  • R1 - ruotare la faccia DESTRA di 90 ° in senso orario in modo che il cubo interno sia simile al secondo esempio sopra
  • R11 - ruotare la faccia DESTRA di 90 ° in senso orario due volte, identico a R2
  • +0 - aggiungi tutti i valori della faccia SU al blocco note
  • +000 - aggiungi tre volte tutti i valori della faccia SU al blocco note
  • @6 - stampa la faccia (memoria) inesistente del 6 ° indicizzato come carattere
  • %4 - stampa la somma di tutti i valori sulla faccia INDIETRO come un numero intero

Un elenco completo di comandi e sintassi è disponibile nel repository .

Sfida

Prenderai il testo ASCII come input e stamperai un programma cubico come output.

Esempi (rubati da qui e qui ):

Input -> Output
Hello, World! -> +53@6+1F2L2+0@6L2F2U3R3F1L1+2@66L3F3R1U1B3+0@6:4U1R1+00@6-000@6*0-4+000@6-00@6+2-000000@6-5+4000@6-00@6/0+00@6:0+0/0+00@6
1$2$3$4$5$6$7$8$9$10$ -> B1+2/2%6@4+00/0%6@4+00/1%6@4+21/1%6@4+30/0%6@4+22/1%6@4+22/1%6@4+40/1%6@4+52/1%6@4+42/1%6@4

Regole

  • Il tuo programma potrebbe non contenere un dizionario contenente le traduzioni per le 100 prove.
  • Il programma deve terminare in meno di 180 secondi (nessun programma di forza bruta che richiede settimane).
  • Il programma deve generare un codice cubico valido che termina in meno di 180 secondi.
  • Il tuo programma prenderà l'input tramite l'input standard, a meno che tu non voglia fare confusione con il driver di test.
  • Il tuo programma deve generare codice cubico che non produce altro che l'input del tuo programma quando eseguito. ಠ_ಠ

punteggio

Testerai il tuo programma con 100 stringhe pseudocasuali di lunghezza pseudocasuale. (Viene fornito uno script bash che farà questo per te.) Ecco come segnerai:

  • Lascia che la lunghezza del programma di output sia o .
  • Lascia che la lunghezza della stringa di input sia l .
  • Lascia che una variabile r sia il risultato di o / l .
  • Trova la media di tutti r : (r 1 + r 2 + r ... + r 100 ) / 100 .

Prova con questo script. Dovrai modificarlo secondo le istruzioni. Si noti che il programma non verifica se l'output è un codice cubico valido. Se non riesci a far funzionare la sceneggiatura, posso aiutarti. Fai un rumore metallico nella chat room cubica .



" @6- stampa la somma della faccia inesistente del 6 ° indicizzato (blocco note) come carattere" sarebbe più precisa? È %4anche una somma? I +comandi sommano la faccia quindi lo aggiungono a tutti i valori o ...?
Jonathan Allan,

@JonathanAllan @6/ %6stampa direttamente il valore del blocco note come carattere / intero. @x/ %x(dove x è una faccia esistente) aggiunge tutti i valori sulla xfaccia non indicizzata e stampa la somma come carattere / intero. +aggiunge tutti i valori sulla faccia specificata al registro.
MD XF,

Ah, per qualche ragione stavo pensando che anche il blocco note avesse 9 valori.
Jonathan Allan,

Risposte:


4

C ++ 11, Punteggio : 6.37

#include <iostream>
#include <vector>
#include <array>
#include <limits>
#include <algorithm>

const int inf = std::numeric_limits<int>::max(),
maxDiff = 128, nFace = 6;
std::array<int, maxDiff+1> plusvalue, totalvalue, plustrace, totaltrace;
std::array<int, nFace> input;

void prtrace(int value) {
    while (value) {
        std::cout << plustrace[value];
        value -= input[plustrace[value]];
    }
}

void prexpr(int i) {
    char xorwt = 0;
    if (i < 0) {
        xorwt = '+' ^ '-';
        i = -i;
    }
    if (totalvalue[i] != 0 && totalvalue[i] != inf) {
        std::cout << (char)('+' xor xorwt);
        prtrace(totaltrace[i]);
        if (totaltrace[i] != i) {
            std::cout << (char)('-' xor xorwt);
            prtrace(totaltrace[i] - i);
        }
    }
}

int main() {
    std::cout << "RU";
    input = {6, 15, 27, 26, 19, 42};
    std::cin >> std::noskipws;

    std::fill(plusvalue.begin(), plusvalue.end(), inf);
    plusvalue[0] = 1; // '+'
    for (int i = 0; i < nFace; ++i) { // knapsack, each value repeated inf times
        int val = input[i];
        if (val == 0) continue;
        for (int p = 0; p <= maxDiff - val; ++p) {
            if (plusvalue[p] != inf && plusvalue[p + val] > plusvalue[p] + 1) {
                plusvalue[p + val] = plusvalue[p] + 1;
                plustrace[p + val] = i;
            }
        }
    }
    for (int p = 0; p <= maxDiff; ++p) totalvalue[p] = plusvalue[p], totaltrace[p] = p;
    totalvalue[0] = 0;
    for (int sub = 1; sub <= maxDiff; ++sub) {
        if (plusvalue[sub] == inf) continue;
        for (int p = 0; p <= maxDiff - sub; ++p) {
            if (plusvalue[p+sub] != inf && totalvalue[p] > plusvalue[p+sub] + plusvalue[sub]) { // include '+'s
                totalvalue[p] = plusvalue[p+sub] + plusvalue[sub];
                totaltrace[p] = p+sub;
            }
        }
    }

//    // Note: plustrace[x] = i<=nFace : plustrace[x-input[i]] + 1 = plustrace[x]
//    long long sum = 0;
//    for (int i = 0; i <= maxDiff; ++i) {
//        sum += totalvalue[i];
//        std::cout << i << '\t' << totalvalue[i] << '\t';
//        prexpr(i);
//        std::cout << '\n';
//    }
//
//    std::cout << "_______________________________\n\nAverage = " << sum / (maxDiff + 1.) << '\n';

// RU 3.98131

    char ch;
    int cur = 0;
    while (std::cin >> ch) {
        int diff = ch - cur;
        prexpr(diff);
        std::cout << "@6";
        cur += diff; // cur = ch
    }
}

/*
RU 3.98131
*/

Provalo online! (genera codice cubico da ASCII) e (esegue codice cubico)

Spiegazione:

  • Innanzitutto il programma stampa "RU", che fa la somma del viso da {0,9,18,27,36,45}a {6, 15, 27, 26, 19, 42}. Ciò che rende utile l'insieme di somma delle facce è che gcd è 1, quindi dall'identità di Bézout esiste un modo per costruire qualsiasi numero dda una somma (o differenza) di quei numeri.
  • Pertanto, se il carattere successivo è che il valore del blocco note corrente è n, allora let d = ch - n, possiamo eseguire comandi cubici nella forma in +{digits from 0 to 5}-{digits from 0 to 5}modo che il valore del blocco note diventi ch. Quindi esegui semplicemente %6per stampare il valore del blocco note.
  • Per trovare il modo più efficiente di esprimere dcome somma / differenza di numeri nel set di facce, uso l'algoritmo Knackack per tutti i numeri da 0 a 128. Ad esempio, per d=1, il programma ottiene 27 - 26 = 1, quindi stampa +2-3, che è 27 - 26 = 1. Che può essere visto quando si esegue il programma con input abc, output del programma

    RU + 4333 @ 6 + 2-3 @ 6 + 2-3 @ 6


Woah, ottimo lavoro! L'algoritmo Knapsack è quello che stavamo cercando, immagino.
TehPers,

Si noti che a causa degli aggiornamenti della lingua, è possibile ottenere un punteggio migliore chiamando @implicitamente - @6può essere abbreviato @in tutti i casi.
MD XF,

17

Lua, Punteggio : 85,91 13,50 13,20 12,70 9,41 9,32 9,83 9,66 9,12 9,06 8,03 (Media)

-- Get input
local inp = io.read("*a")

local out = ""
local faces = { [5] = 45, [4] = 36, [3] = 27, [2] = 18, [1] = 9 }
local lastChar = nil

-- Mode the program is in
-- 2 = not set (needs :), 1 = just set (needs +), 0 = normal
local mode = 1;
for i = 1, inp:len() do
  -- Character value at current position
  local c = string.byte(inp, i)

  if c == lastChar then
    -- Repeat character
    out = out .. "6"
  elseif c % 9 == 0 and c <= 45 then
    if #out == 0 then
      out = out .. "@"
    end
    out = out .. (c / 9)
  else
    local c2 = c

    -- Handle if difference from lastChar is divisible by 9
    if lastChar and (c - lastChar) % 9 == 0 then
      local difference = c - lastChar
      if difference > 0 then
        out = out .. "+"
      else
        out = out .. "-"
        difference = difference * -1
      end

      for index = 5, 1, -1 do
        local face = faces[index]
        while difference >= face do
          difference = difference - face
          out = out .. index
        end
      end
      c = 0
    end

    -- Handle anything not divisible by 9
    local extra = c % 9
    if extra > 0 then
      -- Try to optimize by dividing by 9, if possible
      if lastChar and math.floor(lastChar / 9) == extra then
        out = out .. "/1"
        mode = 1
        extra = 0
      else
        while extra > 0 do
          local n = extra > 5 and 5 or extra

          if mode == 2 then
            out = out .. ":"
            mode = 1
          elseif mode == 1 then
            out = out .. "+"
            mode = 0
          end
          out = out .. n
          extra = extra - n
        end
        out = out .. "/1"
        mode = 1
      end

      c = c - (c % 9)
    end

    -- Handle anything divisible by 9
    for index = 5, 1, -1 do
      local face = faces[index]
      while c >= face do
        if mode == 2 then
          out = out .. ":"
          mode = 1
        elseif mode == 1 then
          out = out .. "+"
          mode = 0
        end
        c = c - face
        out = out .. index
      end
    end

    out = out .. "@6"
    lastChar = c2
  end

  mode = 2
end
print(out)

Provalo online!

Ok, non credo di poterlo ottimizzare più.

Questa versione scorre attraverso ogni personaggio, aggiungendo c% 9 (dove c è il valore decimale del personaggio) facendo :5+2/1, quindi aggiunge le parti divisibili per 9 aggiungendo il valore di quella faccia. Ad esempio: :2/1+551@per stampare "e", dove :2/1aggiunge 2, +551aggiunge 99 (9 * (5 + 5 + 1) o 9 * 11) e @stampa l'output. L'input viene letto con io.read().

Le ottimizzazioni includono l'aggiunta / sottrazione diretta dopo la stampa se la differenza tra i caratteri è un multiplo di 9, dividendo il valore corrente se possibile anziché impostare c% 9 da zero e ripetendo i caratteri stampando nuovamente il valore corrente anziché ricalcolo. Inoltre, ho implementato il metodo di Kamil per stampare istantaneamente qualsiasi faccia che contiene già il valore target e il suggerimento di MD XF di non utilizzare :all'inizio, ma invece di iniziare con un +.


1
Puoi sempre commentare le tue domande e risposte, ma non hai ancora i privilegi di commento generali. Non dovrebbe essere lungo con risposte come questa (o, più probabilmente, solo questa risposta una volta che alcune altre persone lo vedono)
Kamil Drakari,

2
@MDXF Non sono poi così gentile: P
Kamil Drakari,

1
Puoi cambiare local inp = io.read()in local inp = io.read("*all"). Questo risolve il problema.
MD XF,

1
Un'altra possibile ottimizzazione: poiché il blocco note inizia da 0, in realtà non è necessario eseguire l'output, ad esempio :5+124, è possibile semplicemente scrivere +5124, il che probabilmente ridurrà un po 'il punteggio se lo si modifica correttamente.
MD XF,

1
Probabilmente otterrai un punteggio migliore se cambi la tua risposta per supportare alcuni dei recenti aggiornamenti di Cubically, come i volti impliciti.
MD XF,

16

Cubicamente , Punteggio : 86,98

U3D1R3L1F3B1U1D3~:7+1(-1@3(-1%1)6:1+3111@6%1-31111+004@6:1+11111%6:1+45@6:1-1%6~:7+1)6 

Provalo online!

Risulta che tutto ciò di cui hai bisogno sono loop condizionali, una faccia uguale a 1 e un comportamento coerente di fine input.

U3D1R3L1F3B1U1D3     set LEFT face sum to 1
~:7                  read input, set notepad to input
+1                   add 1 to notepad

(                    open loop that can always be jumped to
 -1                   subtract 1 from notepad
 @3                   print RIGHT face (ASCII 43 '+')

            ##   the following mechanism gets the output program's   ##
            ##   notepad to the current inputted ASCII value:        ##

 (                    open loop that can always be jumped to
  -1                   subtract 1 from notepad
  %1                   print '1'
 )6                   jump back to loop while notepad is nonzero

            ##   the following mechanism prints "/1@6:1"             ##

 :1+3111@6            set notepad to 47,    print (ASCII 47 '/')
 %1                   print LEFT face       print (integer '1')
 -31111+004@6         set notepad to 64,    print (ASCII 64 '@')
 :1+11111%6           set notepad to 6,     print (integer 6)
 :1+45@6              set notepad to 58,    print (ASCII 58 ':')
 :1-1%6               set notepad to 0,     print (integer 1)

 ~                    read input
 :7+1                 set notepad to input plus 1, so EOF changes to zero
)6                    loop if notepad is truthy

L'aggiunta / sottrazione della faccia SINISTRA consiste nel far terminare il loop quando viene letto EOF.


2
Hai ottenuto di essere scherzando. Questo è incredibile.
MD XF,

Oh hey, ha anche un punteggio migliore della mia risposta C # originale!
Kamil Drakari il

Nota che grazie agli aggiornamenti della lingua, puoi ottenere un punteggio migliore chiamando @implicitamente - @6può essere abbreviato @in tutti i casi.
MD XF,

9

C # (.NET Core) , Punteggio: 129,98 11,73 10,82 9,62 10,33 10,32 10,20

-1.2 punto dal suggerimento di MD XF da utilizzare @6666...anziché @6@6@6@6...per la ripetizione del carattere e una sequenza di inizializzazione superiore

static void Main()
{
	List<byte> input = new List<byte>();
            int inChar = Console.Read();
            while (inChar != -1)
            {
                input.Add((byte)inChar);
                inChar = Console.Read();
            }


            Console.Write("U3D1R3L1F3B1U1D3");
            byte[] sides = new byte[] { 20, 1, 14, 43, 24, 33 };

            byte currentChar = 0;

   	    if(currentChar == input[0] || sides.Contains(input[0])) Console.Write("@");

            foreach (byte character in input)
            {
		if (currentChar == character)
		{
			Console.Write("6");
			continue;
		}
		
		if (sides.Contains(character))
		{
			Console.Write(Array.IndexOf(sides, character));
			continue;
		}
                if (currentChar < character)
                {
                    Console.Write("+");
                    while (currentChar < character)
                    {
                        byte nextAdd = sides.Where(s => s + currentChar <= character).Max();
                        currentChar = (byte)(currentChar + nextAdd);
                        Console.Write(Array.IndexOf(sides, nextAdd));
                    }
                }

                if (currentChar > character)
                {
                    Console.Write("-");
                    while (currentChar > character)
                    {
                        byte nextSub = sides.Where(v => currentChar - v >= character).Max();
                        currentChar = (byte)(currentChar - nextSub);
                        Console.Write(Array.IndexOf(sides, nextSub));
                    }
                }

                Console.Write("@6");
            }
}

Provalo online!

La mia versione più recente in realtà esegue alcune manipolazioni del cubo! Sìì!

Quella prima Console.Writec'è una manipolazione fissa elaborata da MD XF che crea questo cubo:

   242
   202
   242
000131555313
010121535343
000131555313
   424
   454
   424

Il significato di questo cubo è che uno dei suoi lati ha una somma di 1, che consente manipolazioni del Blocco note su una scala più piccola rispetto ai multipli di nove, e in particolare semplifica il movimento relativo piuttosto che dover ricominciare da zero ogni personaggio; in questo algoritmo sia l'addizione che la sottrazione vengono utilizzate per prendere il percorso più breve tra i caratteri.

La versione di inizializzazione di MD XF fa sì che il lato 2 abbia una somma di 14, che consente di risparmiare molti byte di output per distanze ASCII comprese tra 14 e 20.

Ora può gestire input con newline interne, Console.Read () ottiene singoli caratteri fino alla fine del file; vedere il collegamento TIO che dovrebbe avere l'input

Hello, 
World!

Hai rasato un paio di frazioni di punto emettendo immediatamente un carattere se il suo valore ASCII esiste già da un lato.

Test script fornito da MDXF


Presentazione precedente qui e spiegazione:

Questo è un po 'noioso, ma per quanto ne so, funziona. Certo, ci ho solo provatoHello, World! ma ho eseguito l'output nell'interprete cubico TIO e l'output "Hello, World!" quindi ho pensato che funzionasse.

Invece di manipolare il cubo, il blocco note viene semplicemente incrementato della somma di 1 faccia (9) ripetutamente fino a quando non ha il valore giusto per ciascun personaggio, quindi lo stampa.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Martin Ender,

@MartinEnder Potresti invece spostarli nella chat room esistente ?
MD XF,

@MDXF Potrei ma non so dire se finirebbero completamente fuori posto e contesto in quella chat.
Martin Ender,

@MartinEnder I commenti sono più vecchi della chatroom, quindi apparirebbero molto indietro nella trascrizione, giusto?
MD XF,

Loro dovrebbero. Grazie, sposterò i messaggi.
Martin Ender,
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.