Jump to content
MrGrj

[CHALLANGE]Cum functioneaza ?

Recommended Posts

  • Active Members

Avem urmatoarea bucata de cod scris in C:

 

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

Programul poate fi compilat exact asa cum este (testat cu gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)), outputul fiind:

 

[mrgrj@localhost tmp]# vim challangeRST.c
[mrgrj@localhost tmp]# gcc challangeRST.c -o challangeRST
[mrgrj@localhost tmp]# ./challangeRST 
!!!!!!  !!!!!!          !!!!!!  !!!!!!              !!  !!!!!! 
!!  !!  !!  !!              !!      !!              !!      !! 
!!  !!  !!  !!              !!      !!              !!      !! 
!!  !!  !!!!!!    !!      !!!!    !!!!    !!        !!    !!!! 
!!  !!  !!  !!              !!      !!              !!  !!     
!!  !!  !!  !!              !!      !!              !!  !!     
!!!!!!  !!!!!!          !!!!!!  !!!!!!              !!  !!!! 

Cum functioneaza programul ? (explicati output-ul)

 

O sa va rog sa folositi buttonul de spoiler in momentul in care dati un raspuns decent. Challange-ul expira vineri la ora 23:59.

 

Solvers:

1. @MasterLight

2.

3.

 

 

Edited by MrGrj
  • Upvote 1
Link to comment
Share on other sites

Spoiler

Am sa incep prin a preciza ca nu l-am "disecat" pe cat de mult ar trebui, deci nu pot explica anumite lucruri.

 

1.Am inceput prin a inlocui "_" folosit ca prim argument in functia main cu numele sau standard "argc".

2.Prima linie este foarte interesanta, ea utilizand recursivitatea pentru a-i modifica valoarea lui argc(care initial primeste valoarea 1) pana la 448, atunci cand acel && este fals si functia atinge un fel de "base case".De asemenea, acesta linie poate fi scrisa cu ajutorul unui loop.

3.Acum, acea expresi din functia putchar am s-o despart in mai multe expresii.

  1. exp1 = 32 | (-~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1): Rezultatul returnat de aceasta expresie(care foloseste integer division astfel rezultatul fiind trunchiat) este fie 32(fiind valoarea ascii pentru un spatiu " " ) fie 33(ascii: "!").
  2. exp2 = 10, aceasta fiind valoarea ascii pentru un "\n".
  3. char result = --argc % 64 ? exp1 : exp2, decide ce caracter trebuie afisat: " ", "!", "\n"
  4. Ergo, expresia din putchar va afisa unul dintre caracterele: " ", "\n", "!" in functie de valoarea lui argc.

Din pacate, nu am reusit sa-mi dau seama de ce este folosit 448 sau anumite lucruri ca acel bit field.

 

Cateva note pe care le-am facut in timp ce investighat expresia sus numita:

 


// __TIME__-argc/8%8 = __TIME__ will be a number of this form ddddddd and from those digits(because it gets converted) it will be
//					   subtracted the value of (argc / 8)(int division so it gets truncated i.e all decimal points are lost) & 8
//					   achiving this: for eight values of argc the last digit of __TIME__-argc/8%8 will remain constant, after that it will be
//					   incremented by 1.  

// [argc*2 & 8| argc / 64] = 4 bits are 0 then the next 4 bits are 8 and so on.
// (argc & 2 ? 1:8) % 8 & 1 = (0 for the first two then 1 for the next two and so on.	

Asta este codul la care am ajuns dupa observatiile pe care le-am mentionat mai sus:

 


#include <stdio.h>

int main(void)
{
	for(unsigned int i = 448; i > 0; i--)
	{
		// Don't modifiy the loop sentinel, use a temporary variable instead.
		unsigned int argc = i;
				 																			                  												
		// The result of this is either 0 or 1.
		int exp1 = -~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1;
		
		// After we | it we get either 32(space) or 33(!).
		exp1 |= 32;

		// We reached the end, so put a \n
		int exp2 = 10;
      
		char result = --argc % 64 ? exp1 : exp2;
	
      	// Finally, put the char on the screen.
		putchar(result);
	}
	
	return 0;
}

O zi buna!

 

 

Edited by MasterLight
  • Upvote 1
Link to comment
Share on other sites

  • Active Members
On 3/31/2016 at 0:28 AM, MasterLight said:
  Reveal hidden contents

Am sa incep prin a preciza ca nu l-am "disecat" pe cat de mult ar trebui, deci nu pot explica anumite lucruri.

 

1.Am inceput prin a inlocui "_" folosit ca prim argument in functia main cu numele sau standard "argc".

