Reto de programación en C 2 : Letra DNI

K

Pues visto el "éxito" del otro thread, me he decidido a crear otro. En este la prueba es crear un programa que, pasándole como argumento un número de DNI, te diga la letra. La gracia está en ver quién hace el programa más corto.

La entrada sería así :
$ ./dni 12345678
C:> dni 12345678
(Para los Windowseros :))

Siendo 12345678 el número de DNI.

La salida deberá ser :

  1. Si la entrada es válida devolver el número del DNI seguido de un guión y la letra. Ejemplo : 12345678-Z. Además main deberá devolver 0 (return 0.)
  2. Se la entrada es incorrecta (El DNI no tiene exactamente 8 caracteres. No hace falta comprobar si son números y tal, con comprobar la longitud vale.) deberá escribir "Usage: dni <8 digits number>". Main debe devolver 1 (return 1.)

Toda salida debe seguir de un salto de línea (\n)

Solo vale C a secas, nada de includes (Ni siquiera si vienen con todos los compiladores), ni CPP, ni nada... Si necesitas declarar una función que viene con C (Como printf) declárala en el programa.

Ejemplo: int printf(const char *format, ...);

No seáis cabrones y usad C válido, sin warnings en el compilador ni nada. Mejor si usáis GCC para compilar xD

Al final del fichero debe haber una línea en blanco, que eso ya es un byte en Linux y dos en Windows (Los de Windows avisad que estáis programando ahí para poneros un byte menos.)

Para el que se pregunte como se saca la letra del DNI, decir que es símplemente el resto del número del DNI entre 23, y según el resultado que de el resto, coger ese caracter de una cadena especial. La cadena especial es "TRWAGMYFPDXBNJZSQVHLCKE".

Ejemplo: 12345678/23, el resto da 14. Se debería coger el carácter 14 de la cadena, que en este caso es la Z.

Por cierto, la medida del tamaño del programa se realiza sobre el código, no sobre el binario :) Yo he conseguido acortarlo hasta los 227 bytes. A ver si alguien hace código más corto. No pongáis de momento el código, que cada uno se saque las castañas del fuego, que habrá más de uno que se "inspire" en código de otro xD

Linuxeros, poned esto en la carpeta donde tengáis el código :

echo "echo \"-------------\"; gcc -o dnin dni.c; echo \"Size File\"; echo \"-------------\"; du -b dni.c dnin; echo \"-------------\"; ./dnin 12345678; echo \"-------------\"; ./dnin error; echo \"-------------\"" > dni; chmod +x ./dni

Creará un archivo que, asumiendo que el fichero fuente se llame dni.c, os mostrará la salida si es bueno y si es malo el DNI, y el tamaño del source y el binario. Además autocompilará el programa cada vez que ejecutes ./dni (Con el nombre del binario "dnin"), con lo que no habrá que andar compilando todo el rato.

Cuando yo pongo ./dni me sale :

-------------

Size File


227 dni.c

7484 dnin

12345678-Z


Usage: dni <8 digits number>
-------------

Si lo habéis hecho bien, os debería salir lo mismo que a mi, aunque con diferentes tamaños de archivo, claro.

LOc0

Sólo una cuestión estrictamente matemática: Si divides por 23, ¿cómo es posible que haya 24 letras, si sólo hay 23 restos posibles (0-22 ambos inclusive)?

Según eso, la letra O nunca saldría.

Salu2 ;)

K

Hmm, cierto, no me había fijado :)

No sé, yo saqué el algoritmo de a-saber-donde, hace bastante tiempo... Creo que tienes razón así que quito la O de la cadena. ¿Alguien tiene DNI con letra O?

Un byte menos para el código :)

K

Yo si no pongo lo de "int printf(const char *format,...);" me pone un warning, que raro...

dni.c:1: aviso: declaración implícita incompatible de la función interna 'printf'

Lo mismo con strlen... Aunque el strlen lo cambié por otra cosa, que no necesita declarar strlen y ocupa menos.

Sin declarar strlen (Usándolo) y sin declarar printf, 196 bytes.

No se te olviden los dos returns (Creo que solo pusiste uno) y los finales de linea (Los \n en las salidas), que creo que no los pusiste en el código. No me ha dado tiempo a verlo apenas, así que puede ser que sí lo tuvieras puesto xD ¿Has descontado un byte por la última linea? Al menos a mí me da warning también si no pongo un LF (¿O era CR lo que usaba Linux?) al final del fichero. Por lo que me aumenta un byte y a los de Linux dos.

PD: Quita el código, que más de uno se inspirará en el tuyo xD

LOc0

Se me había olvidado el return 0-1

Quedaría así (199 bytes en Win):

[Censurado]

Salu2 ;)

PD: Me compila sin warnings porque uso Dev-C++ y tendrá las librerías estándar linkadas por defecto. De todas formas ocupa menos un #include <stdio.h> que definir printf, que por otro lado, sólo con la definición realmente no estás haciendo "nada".

K

Ánimo que ese código puede bajar aún más.

A ver si se anima más gente.

¿195 bytes con los \n en la salida? wow, tendré que buscar la forma de bajar algunos bytes :)

