2019-05-23:

CONFidence 2019 golf - wyniki

confidence:conference
Konkursy o wejściówki na CONFidence 2019 zakończyły się wczoraj w południe, więc czas na opublikowanie zwycięskich prac (bo technicznie ogłoszenie wyników miało miejsce na dzisiejszym livestreamie).

Konkurs C++
TOP1: Kacper "kcpikkt" Kokot (943 bajty) - gratulacje!

#include <bits/stdc++.h>
#define L(x) for(int i=0;i<x;i++)
#define S(x) f.seekg(32+x);f.seekp(32+x);
#define W(x,y) f.write((char*)&b[x],y);
char*v="confidence.bmp";using u=uint64_t;std::fstream f;u b[]={6095364,9175814,0xa30407,0xffffff,0xae8081,0,0xc58182,0xd18183,0x5eec204d42,0xc000000200000,0x1043807800000,24},l=3;u s(u x,u y){u v=(y>>6)%2+1;l=v-1?1:l;int o=v*(y&~64)*115200-5760+x*60;S(o)int k=l?f.peek()/l:3;L(20*v+1){L(20)W(k,3)S(o-5760*i)}}int main(){fopen(v,"w");f.open(v);W(8,32)L(2073600)W(5,3)for(auto t:(u[][4]){{7,47,22,15},{19,35,13,19},{24,44,31,18},{28,28,17,22},{42,34,28,22},{60,48,20,18},{64,36,26,16}})L(t[2]*t[3])s(t[0]+(i%t[2]),t[1]-i/t[2]);l=0;for(auto t:(u[]){0x3A31701518B895A,0x14BF07D0417C964,0xAD7E07463F07C96E,0xFA082F80978,0x2B5F81518B897F,0xC64A52900239E,0x2108418E29E,0x632108418E2A8,0xC60842131A3A8,0xC64A52931A3BC,0x63210840022BC,0xDEE378,})L(50)if((t>>14+i)%2)s((t&63)+i/5,((t>>6&63)-i%5)|(t>>13)%2*64);}

Konkurs Python 3.x
TOP1: blamedrop (1133 bajty) - gratulacje!

from base64 import*;import zlib;open('confidence.png','wb').write(zlib.decompress(b85decode(b'c%17D@N?(olHy`uVBq!ia0y~yU~gbxV6k9f28u}iy;A_BBm#UwT!C~f6H5;>+hP{>bq$S28=EdRHvj+sKSVivJp%*hG*1`DkcwMx@0=}sWFXOySbdy#MQiRs-3v^*7o4&@xVJcPXCBmD!n$?C_5%;4*UE4=KdAJR{GV|0LtoJ)0|xqn1HYyAGQCsWd&1_^<o@^l^QFFcA5cheIMC4G2*iwx%uH+`%)$f091;QsAgqw^;M$dE$(OkIFM1Q+BnlP*VF##IM#g4{R+u)3R+1FK9Dt?><^ZrG<}E9qUGQn{f2VI;YmgN~G!U?sC`BZ>jbsmys0c?~I1rAo0{O||1+OJ!ti|73gx)KR`dj(@k#XCj(%0{0wch{u^YgW`h1r^UKUbbyaW0Iw09cs+?TA!f`Jr7b>8GuI*WUlXs;qp?iD`T1U+aHbr6X>?6UcqBbNbcv#mOsQ-;dwM)Lg%i7%$F!-#Jz4zTn)wITcY$%F@@KSox!Jt*ifU9l75bMytF(zA5}F8%A72K6vRHckqAA_k^sypM$noheet+ZFv~+^Uc@Hou4M3HeMxr_2KjN>mR%cH_*~1E}Sn|Rwwap->oCtw0ZiYjT!Hke|{yn=Duw9-sGouPL*Fd_crL~o#c<dJ7mJnALb%1S=sE}`2OK?*>@VJ{Vh*Fe7M=i`i!pq(=*>|+e9V)aPtz3Wtg{76=4mVjHFLoJKFy!o!`Jj<wTpG_=ziN<)>XcKkZ6A9Km;V^UjmT-weX{JwJN>JQtOd^qcHA)jwW7oIgi<{p{vs@292rrz)?gJth|YY-7m2=eMdqcf0IJl?zMwpl?FmOi!&+3#O=%?byEd`EvhG)@!eierGoA&e`pz;pf(Vi+w8IS#a8B&4CB;8RP~Owp8IDoP7VV|L(d^GBUrj{@i&XdH<+&(Z_qK?H_GlNk;Auqk1W+kg%SCOt<1n!HHim)7gbzv8ndK+Egx9FC2RzdL+m^`DFfYS=t$|e0HA>k!270ibx1xA{9}dZ|L00Vc7qX|EEowhIOM!I*9A(>gTe~DWM4ftwo0Y')))