2.Prima linie este foarte interesanta, ea utilizand recursivitatea pentru a-i modifica valoarea lui argc(care initial primeste valoarea 1) pana la 448, atunci cand acel && este fals si functia atinge un fel de "base case".De asemenea, acesta linie poate fi scrisa cu ajutorul unui loop.

3.Acum, acea expresi din functia putchar am s-o despart in mai multe expresii.

  1. exp1 = 32 | (-~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1): Rezultatul returnat de aceasta expresie(care foloseste integer division astfel rezultatul fiind trunchiat) este fie 32(fiind valoarea ascii pentru un spatiu " " ) fie 33(ascii: "!").
  2. exp2 = 10, aceasta fiind valoarea ascii pentru un "\n".
  3. char result = --argc % 64 ? exp1 : exp2, decide ce caracter trebuie afisat: " ", "!", "\n"
  4. Ergo, expresia din putchar va afisa unul dintre caracterele: " ", "\n", "!" in functie de valoarea lui argc.

Din pacate, nu am reusit sa-mi dau seama de ce este folosit 448 sau anumite lucruri ca acel bit field.

 

Cateva note pe care le-am facut in timp ce investighat expresia sus numita:

 



// __TIME__-argc/8%8 = __TIME__ will be a number of this form ddddddd and from those digits(because it gets converted) it will be
//					   subtracted the value of (argc / 8)(int division so it gets truncated i.e all decimal points are lost) & 8
//					   achiving this: for eight values of argc the last digit of __TIME__-argc/8%8 will remain constant, after that it will be
//					   incremented by 1.  

// [argc*2 & 8| argc / 64] = 4 bits are 0 then the next 4 bits are 8 and so on.
// (argc & 2 ? 1:8) % 8 & 1 = (0 for the first two then 1 for the next two and so on.	

Asta este codul la care am ajuns dupa observatiile pe care le-am mentionat mai sus:

 



#include <stdio.h>

int main(void)
{
	for(unsigned int i = 448; i > 0; i--)
	{
		// Don't modifiy the loop sentinel, use a temporary variable instead.
		unsigned int argc = i;
				 																			                  												
		// The result of this is either 0 or 1.
		int exp1 = -~7[__TIME__ - (argc / 8) % 8][">'txiZ^(~z?" - 48] >> ";;;====~$::199"[(argc*2 & 8) | argc / 64] / (argc & 2 ? 1:8) % 8 & 1;
		
		// After we | it we get either 32(space) or 33(!).
		exp1 |= 32;

		// We reached the end, so put a \n
		int exp2 = 10;
      
		char result = --argc % 64 ? exp1 : exp2;
	
      	// Finally, put the char on the screen.
		putchar(result);
	}
	
	return 0;
}

O zi buna!

 

 

 

Close enough. Uite la ce ma gandisem eu ca ar fi un raspuns complet:

 

Se indenteaza putin codul:

 

main(_) {
    _^448 && main(-~_);
    putchar(--_%64
        ? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
        : 10);
}

Se introduc ceva variabile pentru a face codul putin mai readable:

 

main(int i) {
    if(i^448)
        main(-~i);
    if(--i % 64) {
        char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
        char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    } else {
        putchar(10); // newline
    }
}

A se nota ca -~i == i + 1 deci avem:

 

main(int i) {
    if(i != 448)
        main(i+1);
    i--;
    if(i % 64 == 0) {
        putchar('\n');
    } else {
        char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
        char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    }
}

Acum, a se nota faptul ca a[ b ] e acelasi lucru ca si b[ a ], iar aplicand -~ == 1+ avem: 

 

main(int i) {
    if(i != 448)
        main(i+1);
    i--;
    if(i % 64 == 0) {
        putchar('\n');
    } else {
        char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1;
        char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    }
}

Facand trecere de la recursivitate la un loop + incercand sa simplificam putin codul, obtinem:

 

main() {
    int i;
    for(i=447; i>=0; i--) {
        if(i % 64 == 0) {
            putchar('\n');
        } else {
            char t = __TIME__[7 - i/8%8];
            char a = ">'txiZ^(~z?"[t - 48] + 1;
            int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
            if((i & 2) == 0)
                shift /= 8;
            shift = shift % 8;
            char b = a >> shift;
            putchar(32 | (b & 1));
        }
    }
}

Asta va afisa cate un caracter per iteratie. Fiecare al 64-lea caracter va printa un new-line. Altfel, foloseste o pereche de valori dintr-un table pentru a-si da seama ce sa printeze si pune ori caracterul 32(space) sau caracterul 33 ( '!' ).

 

Primul tabel (

">'txiZ^(~z?"

) este un set de 10 bitmaps care descriu aparitia fiecarui caracter, iar cel de-al doilea tabel: (

";;;====~$::199"

) selecteaza bit-ul necesar din bitmap.

 

Al doilea tabel:

 

int shift = ";;;====~$::199"[(i*2&8) | (i/64)];

 

