#include <stdio.h>
#include <string.h> // strlen
#include <ctype.h> // isprint
#define tamQR 21
#define info "www.elhacker.net"
// Ya que la tabla QR es el objeto principal de este programa
// lo hago global, para ahorrarme trabajo con las funciones.
// Cada posición x y guardará un 0, si no ese bit no debe estar
// activo o un valor distino a 0 si ese bit debe tener información.
int QR[tamQR][tamQR];
// Nota: Voy a llamar cursor a la posición x e y dentro del QR
// donde se vaya a escribir un dato.
// Una ayuda para manejar las cosas dentro de las funciones
typedef enum {
ABAJO,
ARRIBA,
DESDE_ABAJO,
DESDE_ARRIBA
} DIRECCION;
// --------------------------------------------------------------
// TODO ESTO NO CODIFICA TUS BYTES, SOLO REPRESENTA EL
// DIBUJO BÁSICO DEL QR
// Crea el cuadrado exterior de los recuadros de posición
void cuadrado_exterior(int x, int y) {
// Variables auxiliares para mover el cursor
// de dibujo por todo el recuadro
int xc, yc;
// Dibujo las líneas horizontales superior e inferior
for(xc = x; xc < x+7; ++xc) {
QR[y][xc] = 1;
QR[y+6][xc] = 1;
}
// Dibujo las líneas verticales
for(yc = y; yc < y+6; ++yc) {
QR[yc][x] = 1;
QR[yc][x+6] = 1;
}
}
// Crea el cuadrado interior de los recuadros de posición
void cuadrado_interior(int x, int y) {
int xc, yc;
for(yc = y; yc < y+3; ++yc)
for(xc = x; xc < x+3; ++xc)
QR[yc][xc] = 1;
}
// La función que se debe llamar para dibujar los cuadrados
// pasándole la posición de la esquina superior izquierda
void cuadrado(int x, int y) {
cuadrado_exterior(x, y);
cuadrado_interior(x+2, y+2);
}
void QR_inicializar() {
int x, y;
// Borrar todo el QR
for(y = 0; y < tamQR; ++y)
for(x = 0; x < tamQR; ++x)
QR[y][x] = 0;
// Escribir en el los recuadros de posición
cuadrado(0, 0);
cuadrado(14, 0);
cuadrado(0, 14);
}
void QR_imprimir() {
int x, y;
// Se escribirá el carácter 219 o el 176 en la consola
// según si QR[y][x] es no 0 o 0 respectivamente
for(y = 0; y < tamQR; ++y) {
for(x = 0; x < tamQR; ++x) {
char c = QR[y][x]? 219:176;
}
}
}
// --------------------------------------------------------------
// La idea es que solo hay dos caminos que se repiten de cada grupo de
// cuatro bits:
// De abajo a arriba (4 pasos)
// 1) .. 2) .. 3) .o 4) o.
// .o o. .. ..
//
// De arriba a abajo (4 pasos)
// 1) .o 2) o. 3) .. 4) ..
// .. .. .o o.
//
// A cada posición le corresponde un bit del nibble (grupo de 4 bits)
// desde el bit de mayor peso al bit de menor peso.
// Además se dejará el cursor a la siguiente posición (la que seguiría
// el patrón si hubiera continuado una vez más) dejándolo preparado
// para que el próximo nibble se escriba en él sin hacer más cálculos
// (cómo se vera esto se consigue de forma natural con el bucle).
void codificar_nibble(int *x, int *y, char nibble, DIRECCION partida) {
// La máscara sirve para para conseguir trabajar con los bits
// que quieres dentro de un dato (si eso búscalo en Google para
// comprender más). En este caso como es un nibble (conjunto de 4 bits)
// el bit de mayor peso, dentro de un byte está aquí 00001000 en binario
// (que es igual a 8 decimal).
char mascara = 8;
// La bandera cambiará entre falso (0) y cierto (no 0) para controlar el
// cursor, si debe ir en una dirección u otra.
int bandera = 0;
// El desplazamiento de bits sobre la máscara (busca que es eso) irá
// desplazando el 1 hacia la derecha hasta que mascara tendrá todo 0,
// momento en que mascara valdrá 0 en decimal y el while se detendrá.
while(mascara) {
// Escribe donde se encuentre el cursor el dato del bit mascara
// del nibble
QR[*y][*x] = nibble & mascara;
// Muevo el bit de la mascara un lugar a la derecha
mascara >>= 1;
// Actualizo el cursor para la siguiente posición
switch(partida) {
case ABAJO:
// No se necesita. Usado para evitar el warning del compilador.
break;
case ARRIBA:
// No se necesita. Usado para evitar el warning del compilador.
break;
// Sacado de tus dibujos
case DESDE_ABAJO:
if(!bandera)
--*x; // A la izquierda
else {
++*x; // A la derecha
--*y; // y a arriba
}
break;
case DESDE_ARRIBA:
if(!bandera)
--*x; // A la izquierda
else {
++*x; // A la derecha
++*y; // Y abajo
}
break;
}
bandera = !bandera;
}
}
void codificar_byte(int *x, int *y, unsigned char c, DIRECCION direcc) {
// La siguiente línea tan solo es para depuración. No es necesaria para
// crear el QR
printf("x: %2i, y: %2i, c: %3i ( %c )\n", *x
, *y
, c
, isprint(c
)? c
: ' ');
// Cada byte se compone de 2 nibbles.
// La expresión c>>4 & 0xF toma los cuatro bits de más peso del byte.
// La expresión c & 0xF toma los cuatro bits de menos peso del byte.
// (En verdad, todo esto del trabajo con bits es necesario para hacer
// este ejercicio).
switch(direcc) {
case ABAJO:
codificar_nibble(x, y, c>>4 & 0xF, DESDE_ARRIBA);
codificar_nibble(x, y, c & 0xF, DESDE_ARRIBA);
break;
case ARRIBA:
codificar_nibble(x, y, c>>4 & 0xF, DESDE_ABAJO);
codificar_nibble(x, y, c & 0xF, DESDE_ABAJO);
break;
case DESDE_ABAJO:
codificar_nibble(x, y, c>>4 & 0xF, DESDE_ABAJO);
*x -= 2; // Estas dos expresiones para actualizar el cursor son necesarias
++*y; // pues donde lo deja la función codificar_nibble solo sirve para
// ABAJO y ARRIBA. Si miras tu dibujo lo comprenderás
codificar_nibble(x, y, c & 0xF, DESDE_ARRIBA);
break;
case DESDE_ARRIBA:
codificar_nibble(x, y, c>>4 & 0xF, DESDE_ARRIBA);
*x -= 2; // Ídem al caso anterior
--*y;
codificar_nibble(x, y, c & 0xF, DESDE_ABAJO);
break;
}
}
void codificar_cadena(char *cadena) {
size_t tam
= strlen(cadena
); // Tamaño de la cadena. int x = 20; // Posición de inicio. Se necesita meter en una variable.
int y = 14; // porqué las mismas funciones lo irán actualizando.
int pos = 0; // Serve para indicar qué caracter de la cadena estamos operando.
int i;
if(tam > 17) tam = 17; // Limitar el tamaño de la cadena a los 17 caracteres inicales.
// Se codifican los caracteres dentro del QR
for(i = 0; i < 2; ++i) {
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ARRIBA);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, DESDE_ABAJO);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ABAJO);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ABAJO);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, DESDE_ARRIBA);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ARRIBA);
}
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ARRIBA);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ARRIBA);
--y; // Necesario para saltar una línea de bits (ver tu dibujo)
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ARRIBA);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, DESDE_ABAJO);
codificar_byte(&x, &y, tam > pos? cadena[pos++] : 0, ABAJO);
}
int main() {
QR_inicializar();
codificar_cadena(info);
QR_imprimir();
return 0;
}