Konkurs JavaScript
TOP1: argeento (535 bajty) - gratulacje!

<canvas id=v width=1920 height=1080><img onload=with(v.getContext`2d`)drawImage(this,imageSmoothingEnabled=0,0,1920,1080) src=data:;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA2BAMAAADKYYHhAAAAGFBMVEUAAABdAgSMAwaugIH////FgYKjBAfRgYOX8gosAAAA4ElEQVRIx+2V4QmDMBCFW3AAU24Bj2yQBZoQXKBkgSK3Qen6fadoBKkUmoKFPMPhXd6XS35oTlXfyyxaV8+53B4NYO4QM12BMoD1JhpvfPQYFJsTIY/+PRAsGQ/EYxC1zZWIQ2DV3CYDF2bp7xZWXR4AOjQAOIYdYFCAfMC61nbYkJW+3+kwBNYzKBCDjWQsR9l0yNgywaM6fRER/iEAzaVSgEhKsDwfM+BSUUAReIzjzmnm8HD6P8CpNX8XOHRhICHkLU0he44OjMK8utLNTNK0MDBp/X8qD2wvlgpUfaI>

Dziwne zagadki
Podczas sprawdzania prac natrafiłem na trzy dziwne przypadki, które wymagały pewnej pracy detektywistycznej. Dwie z nich nawet udało się rozwiązać.

Zaczynając od nierozwiązanej zagadki - jeden z uczestników wrzucił hash SHA256 zgodnie z zasadami w komentarz pod postem konkursowym, ale... nie odnalazłem odpowiadającej mu pracy na mejlu, a szukałem dość długo. Ostatecznie poszukiwania zarzuciłem, ponieważ ten sam uczestnik zgłosił kilka kolejnych aktualizacji pracy, a zgodnie z zasadami i tak dla celów konkursowych rozważałem jedynie najnowsze zgłoszenie. Niemniej jednak dziwne...

W drugim przypadku zgłoszony hash SHA256 nie zgadzał się z samą pracą. Niezrażony dodałem na koniec pliku znak nowej linii - najpierw \n, potem \r\n, i przeliczyłem hashe. Okazało się, że trafiłem za drugim razem i hash zaczął się zgadzać (czyli uczestnik musiał najpierw policzyć SHA256, potem zorientować się, że na końcu pliku jest niepotrzebny "enter", usunąć go, i wysłać pracę).

W trzecim przypadku było jeszcze zabawniej - ponownie hash się nie zgadzał ze zgłoszoną pracą. Po rzuceniu okiem w plik okazało się, że nowe linie korzystają z notacji DOSowo-Windowsowej, czyli \r\n zamiast o bajt krótszego \n. Ponieważ nie sądziłem, żeby uczestnik, przy bądź co bądź bardzo dobrym zgłoszeniu, nie wpadł na pomysł zaoszczędzenia kilku bajtów korzystając z nowych linii w formacie UNIXowym (samo \n), stwierdziłem że przekonwertuje plik do formatu UNIXowego. Po przekonwertowaniu hash SHA256 naglę zaczął się zgadzać. Przypuszczam, że albo program pocztowy autora, albo któryś z serwerów po drodze stwierdził, że skoro plik-załącznik jest definitywnie tekstowy, to można sobie pozmieniać mu nowe linie wedle życzenia. Ot wada załączników puszczanych w formie nieskonwertowanej do base64 przez program pocztowy.

No nic, chyba w przyszłości będzie trzeba jednak napisać krótki skrypcik do przyjmowania zgłoszeń via WWW.

Comments:

2019-05-24 09:33:04 = monika90
{
Ale ten program co ma być w C++ to jednak nie jest w C++.

Poza tym mógłby być o kilka znaków krótszy, można usunąć nadmiarowy przecinek i parę innych rzeczy.
}
2019-05-24 22:25:00 = d33tah
{
Patrząc na Pythonowy top1, wygląda na to że byłem na dobrym tropie... ;) Możnaby jeszcze parę bajtów ugrać skracając nazwę pliku.

