Ilegible , 1830 1796 1791 1771 1762 1745 1736 1727 1626 1606 1577 bytes
La salida está en orden alfabético inverso ( z
a a
) pero de acuerdo con sus reglas, eso parece ser permisible.
'"" "" "'" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" ""' "" "" " "'" "'" "" '"" "" ""' "" "" "" "" "" "" "'" "" "'" "" "" "" "" "" '" "'" "'" "'" ""' "" "" "" '""' "" '"" "'" "" "" "" "" "" "" "" '""'""' "" "'" "" "" "" "" ""' "" '""' "" '"" "" "" "" "" "'" "" "" "" '""' "" '""' "" "'" "" "" "'" "" '""' "" "" "" "" "" '"" "" "" "" "' "" '""' "" '"" "" "" "'" "" "" "" "" "'" "" "" "" "" ""' "" '""'"" "" "" '"" "" "" "'" "" "" "" "" "" '"" "" "" "" "" "" "'" "" '"" "" "" "'" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" '""' " "" '""' "" "" "" "'" "" "" "" "" "" ""' "" "" "" "" "" "'" "'" ""'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "' "" '""' "" '""' "" '""' "" '""' "" '""' "" "'" "" "" "" "" "" "" "" "" '""' "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'"" "" "" "" "'" "" "" "" "" "" "" "'" "'" "" "" "" "" "" ""' "" "" "" '"" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' ""'""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '"" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" "" "" "' "" '""' "" '"" "'" '"" "" "" "'" "" "" "'" "" ""' "" "" "" "" "" "" "" '"" "" "" ""' "" "'" "" "" "" "" "" "" "" ""' "" "" "" "" "" """" "" '""' "" "'" ""' "" "" "" '"" "" "'" "" "" '"" "" "" "" "" "'" "" "" "" '""' "" '"" "'" "'" "'" "'" "'" "'" "'" "" "" "" '""' "" ' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' ""'""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '" "'" "'" "'" "" ""' "" "" "" "" "" "" "" '"" "" "" "" "" "'" "" "" "" '"" "" "" ""' "" "" "" "" "" "" '"" "" "" "" "" "" "" ""' "" "" """" '"" "" "" ""' "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" " "" "" "" '"" "" "" ""' "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "' "" "'" "" "'" "" "" "'" "" "" "" "" "" "" ""' "" '"" "" "" "" ""'"" "'" "" '"" "" "'" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "'" "" "" "'" "'" "'" "" '""' "" "" "" "" "" "" '"" """ '""' "" "'" "'" "" "" "" '""' "" '"" """ '""' "" "'" "'" "" "" "" '""' "" '"" "
Explicación
Primero, para tener una idea de lo que Unreadable puede hacer, aquí está su operación básica:
- Tienes una cinta infinita de celdas enteras de tamaño arbitrario
- Usted no tiene un puntero de memoria como en Brainfuck; en su lugar, desreferencia las celdas por su ubicación en la cinta. Esto significa que puede "leer el valor n. ° 4" o "leer el valor n. ° (leer el valor n. ° 4)" (doble desreferencia).
- Solo puede leer o escribir celdas de memoria (no aumentar / disminuir directamente como en Brainfuck).
- Puede aumentar / disminuir valores dentro de una expresión. Por lo tanto, para incrementar una celda de memoria que tiene que leer , de la subasta , escritura , o diferente puesto:
write(x, inc(read(x)))
.
- Hay bucles while y condicionales ternarios que solo pueden verificar cero frente a no cero.
Este programa usa la cinta de la siguiente manera. Los nombres de las variables se usarán en el pseudocódigo más adelante. Además, esto documenta la primera versión (que tenía 1830 bytes); vea las ediciones en la parte inferior para ver qué ha cambiado desde entonces.
- Celda 0: variable
q
- Cell 1: las variables
a
, p
,ch
- Celda 2: variables
hash
,v
- Celda 3: variables
b
,r
- Celda 4: variables
aa
,l
- Celda 5: sigue siendo 0 para marcar el "final" de la cadena de dígitos decimales
- Celdas 6–95: almacena la cadena de dígitos decimales hacia atrás
- Celdas 96–121: almacene el número de votos que se deducirán de los usuarios
a
(96) a z
(121) (el código ASCII de la carta menos uno).
- Celdas 4657–7380: recuerde qué combinaciones de votante / votante se han encontrado cuántas veces. Estas celdas tienen solo 4 valores posibles:
0
= aún no visto, -1
= visto una vez, -2
= visto dos veces, -3
= visto cualquier número de veces más de 2.
El algoritmo esencialmente procede de la siguiente manera:
- Sigue leyendo pares de caracteres
a
y b
. Calcule el valor hash (a-2)*(a-1)+b-1
, que es único para cada combinación de letras a – z.
- Verifique la celda de memoria en ese valor hash (
*hash
). Si es así -3
, el usuario ya es elegible para la eliminación de votos, así que incremente *(b-1)
. De lo contrario, decremento *hash
. Si es ahora -3
, el usuario acaba de ser elegible para la eliminación de votos después de tres ocurrencias, así que incremente *(b-1)
en 3
.
- Después de esto, revise los caracteres en orden inverso (
z
a a
) y muestre los que necesitan votos deducidos. Esto requiere la división de enteros manual por 10 para traducir el número a dígitos decimales.
Con todo eso aclarado, así es como se ve el programa como pseudocódigo:
// Read pairs of characters
while (a = read) + 1 {
b = read
// Calculate hash = (a-1)*(a-2)/2 + b-1
// This also sets a = b-1
hash = 0
while --a {
aa = a
while --aa {
++hash
}
}
while --b {
++a
++hash
}
// If this combination has just been seen for the third time,
// increment *a by 3; if more than third time, increment *a by 1
*a = (*hash + 3) ? ((--*hash) + 3 ? *a : (*a+3)) : (*a+1)
}
// Loop through the characters z to a
l = 27
while --l { // l loops from 26 to 1 (not 0)
(v = *(ch = l + 95)) ? { // 'a' is ASCII 97, but cell 96
print (ch+1) // print the votee
// Now we need to turn the number v into decimal.
// p points to where we are storing decimal digits.
p = 5
while v {
// Integer division by 10 (q=quotient, r=remainder)
r = (q = 0)
while v {
--v
(++r - 10) ? 1 : {
r = 0
++q
}
}
// Store digit ASCII character
*(++p) = r + 48 // 48 = '0'
v = q
}
// Now output all the digit ASCII characters in reverse order
while *p {
print *(--p + 1)
}
} : 1
}
Edición 1, 1830 → 1796: Me di cuenta de que puedo reutilizar el valor de retorno de un ciclo while en un solo lugar.
Edición 2, 1796 → 1791: Resulta que el programa es un poco más pequeño si, en lugar de usar las celdas 6–95, guardo los dígitos decimales en las celdas con números negativos (–1 en adelante). ¡Como un bono adicional, el programa ya no se limita a 10⁹⁰ votos!
Edición 3, 1791 → 1771: en lugar de asignar el resultado de *(ch = l + 95)
to v
, ahora lo asigno a q
y luego muevo la asignación v = q
a la condición while, llevando el código a 1777 bytes. Luego intercambie la ubicación de q
y v
en la cinta porque q
ahora es 1 más común que v
.
Edición 4, 1771 → 1762: Duh. Inicializar hash
a 1 en lugar de 0 es 9 bytes más corto. El código hash ahora es 1 más, lo que no importa.
Edición 5, 1762 → 1745: si inicializo q
y r
en 1 en lugar de 0, tengo que esparcir algunos -1
s en lugares para hacerlo bien, y todo parece cancelarse, excepto que el while v { --v; [...] }
ciclo ahora necesita ejecutar una iteración menos, lo que puedo hacer diciendo while --v { [...] }
, que es 26 caracteres más corto.
Edición 6, 1745 → 1736: en lugar de { r = 1; ++q }
, podemos escribir q = *((r = 1)+1)+1
. Esto se basa en el hecho de que q
está en la ranura variable # 2. Si estuviera en la ranura # 1, esto sería aún más corto, pero entonces todo el programa sería más largo en general.
Edición 7, 1745 → 1727: se revirtió la Edición 6 y, en su lugar, se logró guardar al incluir el bucle while más interno en la expresión que calcula el código ASCII de dígitos, que también termina en 1736 bytes ... pero luego guardó una instrucción de disminución (9 bytes ) cambiando ((++r) - 11) ? r :
a (r - 10) ? ++r :
.
Edición 8, 1727 → 1626: Se modificó el cálculo del hash. Ahora usa un bucle while menos. Las ubicaciones de las celdas ahora están en sus códigos ASCII reales (ya no están apagados en 1). Reorganizar las variables a diferentes ubicaciones en la cinta porque ahora se producen con diferente frecuencia.
Edición 9, 1626 → 1606: más loco en línea. El cuerpo del primer bucle while ahora se ve así:
// b = next char
*(b = (hash = read)) = {
// hash = b + (a-1)*(a-2)/2
while (a2 = --a) {
while --a2 {
++hash
}
}
// If this combination has just been seen for the third time,
// increment *b by 3; if more than third time, increment *b by 1
(*hash + 3) ? ((--*hash) + 3 ? *b : (*b+3)) : (*b+1)
}
y la asignación variable ahora ha cambiado casi por completo.
Editar 10, 1606 → 1577: He observado que a
y a2
son ambos decrementa a 0 en los bucles while, por lo que si podría emparejarse p
con cualquiera de ellos, pero no con ch
, no necesitaría para inicializar p
a 0
(que cuesta 29 bytes). Resulta que puedo hacer eso intercambiando p
y r
. Las nuevas asignaciones de variables (y su frecuencia de aparición en el código) son ahora:
0 = v (3) (total 3)
1 = hash (6), r (5), ch (2) (total 13)
2 = b (4), q (5) (total 9)
3 = a (3), p (5) (total 8)
4 = a2 (3), l (4) (total 7)
nanananananananabatman
caso de prueba.