Cordas de golfe em Fourier

24

Desafio

Dada uma string como entrada, jogue golfe no programa Fourier que produz essa string.

No Fourier, não há uma maneira fácil de gerar uma string: você precisa passar por cada código de caractere e emiti-lo como caractere.

Fourier

O idioma é baseado em um acumulador, uma variável global que é inicializada como 0 no início do programa. Isso é usado por quase todos os operadores no idioma. Apenas alguns não alteram o valor do acumulador.

Personagem fora

a

Pega o valor do acumulador como o código ASCII e gera o caractere. Não altera o valor do acumulador.

Se o acumulador for maior que 255, o programa retornará um erro. Da mesma forma, se o acumulador for menor que 0.

Número fora

o

Emite o valor do acumulador. Não altera o valor do acumulador.

Aumentar

^

Aumente o acumulador em um.

Diminuir

v

Diminua o acumulador em um.

Adicionar

+x

Define o acumulador para o valor do acumulador mais o valor de x.

Subtrair

-x

Define o acumulador para o valor do acumulador menos o valor de x.

Multiplicar

*x

Define o acumulador como o valor do acumulador multiplicado pelo valor de x.

Dividir

/x

Define o acumulador com o valor do acumulador dividido pelo valor de x. (Observe que essa é a divisão inteira, portanto, 1/6resulta em 0)

Número

n

Defina o acumulador para o número inteiro n.

Nota

Aqui, xe npode ser qualquer número inteiro de 0até 2^32-1inclusivo.

Mais Informações

Você deve usar apenas os operadores descritos acima. Portanto, seu programa Fourier emitido é inválido se usar qualquer um dos seguintes itens (observe que os seguintes operadores são permitidos para a recompensa):

  • Repetir loops
  • Se as declarações
  • Variáveis
  • Aleatória
  • Módulo
  • Entrada do Usuário
  • Maior / menor que operadores
  • Operadores de igualdade
  • Limpar tela
  • Atraso de tempo
  • Funções de data

Seu programa pode ser um programa completo ou uma função, recebendo entrada via STDIN, um arquivo ou argumentos de função. Você também pode receber informações diretamente da Internet.

Observe que, se houver um vvno seu código, você deve substituí-lo por -2. O mesmo vale para ^^substituí-lo por +2.

Exemplos

Se a entrada for 7n, o programa esperado é:

55a110a

Mas você pode salvar um byte com

55a*2a

Outra maneira é

7o110a

Usando número para fora.


Da mesma forma, se a entrada for Hello, o programa esperado é:

72a101a108a108a111a

Você pode reduzir em 3 bytes (porque a saída não altera o acumulador):

72a101a108aa111a

Mas espere, podemos usar o operador de adição, economizando 2 bytes:

72a101a+7aa+3a

Formatação

Como usarei o cabeçalho de snippet de pilha de Martin Büttner, você poderia formatar o título da seguinte forma:

# <Language name>, <length of total output> bytes

Em seguida, você pode colocar o que quiser abaixo do título.

Ganhando

Você deve postar o comprimento dos programas Fourier (produzidos pelo seu código) para gerar esse arquivo de texto e esse arquivo de texto . Sua pontuação é o comprimento combinado dos dois programas de Fourier em bytes (caracteres não ASCII não são usados ​​no Fourier, portanto, isso realmente não faz diferença).

A pessoa com as pontuações mais baixas ganha. Se houver um empate, o programa mais curto em bytes vence.

Recompensa

Esta recompensa de 500 representantes é para um novo resposta que joga as cordas usando qualquer uma das funções de Fourier. Isso inclui variáveis, loops e instruções if etc. Esta nova resposta não será aceita.

Entre os melhores

Consulte a seção de formatação acima:

var QUESTION_ID=55384;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table>

Beta Decay
fonte
6
Não acho que ter que apresentar todas as soluções ideais seja muito justo / interessante. Ele exclui todas as implementações, exceto a força bruta ...
orlp
5
O verdadeiro problema de ter que produzir todas as soluções ótimas é que, para uma entrada longa, haverá mais soluções ótimas do que átomos no universo.
Isaacg
11
@orlp editado saída todas as soluções ótimas
Beta Decay
11
Deve ser apenas ASCII imprimível ou qualquer tipo de ASCII? E apenas ASCII de 7 bits ou bytes completos?
Orlp 27/08/2015
11
O acumulador começa em 0?
ASCIIThenANSI

Respostas:

9

Python, 14307118 bytes

