Paul Nechifor

[english]

Alt fel de a trișa la ConQUIZtador

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 NechiforProiecte