i/64 -> este numarul linie (6-0)

i&2&8 -> 8 daca i = 4, 5, 7 mod 8.

 

if((i & 2) == 0) shift /= 8; shift = shift % 8

- linia de mai sus selecteaza ori "the high octal digit" (pentru i%8 = 0,1,4,5) sau "the low octal figit" (pentru i%8 = 2,3,6,7). Deci tabelul va arata cam asa:

 

rand col val
6   6-7 0
6   4-5 0
6   2-3 5
6   0-1 7
5   6-7 1
5   4-5 7
5   2-3 5
5   0-1 7
4   6-7 1
4   4-5 7
4   2-3 5
4   0-1 7
3   6-7 1
3   4-5 6
3   2-3 5
3   0-1 7
2   6-7 2
2   4-5 7
2   2-3 3
2   0-1 7
1   6-7 2
1   4-5 7
1   2-3 3
1   0-1 7
0   6-7 4
0   4-5 4
0   2-3 3
0   0-1 7

Sau, intr-o forma mai tabulara:

 

00005577
11775577
11775577
11665577
22773377
22773377
44443377

A se observa ca s-a folosit null terminator pentru primele doua valori din tabel :D

 

Primul tabel:

 

__TIME__ este un macro special definit de preprocesor. Aceasta este folosita ca un constant string continand timpul la care preprocesorul a fost rulat, in forma: "HH:MM:SS". Mai pe romaneste, odata cu fiecare compilare, programul va arata ora exacta a compilarii. A se observa ca ora nu se schimba atunci cand dati Run.

 

De sesizat faptul ca HH:MM:SS contine exact 8 caractere. De notat ca 0-9 in ASCII inseamna 48-57 iar semnul ":" are valoarea 58 in tabelul cu valori ASCII. Outputul contine 64 caractere / linie => 8 chars / caracter din __TIME__.

 

7 - i/8%8

este indexul lui __TIME__ care este de fapt outputul ( 7- este necesar pentru ca iteram valoarea lui i invers). Deci, este ceea ce __TIME__ printeaza.

 

sfarsteste prin a fi egal cu una din urmatoarele valori binare, in functie de inputul t:

 

0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000

 

Din moment ce caracterele sunt 7-bit ASCII, cel mai mare bit va fi mereu clearuit => va fi printat mereu ca blank. Deci, al doilea tabel va arata asa, dupa ce 7 = blank

 

000055  
11  55  
11  55  
116655  
22  33  
22  33  
444433  

Deci, de exemplu, 4 = 01101010 (bits 1,3,5, si 6 set) care e printat astfel:

 

----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--

Ca sa vedem ca am inteles cu adevarat codul, sa ajustam putin outputul folosind acest tabel:

 

  00  
11  55
11  55
  66  
22  33
22  33
  44

Asta este encodat ca: 

 

"?;;?==? '::799\x07"

 

In scop artistic, vom adauga 64 la cateva caractere (din moment ce doar ultimii 6 biti sunt folositi, asta nu va afecta ouputul); asta va rezulta in:

 

"?{{?}}?gg::799G"

( de notat ca al 8-lea caracter nu este folosit -> deci practic putem sa il transformam in orice dorim).

 

 

Edited by MrGrj
  • Upvote 2
  • Downvote 1
Link to comment
Share on other sites

Hai ba garaj... sa pui challenge-ul ala e o chestie, dar sa copiezi rezolvarea cuvant cu cuvant de pe stackoverflow e aiurea :| 

@MasterLight a facut macar singur rezolvarea, chiar daca e incompleta.. (cel putin nu am gasit rezolvarea lui pe net)

Edited by Byte-ul
Link to comment
Share on other sites

19 hours ago, Byte-ul said:

Hai ba garaj... sa pui challenge-ul ala e o chestie, dar sa copiezi rezolvarea cuvant cu cuvant de pe stackoverflow e aiurea :| 

@MasterLight a facut macar singur rezolvarea, chiar daca e incompleta.. (cel putin nu am gasit rezolvarea lui pe net)

 

ahhaha

Edited by Webz
Link to comment
Share on other sites

  • Active Members

Ba, nu inteleg de ce va cacati atat pe voi. Am explicat si la @Byte-ul  :(

 

In cazul in care un chall e facut de tine, evident vei veni cu o solutie personala. In cazul de fata, chall-ul nu a fost al meu, insa mi s-a parut extrem de nice, asa ca l-am postat :) La fel si cu rezolvarea: aia a fost cea mai completa pe care am gasit-o, deci am postat-o. Puteam sa vin cu solutia mea, insa era cu mult mai putine detalii fata de ceea ce am postat mai sus.

 

Poti sa-l inchizi

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.


×
×
  • Create New...