Swoją drogą Gynvael, przyjąłbyś plik .pyc z roszerzeniem .py jako zgłoszenie? Chodziło mi po głowie, żeby skompilować coś w stylu "open('o.png', 'w').write(b'\x89PNG..." i wtedy idzie uciąć jeszcze przynajmniej kilkadziesiąt bajtów... Interpreter Pythona to łyka, pytanie czy Ty byś zaakceptował.
}
2019-05-24 23:55:39 = Gynvael Coldwind
{
@d33tah
Nazwy pliku nie można skrócić, musi się nazywać "confidence.png".
Natomiast można jeszcze trochę bajtów ugrać lepiej kompresując PNG.

I tak, przyjąłbym skompilowany .pyc jeśli interpreter by to łykał. Tak szczerze, to nawet w ostatniej chwili trochę zasady poprawiłem, żeby nie sugerowały, że chodzi strikte o kod źródłowy w przypadku Pythona ;)
}
2019-05-25 12:03:10 = 42
{
Szybki test:
- Po zmianie nazwy z a.pyc na b.py, interpreter to "łyka" (czyli polecenie `python3 b.py` działa poprawnie)
- Jednak, po kompilacji plik .pyc ma ponad 100 bajtów więcej od pliku źródłowego .py (1250 vs. 1133 bajtów)
Więc raczej nie tędy droga ;) Kompilowałem poleceniem `python3 -O -m py_compile a.py` - może ktoś zna polecenie na bardziej agresywną kompilację. Dajcie znać! Osobiście wątpie że w przypadku zwycięskiej pracy skompilowana wersja mogłaby zajmować mniej. Prove me wrong ;)
}
2019-05-25 13:50:10 = Gynvael Coldwind
{
@42
Generalnie plik .pyc to zserializowany (marshal) obiekt code (reprezentujący kod w przestrzeni globalnej).

>>> import marshal
>>> m = open("asdf.pyc", "rb").read()
>>> c = marshal.loads(m[12:])
>>> dir(c)

Przypuszczam, że można tam trochę rzeczy wyrzucić. Tak patrząc na szybko
- na pewno nazwe pliku źródłowego (c.co_filename)
- nazwę modułu można usunąć (c.co_name)
- chyba tabele z numerami linii (c.co_lnotab)
- i może jeszcze jakieś pojedyncze pola można wyNone'ować ;)

Patrząc na sam kod bajtowy (c.co_code, a w zasadzie dis.dis(c)):
- chyba można trochę oszukać z importowaniem i kilku bajtów się pozbyć - tj. nie musimy importowanego zlib przypisywać do zmiennej o nazwie zlib (no dobra, po Pythonowemu to by było "nie musimy obiektowi zaimportowanego modułu doczepiać nazwy "zlib").
- być może dało by się w ogóle pozbyć stałej "None", ale to jest trochę ryzykowne (chyba opkod IMPORT_NAME potrzebuje None jako drugi argument); ew w jakichś inny sposób bym pokombinował przed RETURN_VALUE (tam jest POP_TOP po czym jest LOAD_CONST (None) - w zasadzie obu można się pozbyć i RETURN_VALUE nadal zadziała).

Problem jest taki, że obiekt code jest read-only, więc trzeba taki obiekt stworzyć od zera (co jak najbardziej jest robialne ofc).

Co więcej, przypuszczam, że jest jedna duża różnica - do .pyc nie trzeba używać base85. Można zamiast tego w źródle użyć b"stringa" z escape'owaniem \x12\x34\x56\x78, które będzie zmienione na bajty w samym .pyc.

[EDIT]
W zasadzie sprawdziłem to ostatnie przypuszczenie, i sama ta zmiana powoduje zejście do 1031 bajtów.
Można też wtedy usunąć base64 z importów, i dostaje się 1008 bajtów.

Pozostaje się pobawić się trochę tymi niskopoziomowymi rejonami - poniżej 1000 da się spokojnie zejść, ale trochę wątpię czy poniżej 950.

Ah, no i jeszcze można z kompresją zlib trochę powalczyć (albo innymi dostępnymi domyślnie), tj, użyć jakichś alternatywnych kompresorów, które być może są trochę lepsze.
}
2019-05-25 17:22:40 = d33tah
{
Dzięki za odpowiedź!

A co gdyby ten zlibowy blob wewnątrz PNGka ustawić na poziom kompresji=0 i przekompresować jakimś LZMA?

Swoją drogą ciut mnie zaskakuje, że wychodzi na to że najlepszy sposób żeby wygrać tego golfa pod Pythonem to napisać program który wypluwa bufor z tymi bajtami zahardkodowanymi, zamiast opisanymi algorytmem, jak (jeśli dobrze rozumiem) pokazuje przykład C++...
}
2019-05-25 17:23:43 = d33tah
{
Also Gyn, wyraziłbyś zgodę żebym zrobił z tego wątek na codegolf.stackexchange.com? Ciekawi mnie gdzie dalej mogłoby to pójść.
}
2019-05-25 20:31:55 = Gynvael Coldwind
{
@d33tah
Jasne, wrzucaj :) (i wrzuć potem linka tutaj plz)

W sumie fajnie wyszło, bo w każdym języku inny sposób był użyty :)
}
2019-05-26 07:17:11 = d33tah
{
https://codegolf.stackexchange.com/questions/186120/using-the-smallest-number-of-bytes-of-code-write-a-program-that-produces-this-i

Nie mam doświadczenia w opisywaniu golfów, więc jeśli moderacja nie chce tego przyjąć i wiadomo jak zgodnie z duchem zagadki ją poprawić, zapraszam do tego kogokolwiek chętnego ;)