601216 para Hamlet + 13705902 para Genesis = 14307118

Definitivamente, existem alguns cenários em que esta solução não é ideal, como para 1111, onde ela produzirá 1111oem oposição a11oo . No entanto, acho que é quase ideal.

Editar: salvou alguns bytes, melhorando 0o0opara 0oo.

O nome do arquivo que contém a entrada é recebido em STDIN, enviado para STDOUT.

Resultados verificados com o intérprete oficial.

def opt_str(char, acc):
    opts = []
    char_num = ord(char)
    opts.append(str(char_num))
    if 0 < char_num - acc < 10:
        opts.append('+' + str(char_num - acc))
    if 0 < acc - char_num < 10:
        opts.append('-' + str(acc - char_num))
    if char_num - acc == 1:
        opts.append('^')
    if acc - char_num == 1:
        opts.append('v')
    if acc == char_num:
        opts.append('')
    if acc and char_num % acc == 0:
        opts.append('*' + str(char_num//acc))
    try:
        if acc // (acc // char_num) == char_num:
            opts.append('/' + str(acc // char_num))
    except:
        pass
    return [opt for opt in opts if len(opt) == len(min(opts, key=len))]

acc = 0
result = []
pos = 0
with open(input(), "r") as myfile:
        in_str = myfile.read()
while pos < len(in_str):
    i = in_str[pos]
    pos += 1
    if i in '0123456789':
        if i != '0':
            while pos < len(in_str) and in_str[pos] in '0123456789':
                i += in_str[pos]
                pos += 1
        if i == str(acc):
            result.append('o')
        else:
            result.append(i + 'o')
        acc = int(i)
    else:
        opts = opt_str(i, acc)
        result.append(opts[0] + 'a')
        acc = ord(i)
print(''.join(result))
isaacg
fonte
@ Shebang Bem, eu tenho certeza que o resultado do Geobit está errado, veja meus comentários lá.
Isaacg
Havia muito pouco nele, mas você ganhou por apenas 5 caracteres (você e Razvan amarradas então eu usei o comprimento do código como o desempate)
Beta Decay
2
@BetaDecay Eu nunca vi o desempate de comprimento ser relevante entre um par de programas não destruídos antes.
Isaacg 03/09/2015
Sim ... Eu também: P
Beta Decay
13

> <>, 14310665 bytes

601398 para aldeia + 13709267 para genesis

Ainda é um trabalho em andamento e leva muito tempo para ser concluído.

v
0
>i:0(?;:r-:?!v:0a-)?v     v
  >~:v       ~      >:a(?v>
 :1+?v~'v'o  v      o'^'~\:0)?v
     >n      vno'+'      ^?=1:<
^        o'a'<
Aaron
fonte
Isso é loucura, pena, mas não é o ideal.
orlp
Estou trabalhando no uso de /, * e o, mas está começando a tomar um pouco mais de lugar.
Aaron
18
Tudo bem, o peixe normalmente crescem a cada narração da história;)
Geobits
Bem, esta é uma brilhante escolha de idioma: D
Beta Decay
Seu programa não se enquadrava nos critérios para a recompensa (nenhuma das respostas postadas correspondia). Por isso, concordei com você porque eu amo o fato de você ter usado <> <.
Beta Decay
8

Java, 14307140 bytes

Hamlet - 601.218

Gênesis - 13.705.922

A idéia aqui é fazer todo o trabalho antecipadamente, criando um mapa de personagem-> personagem. Então você pode simplesmente percorrer e pegar as cordas mais curtas.

É preciso fazer uma exceção para os numerais, então eu os verifico no loop principal. No entanto, ainda é rápido e lida com o caso de teste maior em alguns segundos. Talvez eu consiga ajustar esta seção por mais alguns bytes, mas tenho quase certeza de que está perto do ideal.

Entrada é um nome de arquivo como argumento. A saída é gravada em um arquivo inputFilename_out.4e a contagem de caracteres é enviada para STDOUT.

Trata-se de 1737 bytes para o desempatador, completamente não-destruído. Eu posso jogar muito, se necessário, mas ainda será um pouco grande.

import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import java.text.NumberFormat;

public class FourierMapper {
    public static void main(String[] args) throws Exception {
        FourierMapper fm = new FourierMapper();
        fm.createMap();
        String filename = args.length>0? args[0]:"bible.txt";
        String out = fm.fourierize(filename);
        System.out.println(out.length());
        Files.write(Paths.get(filename + "_out.4"), out.getBytes(), new OpenOption[]{});
    }

    String[][] map = new String[9999][256];
    void createMap(){
        for(int from=0;from<9999;from++){
            for(int to=0;to<256;to++){
                if(to<10||from<1){
                    map[from][to] = ""+to;
                } else if(to==from){
                    map[from][to] = "";
                } else if(to-from==1){
                    map[from][to] = "^";
                } else if(to-from==-1){
                    map[from][to] = "v";
                } else if(to>99){               
                    if(to%from<1){
                        map[from][to] = "*"+(to/from);
                    } else if(to>from&&to-from<10){
                        map[from][to] = "+"+(to-from);
                    } else if(from>to&&from-to<10){
                        map[from][to] = "-"+(from-to);
                    } else {
                        map[from][to] = ""+to;
                    }
                } else {
                    map[from][to] = ""+to;
                }
            }
        }
    }

    String fourierize(String filename) throws Exception{
        StringBuilder out = new StringBuilder();
        byte[] in = Files.readAllBytes(Paths.get(filename));
        String whole = new String(in);
        out.append(in[0] + "a");
        int number = -1;
        for(int i=1;i<in.length;){
            if(in[i]<58&&in[i]>47){
                number = in[i]==48?0:((Number)NumberFormat.getInstance().parse(whole.substring(i,i+4))).intValue();
                out.append(""+number+"o");
                i += (""+number).length();
            } else {
                if(number<0)
                    out.append(map[in[i-1]][in[i]]+"a");
                else
                    out.append(map[number][in[i]]+"a");
                number = -1;
                i++;
            }
        }
        return out.toString();
    }

}
Geobits
fonte
Eu acho que isso não lida com seqüências de dígitos com zeros à esquerda corretamente. Por exemplo, na entrada 01, acredito que ela produz 01o, o que não está correto.
Isaacg
Além disso, acho que você está usando mal o acumulador. Na elsecláusula do loop principal, você escolhe entre usar o valor real do acumulador e o valor do caractere anterior. Você não pode fazer a última escolha se os dois forem diferentes, porque isso significa que você usou oo tempo anterior e o acumulador não contém o valor do caractere anterior.
Isaacg
Certo, ambos devem ser corrigidos agora. Obrigado!
Geobits
Quando executo isso na minha faca, recebo 625474 para Hamlet e 13705922 para Genesis.
Isaacg
@isaacg Você está executando no mesmo arquivo (com as mesmas terminações de linha)? Encontrei um problema com terminações de linha anteriormente. Quando executo o meu e o seu no mesmo arquivo, os dois mostram as pontuações publicadas.
Geobits
2

PHP, 14307118 bytes

601.216 (Hamlet) + 13.705.902 (Bíblia)

function f($file) {
    $text = file_get_contents($file);

    $a = 0;

    for ($i = 0; $i < strlen($text); $i++) {
        $chr = $text[$i];

        if (ctype_digit($chr)) {
            while ($chr && isset($text[$i + 1]) && ctype_digit($text[$i + 1])) {
                $chr .= $text[$i + 1];
                $i++;
            }

            if ($a == (int)$chr) {
                print "o";
            }
            else {
                $a = (int)$chr;
                print $chr . "o";
            }

            continue;
        }

        $ord = ord($chr);

        $mapping = array(
            '' => $a,
            '^' => $a + 1,
            'v' => $a - 1
        );

        for ($j = 2; $j <= 9; $j++) {
            $mapping["+$j"] = $a + $j;
            $mapping["-$j"] = $a - $j;
            $mapping["*$j"] = $a * $j;
            $mapping["/$j"] = $a / $j;
        }

        foreach ($mapping as $op => $value) {
            if ($value === $ord) {
                $a = $value;
                print $op . "a";
                continue 2;
            }
            else if ($value . '' === $chr) {
                $a = $value;
                print $op . "o";
                continue 2;
            }
        }

        $a = $ord;
        print $ord . "a";
    }
}

Saída de Fourier para Hamlet

Funciona da seguinte maneira:

  1. Repete sobre cada caractere na entrada;
  2. Se houver uma sequência de dígitos que não sejam zero, ele definirá o acumulador para esse número e o produzirá como número. Ele também verifica dígitos semelhantes;
  3. Caso contrário, verifica se há uma maneira mais curta de emitir o caractere atual (em vez do código ASCII + símbolo "a" = 4 caracteres) executando uma operação básica (+ - * /) no acumulador com um número entre 2 e 9; obviamente, ele também tenta comparar / incrementar / diminuir;
Razvan
fonte