diff --git a/Dockerfile.cgolf b/Dockerfile.cgolf new file mode 100644 index 0000000..d681cca --- /dev/null +++ b/Dockerfile.cgolf @@ -0,0 +1,13 @@ +FROM alpine:latest + +RUN apk --no-cache add gcc musl-dev curl-dev + +WORKDIR /app + +COPY golf.c . + +RUN gcc -o webwords golf.c -lcurl + +EXPOSE 31337 + +CMD ["./webwords"] \ No newline at end of file diff --git a/Dockerfile.golf b/Dockerfile.golf new file mode 100644 index 0000000..157075a --- /dev/null +++ b/Dockerfile.golf @@ -0,0 +1,12 @@ +FROM alpine:latest + +ENTRYPOINT ["/bin/webwords"] + +EXPOSE 31337 + +COPY golf.py /bin/webwords + +RUN chmod 0754 /bin/webwords + +RUN apk --no-cache add python3 ca-certificates \ + && rm -rf /var/cache/apk/* \ No newline at end of file diff --git a/content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst b/content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst new file mode 100644 index 0000000..8968cd0 --- /dev/null +++ b/content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst @@ -0,0 +1,123 @@ +webwords code golf: minimal HTTP servers in multiple languages +################################################################ + +:author: Russell Ballestrini +:slug: webwords-code-golf-minimal-implementation +:date: 2025-10-10 16:00 +:tags: Code, Python, C, Golf +:status: published + +The full webwords implementations have proper error handling, logging, and structure. But what's the absolute minimum code needed to implement the core functionality? + +.. contents:: + +the challenge +============= + +Implement webwords functionality in the fewest Python characters possible: + +1. Accept HTTP requests on port 31337 +2. Parse ``keyword`` and ``target`` parameters +3. Fetch target URI content +4. Return ``true`` if keyword found, ``false`` otherwise + +python solution +=============== + +.. code-block:: python + + import http.server as h,urllib.request as u,urllib.parse as p + class S(h.BaseHTTPRequestHandler): + def do_GET(s):q=dict(p.parse_qsl(p.urlparse(s.path).query));s.send_response(200);s.end_headers();s.wfile.write(str(q.get('keyword','')in u.urlopen(q.get('target','')).read().decode()).lower().encode()) + h.HTTPServer(('',31337),S).serve_forever() + +**Character count: 314** + +c solution +========== + +.. code-block:: c + + #include + #include + #include + #include + #include + #include + #include + struct M{char*m;size_t s;};size_t w(void*c,size_t z,size_t n,void*u){size_t r=z*n;struct M*m=u;char*p=realloc(m->m,m->s+r+1);if(!p)return 0;m->m=p;memcpy(&m->m[m->s],c,r);m->s+=r;m->m[m->s]=0;return r;}int f(char*u,char**o){CURL*h;struct M c={malloc(1),0};curl_global_init(0);h=curl_easy_init();if(h){curl_easy_setopt(h,10002,u);curl_easy_setopt(h,20011,w);curl_easy_setopt(h,10001,&c);curl_easy_perform(h);curl_easy_cleanup(h);}curl_global_cleanup();*o=c.m;return 1;}void s(int k,char*r){char b[256];sprintf(b,"HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",strlen(r),r);send(k,b,strlen(b),0);}int main(){int v=socket(2,1,0),c;struct sockaddr_in a={2,htons(31337),0};bind(v,(void*)&a,16);listen(v,10);while(1){c=accept(v,0,0);char b[4096],*q,*t,*d;recv(c,b,4095,0);q=strchr(b,'?');if(q&&(t=strstr(q,"target="))&&(q=strstr(q,"keyword="))){char*p;if((p=strchr(t+7,'&')))*(p)=0;else if((p=strchr(t+7,' ')))*(p)=0;if((p=strchr(q+8,'&')))*(p)=0;else if((p=strchr(q+8,' ')))*(p)=0;if(f(t+7,&d))s(c,strstr(d,q+8)?"true":"false");else s(c,"false");free(d);}else s(c,"false");close(c);}} + +**Character count: 1,232** + +how they work +============= + +**Python version (314 chars):** + +1. Compressed imports with short aliases +2. Minimal variable names (``s`` for self, ``q`` for query) +3. Chained operations on single lines +4. No error handling or validation +5. Direct string conversion of boolean result + +**C version (1,232 chars):** + +1. Single-character variable names +2. Removes all whitespace and comments +3. Uses curl magic numbers instead of constants +4. Minimal HTTP response formatting +5. No error checking or memory leak prevention + +docker implementation +==================== + +.. code-block:: dockerfile + + FROM alpine:latest + ENTRYPOINT ["/bin/webwords"] + EXPOSE 31337 + COPY golf.py /bin/webwords + RUN chmod 0754 /bin/webwords + RUN apk --no-cache add python3 ca-certificates && rm -rf /var/cache/apk/* + +testing +======= + +**Python golf:** + +.. code-block:: bash + + docker build -f Dockerfile.golf -t webwords-golf . + docker run -d -p 31337:31337 webwords-golf + curl "http://localhost:31337/?keyword=potato&target=https://www.remarkbox.com" + +**C golf:** + +.. code-block:: bash + + docker build -f Dockerfile.cgolf -t webwords-cgolf . + docker run -d -p 31337:31337 webwords-cgolf + curl "http://localhost:31337/?keyword=potato&target=https://www.remarkbox.com" + +Both return ``true`` for potato and ``false`` for lemon, just like the full implementations. + +.. image:: /uploads/2025/10/potato.jpg + :alt: potato + :align: center + :width: 480px + +comparison +========== + +- **Full webwords Python**: 50+ lines, proper structure, error handling +- **Full webwords C**: 268 lines, proper structure, error handling +- **Python golf**: 3 lines, 314 characters, minimal functionality +- **C golf**: 1 line, 1,232 characters, minimal functionality +- **Functionality**: Identical for valid requests + +These golf versions prove webwords' core concept can be distilled to its absolute essence while remaining functional across different programming paradigms. + +.. image:: /uploads/2025/10/unpotato.jpg + :alt: unpotato + :align: center + :width: 480px \ No newline at end of file diff --git a/golf.c b/golf.c new file mode 100644 index 0000000..59078f9 --- /dev/null +++ b/golf.c @@ -0,0 +1,8 @@ +#include +#include +#include +#include +#include +#include +#include +struct M{char*m;size_t s;};size_t w(void*c,size_t z,size_t n,void*u){size_t r=z*n;struct M*m=u;char*p=realloc(m->m,m->s+r+1);if(!p)return 0;m->m=p;memcpy(&m->m[m->s],c,r);m->s+=r;m->m[m->s]=0;return r;}int f(char*u,char**o){CURL*h;struct M c={malloc(1),0};curl_global_init(0);h=curl_easy_init();if(h){curl_easy_setopt(h,10002,u);curl_easy_setopt(h,20011,w);curl_easy_setopt(h,10001,&c);curl_easy_perform(h);curl_easy_cleanup(h);}curl_global_cleanup();*o=c.m;return 1;}void s(int k,char*r){char b[256];sprintf(b,"HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",strlen(r),r);send(k,b,strlen(b),0);}int main(){int v=socket(2,1,0),c;struct sockaddr_in a={2,htons(31337),0};bind(v,(void*)&a,16);listen(v,10);while(1){c=accept(v,0,0);char b[4096],*q,*t,*d;recv(c,b,4095,0);q=strchr(b,'?');if(q&&(t=strstr(q,"target="))&&(q=strstr(q,"keyword="))){char*p;if((p=strchr(t+7,'&')))*(p)=0;else if((p=strchr(t+7,' ')))*(p)=0;if((p=strchr(q+8,'&')))*(p)=0;else if((p=strchr(q+8,' ')))*(p)=0;if(f(t+7,&d))s(c,strstr(d,q+8)?"true":"false");else s(c,"false");free(d);}else s(c,"false");close(c);}} \ No newline at end of file diff --git a/golf.py b/golf.py new file mode 100644 index 0000000..c179e9c --- /dev/null +++ b/golf.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +import http.server as h,urllib.request as u,urllib.parse as p +class S(h.BaseHTTPRequestHandler): + def do_GET(s):q=dict(p.parse_qsl(p.urlparse(s.path).query));s.send_response(200);s.end_headers();s.wfile.write(str(q.get('keyword','')in u.urlopen(q.get('target','')).read().decode()).lower().encode()) +h.HTTPServer(('',31337),S).serve_forever() \ No newline at end of file