Wybrałem PNG dla wszystkich języków, bo IIRC poziom kompresji można zawsze ustawić na zero, tylko trzeba wtedy od nowa przeliczać sumy kontrolne w przypadku tricku z fseek.
}
2019-05-26 14:57:59 = blamedrop
{
Co do zabaw z PNG miałem pewien pomysł, niestety ostatecznie nietrafiony.
Jak już wiadomo, można źródłową grafikę zeskalować bez interpolacji 20 razy otrzymując 96x54 pikselowy obrazek. Ten można ostatecznie zoptymalizować do rozmiaru 312 bajtów - jest to poprawny, nieuszkodzony plik PNG.

Dla rozwiązania JavaScript, tak jak zrobił to argeento, można go uszkodzić (argeento usunął sekcję IEND (3*4=12 bajtów), 4 bajty CRC sekcji IDAT i z tego co rozumiem usunął też 5 ostatnich bajtów zawartości IDAT, otrzymując 296 bajtów (czyli prawdopodobnie nieuszkodzony plik PNG miał 317 bajtów)). Jednak taki plik nie jest już poprawnie otwierany przez GIMPa, ale przeglądarki nadal sobie radzą - co wystarcza dla konkursu JS. W przypadku pliku startowego 312B udało się zejść (uszkodzić tak by nadal przeglądarka go rysowała) do 292B. Następnie psując delikatnie Base64 ostatecznie (wykorzystując, świetnie zoptymalizowane zwycięskie rozwiązanie) udało się uzyskać 530 bajtów. Czyli 5 bajtów lepiej. Ciekawe czy możliwe jest zejście jeszcze niżej :>

```
<canvas id=v width=1920 height=1080><img onload=with(v.getContext`2d`)drawImage(this,imageSmoothingEnabled=0,0,1920,1080) src=data:;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA2BAMAAADKYYHhAAAAGFBMVEUAAABdAgSMAwb///+jBAfFgYLRgYOugIE5HrT9AAAA20lEQVR4AWKgHIwCQThAFmVECAsA2qsDk4qBGIzjD7qAn5ngvlvAJJ3AdyscTqAr3PqaQwMgVYATKvQPlED5kQaAng2QBVnoCywBVeFQqKu6im83gcP1GFgVqEMVqiIP25MIzRjlmgSPZNufK/Qj1wC+bSKk2w/gHkDUaFZrEXht+85jcDc6FAHcqgsqvX3fkCxfcFZiaK3xL8EckS0ArfVO8u31C4y+FAQBBgbLAOYE9v8HxgDAgiiPXgk6gPykz8ctOzPIgHl0f8mjB1aDGQuyxeDgx3KB37t6Bw>
```

Niechcący wyszły dywagacje a ja chciałem o czymś innym :P Zastanawiałem się, czy PNG nie ma w sobie (w nagłówkach) opcji jakiegoś skalowania - by dla pliku 96x54 programy wyświetlały 1920x1080. Przeglądnąłem specyfikacje i spróbowałem dla tego 312 bajtowego pliku:
- w IHDR zmienić rozmiary na 1920x1080 zmieniając też CRC, niestety bez sukcesu - programy które testowałem piksele z IDATy rysują w pierwszej/drugiej linii reszte pozostawiając pustą - bez zaskoczenia
- ręczne dodanie nagłówka pHYs z wartościami "Pixels per unit" równymi 20, niestety to też nie dało oczekiwanego rezultatu, zarówno dla 0 jak i 1 w "Unit specifier"

Rozumiem, że takiej opcji w PNG po prostu nie ma - ale może ktoś coś wie więcej ;)?
}
2019-05-26 15:26:34 = Gynvael Coldwind
{
@blamedrop
O! Dobry trop :)
O ile PNG nie ma skalowania, to ma algorytm do streamowania - https://en.wikipedia.org/wiki/Adam7_algorithm
W dużym skrócie działa to tak, że wysyła się najpierw grafikę w niższej rozdzielczości (tj. na początku PNG jest tylko 1/64 pixeli), a potem dosyła kolejne dane stopniowo zwiększając rozdzielczość.
Nie jestem pewien czy użycie tego w naszym przypadku by coś dało, bo niestety 20 nie jest za bardzo podzielne przez 8, więc nie możnaby uciąć danych już po pierwszym całym obrazie.

Btw, inna rzecz której można spróbować, to rozkompresowania tej sekcji IDAT z PNG, ręczne wycięcie ostatnich N scanline (która są i tak czarne), i skompresowanie ponownie. Nie jestem przekonany czy to cokolwiek poprawi, ale może warto rzucić okiem.
}

Add a comment:

Nick:
URL (optional):
Math captcha: 9 ∗ 1 + 4 =