Am o istorie lungă de trișat la ConQUIZtador. Eu inițial foloseam o metodă prin care obținem întrebările și răspunsurile folosind funcții JavaScript cu un script în AutoIt. După ceva timp ei au schimbat cum funționează clientul. Acum întrebarea nu mai este lăsată într-o variabilă. Ea este transformată într-o imagine și variabila este golită. Am aflat asta decompilând fișierele SWF. Totuși, eu am rămas cu mii de întrebări de pe ConQUIZtador.
Acum pentru că n-am mai trișat de mult, vreau să joc din nou. M-am gândit că metoda cea mai simplă de a reveni în lumea trișorilor ar fi să folosesc un program OCR pentru a citi întrebarea direct de pe ecran și să o caut printre întrebările pe care le am deja. Dar pentru că programele OCR nu sunt exacte trebuie să caut întrebarea cea mai apropiată, și nu să verific caracter cu caracter.
Înainte foloseam AutoIt, deci mergea doar pe Windows. Acum am făcut să meargă pe Linux. Pentru a captura imaginea am folosit comanda import
care aparține de ImageMagick (se instalează în Ubuntu cu apt-get install imagemagick
). Exemplul următor capturează o imagine în format PBM cu mărimea 900x110 începând de la poziția 105x382 (la poziția asta se află întrebarea din ConQUIZtador pe ecranul meu).
import -window root -crop 900x110+105+382 imagine.pbm
Pentru a citi textul folosesc programul ocrad. Programul ăsta nu recunoaște decât 3 tipuri de imagini. De asta trebuie ca import
să salveze în formatul PBM. Exempul următor afișează pe ecran textul din imagine.pbm. Trebuie -i
ca să inverseze imaginea deoarece în joc culoarea textului este mai deschisă.
ocrad --charset=ascii -i imagine.pbm
Pentru a găsi răspunsul la întrebare am nevoie de lista mea de întrebări și răspunsuri colectate de pe ConQUIZtador. Adică fișierele rapide.txt
și grila.txt
. Dar pentru că ocrad
nu detectează diacriticele corect, trebuie să scap de ele.
iconv -f utf-8 -t ascii//TRANSLIT rapide.txt > rapide.txt.ascii iconv -f utf-8 -t ascii//TRANSLIT grila.txt > grila.txt.ascii rm grila.txt rapide.txt mv rapide.txt.ascii rapide.txt mv grila.txt.ascii grila.txt
Acum am nevoie de un progrămel care să caute întrebarea cea mai apropiată. Mă gândeam să folosesc algoritmul Levenshtein, dar eu am nevoie să găsesc un răspuns cât mai rapid! Așa că am facut un program C cu o metodă proprie de a afla diferența dintre două șiruri de caractere.
Codul sursă îl scriu mai jos, dar se găsește și în fișierul gaseste.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | /*
* Nume: gaseste
* Autor: Paul Nechifor <[email protected]>
* Inceput: 23.07.2009
* Terminat: 23.07.2009
* Descriere: Citeste o intrebare de la stdin si cauta intrebarea cea mai apropiata
* din fisierele rapide.txt si grila.txt.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LUNG 5
struct intrebare
{
char text[300];
char rasp[200];
};
struct intrebare intrebari[30000];
int nr = 0;
int scorPentru(char* corect, char* verific)
{
int i, scor = 0, lc = strlen(corect) - LUNG;
char save;
for (i=0; i<lc; i++)
{
save = corect[i + LUNG];
corect[i + LUNG] = 0;
if (strstr(verific, &corect[i]) == NULL) scor++;
corect[i + LUNG] = save;
}
return scor;
}
void incarcaRapide()
{
int i;
FILE* rapide = fopen("rapide.txt", "r");
if (!rapide) { printf("Nu exista 'rapide.txt'!\n"); exit(4); }
while (fgets(intrebari[nr].text, 300, rapide))
{
intrebari[nr].text[strlen(intrebari[nr].text)-1] = 0;
fgets(intrebari[nr].rasp, 10, rapide);
nr++;
}
fclose(rapide);
}
void incarcaGrila()
{
char r[4][200];
int i, c;
FILE* grila = fopen("grila.txt", "r");
if (!grila) { printf("Nu exista 'grila.txt'!\n"); exit(3); }
while (fgets(intrebari[nr].text, 300, grila))
{
intrebari[nr].text[strlen(intrebari[nr].text)-1] = 0;
for (i=0; i<4; i++)
fgets(r[i], 200, grila);
fscanf(grila, "%d\n", &c);
strcpy(intrebari[nr].rasp, r[c-1]);
nr++;
}
fclose(grila);
}
int main(int argc, char *argv[])
{
int i, s, min = 9999;
char cauta[1000];
if (argc < 2) { printf("Utilizare: %s grila|rapid\n", argv[0]); exit(1); }
if (!strcmp(argv[1], "rapid")) incarcaRapide();
else if (!strcmp(argv[1], "grila")) incarcaGrila();
else { printf("Trebuie grila sau rapid\n"); exit(2); }
fgets(cauta, sizeof(cauta), stdin);
for (i=0; i<nr; i++)
{
s = scorPentru(cauta, intrebari[i].text);
if (s < min)
{
min = s;
printf("%s\n", intrebari[i].text);
printf("S:%-4d CORECT: %s", s, intrebari[i].rasp);
}
}
return 0;
}
|
Acum mai am nevoie doar de o metodă simplă de a alege tipul de întrebare. Am făcut un script Python care folosește xlib
(adică apt-get install python-xlib
pentru a instala pe Ubuntu) pentru a asculta tastele. Am ales patru butoane. Când apas, scriptul apelează programele import
și ocrad
pentru a primi textul. Apoi apelează programul gaseste
.
Codul sursă îl scriu mai jos, dar se găsește și în fișierul conquizocr.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #!/usr/bin/env python
# Nume: conquiz_ocr
# Autor: Paul Nechifor <[email protected]>
# Inceput: 22.07.2009
# Terminat: 23.07.2009
# Descriere: Programul asta asculta niste taste folosind xlib si face screenshot la o intrebare
# de pe ConQUIZtador. Apoi citeste textul din imagine si cauta in baza de date raspunsul.
import os, re
from Xlib.display import Display
from Xlib import X
dinNou = False
def handle_event(event):
keycode = event.detail
global dinNou
if keycode == 51:
dinNou = True
print "\n" * 50
return
if not dinNou: return
dinNou = False
if keycode == 47:
marime = "900x110+105+382" # pentru intrebare rapida
elif keycode == 48 or keycode == 34:
marime = "1230x100+105+424" # pentru intrebare grila si intrebare rapida care vine dupa intrebare grila
# folosesc programul import pentru a face un screenshot, care este salvat ca 'imagine.pbm'
os.system("import -window root -crop " + marime + " imagine.pbm")
# folosesc programul ocrad pentru a citi textul din imagine
text = os.popen("ocrad --charset=ascii -i imagine.pbm").read()
# inlocuiesc mai multe caractere albe cu un singur spatiu
text = re.sub("[ \t\n]+", " ", text)
# 'escape' pentru apostrof si slash
text.replace("\\", "\\\\").replace("'", "\\'")
# apelez programul C care trebuie sa gasesca intrebarea cea mai apropiata si raspunsul
if keycode == 48:
os.system("echo '" + text + "' | ./gaseste grila")
elif keycode == 34 or keycode == 47:
os.system("echo '" + text + "' | ./gaseste rapid")
print "=" * 100,
# current display
disp = Display()
root = disp.screen().root
# we tell the X server we want to catch keyPress event
root.change_attributes(event_mask = X.KeyPressMask)
for keycode in [47, 48, 34, 51]: # tastele sunt ;'[\
root.grab_key(keycode, X.AnyModifier, 1, X.GrabModeAsync, X.GrabModeAsync)
while 1:
event = root.display.next_event()
handle_event(event)
|
Creat în 2009 de Paul Nechifor • Proiecte