A primeira linguagem de programação à qual fui exposto foi o Sinclair BASIC . Como muitos dialetos BASIC, ele exige que todas as linhas de código-fonte sejam numeradas .
Como resultado, o uso do GO TO
comando era idiomático e salta a execução para o número da linha fornecido (sem rótulos).
Também existe um GO SUB
comando relacionado que pode ser usado como uma chamada de função rudimentar. Novamente, a execução salta para o número de linha especificado, mas quando um RETURN
comando é alcançado, a execução retorna para a próxima instrução após a GO SUB
.
Da mesma forma, o RUN
comando reiniciará a execução do programa na linha especificada.
Qualquer pessoa que tenha passado algum tempo em um intérprete do BASIC numerado por linha aprenderá a usar um esquema de numeração com lacunas. Isso é mais fácil para inserir novas linhas de código. No entanto, mesmo assim, você ainda pode precisar inserir novas linhas entre as linhas numeradas consecutivamente.
Dada uma listagem BASIC numerada por linha como entrada, produza o mesmo programa, mas renumerado, de modo que os números de linha iniciem em 10 e aumentem em etapas de 10. A listagem de entrada pode ter GO TO
ou GO SUB
comandos, portanto, os números associados a eles também devem ser ajustados.
GO TO
e osGO SUB
comandos estão em suas próprias linhas ou no final dasIF
THEN
linhas. É seguro dizer que^(\d+) .*GO (TO|SUB) (\d+)$
é suficiente para corresponder a essas linhas. Esses comandos entre aspas devem ser ignorados.RUN
Os comandos sempre estarão em suas próprias linhas. Nesse caso, um número de linha é opcional. Se estiver faltando, o intérprete simplesmente inicia na parte superior do programa.Se um
GO TO
,GO SUB
ouRUN
referências de comando uma linha inexistente, então ele vai em vez ir para a próxima linha definida. Sua entrada precisa lidar com isso e garantir que essas referências de linha sejam corrigidas para que aponte para a linha correta. O comportamento pode ser indefinido se um número de linha após o final do programa for fornecido em um desses comandos.Os números de linha sempre serão inteiros positivos de 1 a 9999 (conforme o manual). Isso significa que os programas de entrada nunca terão mais de 999 linhas.
As linhas de entrada sempre serão numeradas em ordem numericamente crescente.
Para os fins deste desafio, as listagens de entrada conterão apenas ASCII imprimível. Você não precisa se preocupar com o conjunto de caracteres ZX. Dito isto, se sua entrada for realmente escrita no ZX BASIC ou no código / conjunto de máquinas z80 apropriado (e houver emuladores por aí ), você poderá escolher que sua entrada seja codificada no conjunto de caracteres ZX .
Você não pode usar nenhuma numeração de bibliotecas ou utilitários especificamente personalizados para esse fim.
Exemplo de entrada:
1 REM "A rearranged guessing game"
2 INPUT A: CLS
3 INPUT "Guess the number ", B
10 IF A=B THEN PRINT "Correct": STOP
100 IF A<B THEN GO SUB 125
120 IF A>B THEN GO SUB 122
121 GO TO 3
125 PRINT "Try again"
126 RETURN
127 REM "An example of GO TO 7 and GO SUB 13 in quotes"
Saída de exemplo:
10 REM "A rearranged guessing game"
20 INPUT A: CLS
30 INPUT "Guess the number ", B
40 IF A=B THEN PRINT "Correct": STOP
50 IF A<B THEN GO SUB 80
60 IF A>B THEN GO SUB 80
70 GO TO 30
80 PRINT "Try again"
90 RETURN
100 REM "An example of GO TO 7 and GO SUB 13 in quotes"
Eu queria vincular a um manual do ZX BASIC. O melhor que pude encontrar parece ser http://www.worldofspectrum.org/ZXBasicManual/index.html, mas esse parece ser um link morto. A máquina wayback tem uma cópia .
GOTO 100 + A*10
, e o Apêndice C do Manual do ZX Spectrum listaGO TO
como aceitando uma expressão numérica (sem restrição de constantes). Aqui está uma discussão dos méritos dos computadosGOTO
no ZX80 e no ZX81. BTW, eu não tenho idéia do por que o espaço foi adicionado na versão Spectrum.Respostas:
JavaScript (ES6) 177
Editar Adicionada a varredura (cara) para o próximo número de linha válido
TESTE
fonte
Perl 6,
147145144142 142 bytesProvavelmente isso pode ser um pouco mais complicado.
Expandido
fonte
.min
. use{min %line-map.keys».Num.grep:*>=$1
vezVisual Basic for Applications, 288 bytes
Eu não pude resistir a dar uma solução em um dialeto BASIC. Provavelmente funciona com o Visual Basic 6 / .NET ou outras variantes modernas com pequenas alterações.
Eu usei muitas variáveis de uma letra para concisão. Além disso, suprimi todos os espaços em branco desnecessários (o VBE os expande automaticamente na importação). A contagem de bytes é para o arquivo .BAS final, com CHR (10) como nova linha.
A sub-rotina, que pode ser invocada na janela imediata do VBE, abre um programa Sinclair BASIC (o primeiro parâmetro é o caminho para um arquivo ASCII - com CHR (10) como nova linha - contendo o programa), renumera as linhas e grava os resultados em uma variável Variant (segundo parâmetro).
A idéia é fazer uma iteração em todos os números de linha fonte possíveis, ordem ascendente, e para cada um, substituir de uma só vez todos os números de linha correspondentes, bem como
GO TO
,GO SUB
eRUN
referências com o próximo número de linha de destino disponíveis. Usando essa abordagem, não precisamos de nenhum tipo de tabela de conversão. O número da linha de destino é incrementado toda vez que uma correspondência no número da linha de origem é encontrada, para que as referências de linha "incorretas" sejam ajustadas automaticamente para o próximo número válido. Os caracteres de nova linha são usados como marcadores de início e fim de linha, e um CHR (0) - nunca usado no programa, pois não é imprimível - é usado como um marcador temporário, para evitar renumerar a mesma linha várias vezes.Algumas observações:
Por uma questão de concisão, usamos a menor seqüência possível para uma correspondência com as instruções de salto. Usando o final de linha em nossas cadeias de pesquisa, não corremos o risco de incluir ocorrências citadas ou funções de usuário (que sempre usam parênteses no Sinclair).
GO TO
requer uma string maior por causa daFOR ... TO
construção (por exemplo, compare50 FOR X=AGO TO 100
e50 GO TO 100
)O código não suporta instruções no formulário
GO TO200
(sem espaço em branco), embora o manual do ZX implique que seja um código válido em vários exemplos (custaria uma dúzia de bytes a mais para lidar com ele).O código adiciona uma nova linha no início e outra no final do programa. Eu poderia limpar isso no final (mais uma dúzia de bytes), mas acho que o ZX provavelmente ignoraria as linhas em branco.
Abaixo, uma versão mais legível:
fonte
Pip
-rn
, 63 bytesExperimente online!
Explicação
Configuração
O
-r
sinalizador lê todo o stdin e o armazena como uma lista de linhas na variável localg
. A variável globalt
é pré-inicializada para 10 e a variável globals
é pré-inicializada para" "
.Arruma a lista de linhas
g
para a variável globaly
, para que fique disponível dentro da função que estamos prestes a definir.Função de conversão de número de linha
Construímos uma função que mapeia de qualquer número de linha no esquema de numeração original (incluindo um inexistente) para o número de linha correspondente no novo esquema de numeração.
Suponha que tenhamos estas linhas:
Queremos mapear 1 a 10, 2-4 a 20 e 5-9 a 30. Se tivermos uma lista dos números de linha originais (
[1; 4; 9]
), podemos usar uma operação de filtro para descobrir quantos desses números são menos do que o número da linha que estamos tentando converter. Multiplique esse resultado por 10 e adicione 10, e temos a resposta desejada.Por exemplo, ao converter 9, há dois números de linha (1 e 4) menores que 9. 2 * 10 + 10 fornece 30. Ao converter 3, há um número de linha (1) menor que 3. 1 * 10 + 10 dá 20.
Aqui está o código (ligeiramente modificado para facilitar a leitura):
Primeira substituição:
GO TO
,GO SUB
eRUN
O restante do programa é uma expressão única que recebe
g
e faz algumas substituições de expressões regulares (que vetorizam, se aplicam a cada linha inseridag
).Aqui está a primeira substituição:
A regex corresponde a qualquer um de
RUN
,GO SUB
eGO TO
, seguida por um número, seguido pelo final da linha. Isso garante que ele não corresponda a cadeias internas nem aRUN
um número de linha.A ordem dos grupos de captura é importante. O primeiro grupo capta o comando (de um
RUN
,GO SUB
ouGO TO
). O segundo grupo, se usado, captura umSUB
ouTO
. Não precisamos capturar esta parte, mas um grupo que não captura captura exigiria bytes extras. Em seguida, o terceiro grupo captura o número da linha.Usamos uma função de retorno de chamada para a substituição. Com funções de callback em Pip, todo o jogo é o primeiro argumento
a
, e os grupos de captura no fim são os argumentos posterioresb
,c
,d
, ee
. Portanto, temos o comando no primeiro grupo, que entrab
, e o número da linha no terceiro grupo, que entrad
. A única mudança que precisamos fazer é passar o número da linha através da nossa função de conversão, que é chamado Lisp-style:(nd)
. Em seguida, concatenamos isso junto comb
e um espaço e o devolvemos.Segunda substituição: números de linha
Tudo o que resta para converter são os números de linha no início das linhas.
A regex corresponde a uma sequência de dígitos no início de uma linha. Novamente, usamos uma função de retorno de chamada; dessa vez, a
n
própria função de conversão é suficiente, pois a correspondência inteira (primeiro argumentoa
) é o número que queremos converter.Como essa é a última expressão do programa, o Pip imprime automaticamente o resultado. O
-n
sinalizador separa a lista de resultados com novas linhas.fonte