He bajado a 180 bytes de la forma más tonta xD Eso sí, usando strlen y sin declarando, y tampoco declarando el printf. Usando el método que no me da warnings (Declarando printf y sin usar strlen) son 227 bytes.

LOc0

Son 195 bytes sin poner un \n en las salidas. Con el \n me sube a 199 bytes. Y ya he tocado de to xD.

Lo miro un poco más y a sobar.

Salu2 ;)

LOc0

180 bytes y me rindo :)

main(int a,char*b[]){char c,r[23]="TRWAGMYFPDXBNJZSQVHLCKE";if(c=strlen(b[1])==8)printf("%s-%c\n",b[1],r[atoi(b[1])%23]);else printf("Usage: dni <8 digits number>\n");return(c);}

Me piro a sobar.

Salu2 ;)

PD: Me ha costado, pero he conseguido saltarme todas los consejos de "elegancia de código" que me enseñaron allá en 1º xD...

cabron

El mismo que ha puesto #8, rebajado a 169 bytes:

http://cpp.sourceforge.net/?show=9752

De todas formas sin ánimo de ofender, me parece esto un poco chorra, si para "ganar" hay que recurrir a hacer un código horrible e ilegible, no le veo ningún sentido.

En todo caso se debería valorar la sencillez del algoritmo y el usar el mínimo de instrucciones necesarias, no el tener que usar variables de nombre a, y el tener que comerse todos los espacios.

Por cierto, el foro de desarrollo y diseño existe : P

Y

tiene que ser estrictamente necesario en C? yo es que soy más por la labor de scripting, como perl, python o php que son multiplataforma. Además, el propio código mostrado es el propio codigo a ejecutar sin necesidad de compilación.

DArgo

Pero haced cosas que no esten hechas ya. Un ejemplo seria calcular los primeros n numeros de fibonacci en lenguaje ensamblador o cosas de esas xD.
Otra idea seria hacer un editor por consola sencillo, de la manera mas eficiente posible. O un buscaminas en C, o un tetris en python. Cosas asi.

#9, no importa el numero de intrucciones de un programa, sino su coste temporal (cpu) y espacial (memoria).

TeKaNeO

Yo lo he hecho pero vamos, es larguito, lleva varias funciones, pero funciona:

http://www.rafb.net/paste/results/38QgzW79.html

Saludos^^

Trisky

creo pero no me hagais caso que la letra O no sale en ningun dni, hice el otro dia el programa en Visual y me di cuenta de que no aparecian todas las letras y que el orden no es el mismo, ejemplo el 1 no es la A....

PD: por ahi arriba os lo dicen, de que os sirve hacer un programa que sea casi ilegible para ahorrar espacio..... si todavia tuvieras millones de bucles y numeros grandisimos pues todavia lo entenderia porque es lo que dicen lo importante es el tiempo de memoria y demas.....

cabron

#11:

Estamos hablando de programas muy simples ejecutados en máquinas modernas(p4 de 1gb de ram or ejemplo), el uso de CPU y la carga de memoría son insignificantes...

K

En el código de LOc0 y el de cabron, no están los dos return, solo uno, y devuelve "c" en lugar de 0 o 1, pero aún así está muy bien :)

Mi código (180 bytes):

char *c="TRWAGMYFPDXBNJZSQVHLCKE";int main(int a,char **b){if(strlen(b[1])!=8){printf("Usage: dni <8 digits number>\n");return 1;}printf("%s-%c\n",b[1],c[atoi(b[1])%23]);return 0;}

Como curiosidad, mi sustituto del strlen:

if (argv[1][8] || !argv[1][9])

#11, me pongo a hacer lo de los n números de Fibonacci en FASM en cuanto pueda, no debe ser muy difícil.

@Cabron:

"En todo caso se debería valorar la sencillez del algoritmo y el usar el mínimo de instrucciones necesarias, no el tener que usar variables de nombre a, y el tener que comerse todos los espacios."
¿Sabes qué? Tienes razón.

"Por cierto, el foro de desarrollo y diseño existe : P"
Woops :)

cabron

#15:

"if (argv[1][8] || !argv[1][9])"

Creo que eso no produce el resultado esperado. No olvides que en C, los arrays son punteros, y que no hay ningún mecanismo de protección que te impida acceder a zonas de memoria más alla del límite del array.

Si alguien inicia el programa con una cadena de 5 caracteres, arg[1] tendrá 5 elementos nada más, con la instrucción argv[1][8] estás comprobando el valor de una dirección de memoria que no tiene nada que ver con el array, y si casualmente esa posición tiene un valor distinto de 0, te lo cogerá como positivo, aunque la cadena tenga solo 5 caracteres.

El mismo problema existe con !argv[1][9], no tienes ninguna garantia de que esa posición de memoria sea un elemento del array o cualquier otra cosa.

cabron

Tekaneo tío, tu código fuente es extremadamente complejo para hacer algo tan simple.

Bueno, al final me he puesto a hacer una versión completa y legible:

http://cpp.sourceforge.net/?show=9766

TeKaNeO

Jeajejaea, lo se pero es que lo hice rapido y solo se me venian a la mente funciones y mas funciones, soy del estilo de: "Divide y vencerás" xDD

Saludos^^

Usuarios habituales