виклик xkcd: "Відсоток екрану, який є [x] кольором"


57

Тому я думаю, що ми всі, мабуть, бачили цей xkcd комікс :

http://imgs.xkcd.com/comics/self_description.png:

Це може бути занадто загальним або занадто важким, я не впевнений. Але завдання полягає в тому, щоб створити програму будь-якою мовою, яка створює вікно, яке має щонайменше 2 кольори та відображає англійськими словами, який відсоток екрана є кожним кольором.

колишній Найпростішим рішенням буде білий фон із чорними літерами, на якому написано "Відсоток цього чорного зображення: [x]%. Відсоток цього білого зображення: [y]%"

Ви можете піти як божевільний або простий, як хочете; звичайний текст є правильним рішенням, але якщо ви робите цікаві зображення, як у коміксі xkcd, це ще краще! Переможець стане найсмішнішим та креативним рішенням, яке набере найбільше голосів. Тож виходьте і робіть щось цікаве та гідне xkcd! :)

Так що ж ви думаєте? Звучить як веселе завдання? :)

Будь ласка, включіть у свою відповідь знімок екрана програми, що працює :)


6
"Ця програма має 64 вихідні, 4 B, ... та 34 подвійні лапки у вихідному коді", програма буде цікавішою :-)
Джон Дворак

2
Гаразд ... які об’єктивні критерії виграшу? Як визначити, чи дійсний якийсь конкретний вихід? Чи достатньо, щоб це було правдою, і воно чисельно описує властивість?
Джон Дворак

@JanDvorak О, це добре! Програма з алфавітом насправді змусила мене подумати про це спочатку, але я не розглядав можливість додавання до нього елемента вихідного коду! Ви можете це поставити як питання :) Так, достатньо, щоб це було правдою і описує себе. Хм, ти прав, хоча я не замислювався над тим, як довести, що кінцеві результати були правильними. Мені потрібен спосіб підрахувати всі пікселі кожного кольору в результативному зображенні. Я зараз піду розслідувати це. (Вибачте, у мого першого питання виникли проблеми ... Я спробував, але я в цьому новачок! Дякую :))
WendiKidd

якщо правдивість та самонавіювання є достатніми критеріями, ось мій учасник гольфскрипту "/.*/"(читати: [вихідний код] не містить нового рядка)
Джон Дворак

@JanDvorak Хм, я спробував ваш код тут, і вихід був таким же, як код, за винятком без лапок. Можливо, я не пояснюю цього права, вибачте. Повинно бути створено щонайменше 2 кольори, а в якійсь формі англійського речення вихід повинен створювати справжні слова, які описують, який відсоток екрана займає кожен з кольорів. Можливо, це була дурна ідея. Я думав, що це буде весело, але це може не спрацювати на практиці :)
WendiKidd

Відповіді:


35

В'яз

Ще не бачив, щоб хтось використовував цю лазівку: демо

import Color exposing (hsl)
import Graphics.Element exposing (..)
import Mouse
import Text
import Window

msg a = centered <| Text.color a (Text.fromString "half the screen is this color")

type Pos = Upper | Lower

screen (w,h) (x,y) = 
  let (dx,dy) = (toFloat x - toFloat w / 2, toFloat h / 2 - toFloat y)
      ang = hsl (atan2 dy dx) 0.7 0.5
      ang' = hsl (atan2 dx dy) 0.7 0.5
      box c = case c of
        Upper -> container w (h // 2) middle (msg ang) |> color ang'
        Lower -> container w (h // 2) middle (msg ang') |> color ang
  in  flow down [box Upper, box Lower]

main = Signal.map2 screen Window.dimensions Mouse.position

введіть тут опис зображення


3
Чудова лазівка!
Timtech

Я люблю це!!! Принаймні поки що ви отримуєте галочку для рівних розумних балів. Любіть це!
WendiKidd

13
Найкраще - я досі не впевнений, яке речення говорить про те, якого кольору.
Brilliand

3
Там view sourceрозміщено share-elm.com і не є частиною складеного JS / HTML.
hoosierEE

1
@ML Це залежить від обсягу слова "це". Програмісти JavaScript розуміють ...
hoosierEE

37

JavaScript з HTML

Я намагався точніше відтворити оригінальний комікс. Знімок екрана робиться за допомогою бібліотеки html2canvas. Цифри обчислюються неодноразово, тому ви можете змінити розмір вікна або навіть додати щось до сторінки в режимі реального часу.

Спробуйте в Інтернеті: http://copy.sh/xkcd-688.html

Ось скріншот:

введіть тут опис зображення

<html contenteditable>
<script src=http://html2canvas.hertzen.com/build/html2canvas.js></script>
<script>
onload = function() {
    setInterval(k, 750);
    k();
}
function k() {
    html2canvas(document.body, { onrendered: t });
}
function t(c) {
    z.getContext("2d").drawImage(c, 0, 0, 300, 150);
    c = c.getContext("2d").getImageData(0, 0, c.width, c.height).data;

    for(i = y = 0; i < c.length;) 
        y += c[i++];

    y /= c.length * 255;

    x.textContent = (y * 100).toFixed(6) + "% of this website is white";

    q = g.getContext("2d");

    q.fillStyle = "#eee";
    q.beginPath();
    q.moveTo(75, 75);
    q.arc(75,75,75,0,7,false);
    q.lineTo(75,75);
    q.fill();

    q.fillStyle = "#000";
    q.beginPath();
    q.moveTo(75, 75);
    q.arc(75,75,75,0,6.28319*(1-y),false);
    q.lineTo(75,75);
    q.fill();
}
</script>
<center>
<h2 id=x></h2>
<hr>
<table><tr>
<td>Fraction of<br>this website<br>which is white _/
<td><canvas width=150 id=g></canvas>
<td>&nbsp; Fraction of<br>- this website<br>&nbsp; which is black
</table>
<hr>
0
<canvas style="border-width: 0 0 1px 1px; border-style: solid" id=z></canvas>
<h4>Location of coloured pixels in this website</h4>

Приємно !! Любіть схожість з коміксом xkcd і те, що я можу змінити текст. Акуратно! : D
WendiKidd

1
вражаюча робота
oO

Nifty ... але я думаю, що він повинен стабілізуватися, щоб бути "рішенням". Не продумав це повністю - але оскільки не обов'язково є рішення для довільної точності, коли витягуєте з обмеженого набору цифрових гліфів, вам доведеться відмовитися від точності, якщо її неможливо вирішити з більшою точністю ти намагаєшся. Я думаю, що використання шрифту монопростору, який ви попередньо обчислили чорно-білі пікселі, буде також необхідним.
Доктор Ребму

Ви використовуєте 3 кольори, тож де відсотки для сірого? ;)
ML

26

Обробка, 222 символи

http://i.imgur.com/eQzMGzk.png

Я завжди хотів зробити свою власну версію цього коміксу! Найпростіший (єдиний?) Спосіб, який я міг би подумати, щоб це зробити, - це проба та помилка - намалювати щось, порахувати, намалювати знову ...

Ця програма встановлюється на точний відсоток через кілька секунд. Це не дуже красиво, але це інтерактивно ; ви можете змінити розмір вікна, і воно почне перераховувати.

Додано кілька нових рядків для читабельності:

float s,S,n;
int i;
void draw(){
frame.setResizable(true);
background(255);
fill(s=i=0);
text(String.format("%.2f%% of this is white",S/++n*100),10,10);
loadPixels();
while(i<width*height)if(pixels[i++]==-1)s++;
S+=s/height/width;
}

Він показує лише відсоток білих пікселів; Через антиалійний текст небілі пікселі не обов'язково чорні. Чим довше він працює, тим більше часу знадобиться для оновлення на розмір.

Редагувати:

Отже, це виклик коду; Я все одно гольфував це будь-коли. Можливо, я можу пізніше додати якісь графіки, але загальний принцип залишився б тим самим. Я думаю, що інтерактивність є акуратною частиною.


Дуже хороша!! Я думаю, ви отримуєте додатковий кредит на інтерактивність; Я весело змінив розмір вікна! Дуже круто :) І ти моя перша в історії відповідь! Я не знав, чи хтось захоче грати, тож спасибі. Ти зробив мій день. : D +1! (Мені цікаво, чому це сповільнюється з часом, і він стає ближчим до досягнення правильного відсотка? Мені просто цікаво, що відбувається, я ніколи раніше не бачив цієї мови. Я бачу багато нового, що
розкочує

headdesk Крім того, що я випадково забув натиснути +1. Зараз +1 ... ха-ха. Вибачте!
WendiKidd

1
Ви можете додати ще одну функцію, яка дозволяє користувачам малювати на ній мишею для додаткової інтерактивності.
AJMansfield

7
Holy box shadow, Batman
Bojangles

Якщо ви хочете , щоб грати в гольф, ви можете використовувати background(-1)замістьbackground(255)
Kritixi Lithos

20

Великий виклик. Ось моє рішення. Я намагався максимально наблизитися до оригінального коміксу, навіть використав шрифт xkcd .

Це додаток WPF, але я System.Drawingробив деталі для малювання, тому що я лінивий.

Основна концепція: У WPF вікна є Visuals, це означає, що вони можуть бути надані. Я відтворюю весь екземпляр Window на растрову карту, підраховую чорний і загальний чорний або білий (ігноруючи сірі кольори шрифту та ін.), А також підраховую їх для кожного 3-го зображення (для кожної панелі). Потім я знову це роблю на таймері. Він досягає рівноваги протягом секунди або двох.

Завантажити:

MEGA Завжди перевіряйте завантажені файли на наявність вірусів тощо тощо.

Вам потрібно буде встановити шрифт вище у вашій системі, якщо ви хочете його бачити, інакше це WPF за замовчуванням.

XAML:

<Window
 x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="xkcd: 688" Height="300" Width="1000" WindowStyle="ToolWindow">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.3*"/>
            <ColumnDefinition Width="0.3*"/>
            <ColumnDefinition Width="0.3*"/>
        </Grid.ColumnDefinitions>

        <Border BorderBrush="Black" x:Name="bFirstPanel" BorderThickness="3" Padding="10px" Margin="0 0 10px 0">
            <Grid>
                <Label FontSize="18" FontFamily="xkcd" VerticalAlignment="Top">Fraction of this window that is white</Label>
                <Label FontSize="18" FontFamily="xkcd" VerticalAlignment="Bottom">Fraction of this window that is black</Label>
                <Image x:Name="imgFirstPanel"></Image>
            </Grid>
        </Border>
        <Border Grid.Column="1" x:Name="bSecondPanel" BorderBrush="Black" BorderThickness="3" Padding="10px" Margin="10px 0">
            <Grid>
                <TextBlock FontSize="18" FontFamily="xkcd" VerticalAlignment="Top" HorizontalAlignment="Left">Amount of <LineBreak></LineBreak>black ink <LineBreak></LineBreak>by panel:</TextBlock>
                <Image x:Name="imgSecondPanel"></Image>
            </Grid>
        </Border>
        <Border Grid.Column="2" x:Name="bThirdPanel" BorderBrush="Black" BorderThickness="3" Padding="10px" Margin="10px 0 0 0">
            <Grid>
                <TextBlock FontSize="18" FontFamily="xkcd" VerticalAlignment="Top" HorizontalAlignment="Left">Location of <LineBreak></LineBreak>black ink <LineBreak></LineBreak>in this window:</TextBlock>
                <Image x:Name="imgThirdPanel"></Image>
            </Grid>
        </Border>

    </Grid>
</Window>

Код:

using System;
using System.Drawing;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Brushes = System.Drawing.Brushes;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        private Timer mainTimer = new Timer();
        public MainWindow()
        {
            InitializeComponent();

            Loaded += (o1,e1) =>
                          {
                              mainTimer = new Timer(1000/10);
                              mainTimer.Elapsed += (o, e) => {
                                  try
                                  {
                                      Dispatcher.Invoke(Refresh);
                                  } catch(Exception ex)
                                  {
                                      // Nope
                                  }
                              };
                              mainTimer.Start();
                          };
        }

        private void Refresh()
        {
            var actualh = this.RenderSize.Height;
            var actualw = this.RenderSize.Width;

            var renderTarget = new RenderTargetBitmap((int) actualw, (int) actualh, 96, 96, PixelFormats.Pbgra32);
            var sourceBrush = new VisualBrush(this);

            var visual = new DrawingVisual();
            var context = visual.RenderOpen();

            // Render the window onto the target bitmap
            using (context)
            {
                context.DrawRectangle(sourceBrush, null, new Rect(0,0, actualw, actualh));
            }
            renderTarget.Render(visual);

            // Create an array with all of the pixel data
            var stride = (int) actualw*4;
            var data = new byte[stride * (int)actualh];
            renderTarget.CopyPixels(data, stride, 0);

            var blackness = 0f;
            var total = 0f;

            var blacknessFirstPanel = 0f;
            var blacknessSecondPanel = 0f;
            var blacknessThirdPanel = 0f;
            var totalFirstPanel = 0f;
            var totalSecondPanel = 0f;
            var totalThirdPanel = 0f;

            // Count all of the things
            for (var i = 0; i < data.Length; i += 4)
            {
                var b = data[i];
                var g = data[i + 1];
                var r = data[i + 2];

                if (r == 0 && r == g && g == b)
                {
                    blackness += 1;
                    total += 1;

                    var x = i%(actualw*4) / 4;

                    if(x < actualw / 3f)
                    {
                        blacknessFirstPanel += 1;
                        totalFirstPanel += 1;
                    } else if (x < actualw * (2f / 3f))
                    {
                        blacknessSecondPanel += 1;
                        totalSecondPanel += 1;
                    }
                    else if (x < actualw)
                    {
                        blacknessThirdPanel += 1;
                        totalThirdPanel += 1;
                    }
                } else if (r == 255 && r == g && g == b)
                {
                    total += 1;

                    var x = i % (actualw * 4) / 4;

                    if (x < actualw / 3f)
                    {
                        totalFirstPanel += 1;
                    }
                    else if (x < actualw * (2f / 3f))
                    {
                        totalSecondPanel += 1;
                    }
                    else if (x < actualw)
                    {
                        totalThirdPanel += 1;
                    }
                }
            }

            var black = blackness/total;

            Redraw(black, blacknessFirstPanel, blacknessSecondPanel, blacknessThirdPanel, blackness, renderTarget);
        }

        private void Redraw(double black, double firstpanel, double secondpanel, double thirdpanel, double totalpanels, ImageSource window)
        {
            DrawPieChart(black);
            DrawBarChart(firstpanel, secondpanel, thirdpanel, totalpanels);
            DrawImage(window);
        }

        void DrawPieChart(double black)
        {
            var w = (float)bFirstPanel.ActualWidth;
            var h = (float)bFirstPanel.ActualHeight;
            var padding = 0.1f;

            var b = new Bitmap((int)w, (int)h);
            var g = Graphics.FromImage(b);

            var px = padding*w;
            var py = padding*h;

            var pw = w - (2*px);
            var ph = h - (2*py);

            g.DrawEllipse(Pens.Black, px,py,pw,ph);

            g.FillPie(Brushes.Black, px, py, pw, ph, 120, (float)black * 360);

            g.DrawLine(Pens.Black, 30f, h * 0.1f, w / 2 + w * 0.1f, h / 2 - h * 0.1f);
            g.DrawLine(Pens.Black, 30f, h - h * 0.1f, w / 2 - w * 0.2f, h / 2 + h * 0.2f);

            imgFirstPanel.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(b.Width, b.Height));
        }

        void DrawBarChart(double b1, double b2, double b3, double btotal)
        {
            var w = (float)bFirstPanel.ActualWidth;
            var h = (float)bFirstPanel.ActualHeight;
            var padding = 0.1f;

            var b = new Bitmap((int)w, (int)h);
            var g = Graphics.FromImage(b);

            var px = padding * w;
            var py = padding * h;

            var pw = w - (2 * px);
            var ph = h - (2 * py);

            g.DrawLine(Pens.Black, px, py, px, ph+py);
            g.DrawLine(Pens.Black, px, py + ph, px+pw, py+ph);

            var fdrawbar = new Action<int, double>((number, value) =>
                {
                    var height = ph*(float) value/(float) btotal;
                    var width = pw/3f - 4f;

                    var x = px + (pw/3f)*(number-1);
                    var y = py + (ph - height);

                    g.FillRectangle(Brushes.Black, x, y, width, height);
                });

            fdrawbar(1, b1);
            fdrawbar(2, b2);
            fdrawbar(3, b3);

            imgSecondPanel.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(b.Width, b.Height));
        }

        void DrawImage(ImageSource window)
        {
            imgThirdPanel.Source = window;
        }
    }
}

Код не очищено, але він повинен бути дещо читабельним, вибачте.


2
Пізній запис, але один з найкращих.
примо

14

C (з SDL та SDL_ttf): Розчин сірого масштабу

Ось рішення, яке використовує перевагу форми кругової діаграми, щоб захопити повний спектр кольорів пікселів у відтінках сірого, розміщуючись приблизно під 100 рядків.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "SDL.h"
#include "SDL_ttf.h"

int main(void)
{
    SDL_Surface *screen, *buffer, *caption;
    SDL_Color pal[256];
    SDL_Rect rect;
    SDL_Event event;
    TTF_Font *font;
    int levels[256], plev[256];
    Uint8 *p;
    float g;
    int cr, redraw, hoffset, h, n, v, w, x, y;

    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();
    screen = SDL_SetVideoMode(640, 480, 0, SDL_ANYFORMAT | SDL_RESIZABLE);
    font = TTF_OpenFont(FONTPATH, 24);
    buffer = 0;
    for (;;) {
        if (!buffer) {
            buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h,
                                          8, 0, 0, 0, 0);
            for (n = 0 ; n < 256 ; ++n)
                pal[n].r = pal[n].g = pal[n].b = n;
            SDL_SetColors(buffer, pal, 0, 256);
        }
        memcpy(plev, levels, sizeof levels);
        memset(levels, 0, sizeof levels);
        SDL_LockSurface(buffer);
        p = buffer->pixels;
        for (h = 0 ; h < buffer->h ; ++h) {
            for (w = 0 ; w < buffer->w ; ++w)
                ++levels[p[w]];
            p += buffer->pitch;
        }
        for (n = 1 ; n < 256 ; ++n)
            levels[n] += levels[n - 1];
        redraw = memcmp(levels, plev, sizeof levels);
        if (redraw) {
            SDL_UnlockSurface(buffer);
            SDL_FillRect(buffer, NULL, 255);
            caption = TTF_RenderText_Shaded(font,
                        "Distribution of pixel color in this image",
                        pal[0], pal[255]);
            rect.x = (buffer->w - caption->w) / 2;
            rect.y = 4;
            hoffset = caption->h + 4;
            SDL_BlitSurface(caption, NULL, buffer, &rect);
            SDL_FreeSurface(caption);
            SDL_LockSurface(buffer);
            cr = buffer->h - hoffset;
            cr = (cr < buffer->w ? cr : buffer->w) / 2 - 4;
            p = buffer->pixels;
            for (h = 0 ; h < buffer->h ; ++h) {
                y = h - (screen->h + hoffset) / 2;
                for (w = 0 ; w < buffer->w ; ++w) {
                    x = w - buffer->w / 2;
                    g = sqrtf(x * x + y * y);
                    if (g < cr - 1) {
                        g = atanf((float)y / (x + g));
                        v = levels[255] * (g / M_PI + 0.5);
                        for (n = 0 ; n < 255 && levels[n] < v ; ++n) ;
                        p[w] = n;
                    } else if (g < cr + 1) {
                        p[w] = (int)(128.0 * fabs(g - cr));
                    }
                }
                p += buffer->pitch;
            }
        }
        SDL_UnlockSurface(buffer);
        SDL_BlitSurface(buffer, NULL, screen, NULL);
        SDL_UpdateRect(screen, 0, 0, 0, 0);
        if (redraw ? SDL_PollEvent(&event) : SDL_WaitEvent(&event)) {
            if (event.type == SDL_QUIT)
                break;
            if (event.type == SDL_VIDEORESIZE) {
                SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
                                 SDL_ANYFORMAT | SDL_RESIZABLE);
                SDL_FreeSurface(buffer);
                buffer = 0;
            }
        }
    }
    SDL_Quit();
    TTF_Quit();
    return 0;
}

Як і в моєму попередньому рішенні, шлях до файлу шрифту повинен бути або жорстко закодований у джерелі, або доданий до команди збірки, наприклад:

gcc -Wall -o xkcdgolf `sdl-config --cflags`
    -DFONTPATH=`fc-match --format='"%{file}"' :bold`
    xkcdgolf.c -lSDL_ttf `sdl-config --libs` -lm

Вихід програми виглядає приблизно так:

Кругова діаграма, що показує повне розподіл кольорів пікселів у відтінках сірого

Це цікаво спостерігати, тому що вся математика сповільнює перемальовки до того, де можна побачити нуль програми на стабільному рішенні. Перша оцінка дико відключається (оскільки поверхня починає повністю чорніти), а потім зменшується до остаточного розміру приблизно через десяток або більше ітерацій.

Код працює, беручи підрахунок сукупності кожного кольору пікселів у поточному зображенні. Якщо ця кількість населення не відповідає останній, вона перемальовує зображення. Код перетворюється на кожен піксель, але він перетворює координати x, y в полярні координати, обчислюючи спочатку радіус (використовуючи центр зображення як джерело). Якщо радіус знаходиться в межах кругової діаграми, то він обчислює тету. Тета легко масштабується до кількості населення, яка визначає колір пікселів. З іншого боку, якщо радіус знаходиться прямо на межі кругової діаграми, то обчислюється протизріджене значення, щоб намалювати коло навколо зовнішньої сторони діаграми. Полярні координати роблять все просто!


Ви в основному використовуєте floatверсії математичних функцій бібліотеки, але тоді їх не повинно fabsбути fabsf?
luser droog

Технічно, можливо, але fabs()портативніше.
хлібниця

Щоправда, у мене виникли проблеми з тим, що його не визначають у заголовках, навіть коли він присутній у бібліотеці. Також можна досягти меншої продуктивності, ніж з трансцендентами. :)
luser droog

10

C (із SDL та SDL_ttf)

Ось дуже проста реалізація, приблизно в 60 рядках коду С:

#include <stdio.h>
#include "SDL.h"
#include "SDL_ttf.h"

int main(void)
{
    char buf[64];
    SDL_Surface *screen, *text;
    SDL_Rect rect;
    SDL_Color black;
    SDL_Event event;
    TTF_Font *font;
    Uint32 blackval, *p;
    int size, b, prevb, h, i;

    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();
    screen = SDL_SetVideoMode(640, 480, 32, SDL_ANYFORMAT | SDL_RESIZABLE);
    font = TTF_OpenFont(FONTPATH, 32);
    black.r = black.g = black.b = 0;
    blackval = SDL_MapRGB(screen->format, 0, 0, 0);

    b = -1;
    for (;;) {
        prevb = b;
        b = 0;
        SDL_LockSurface(screen);
        p = screen->pixels;
        for (h = screen->h ; h ; --h) {
            for (i = 0 ; i < screen->w ; ++i)
                b += p[i] == blackval;
            p = (Uint32*)((Uint8*)p + screen->pitch);
        }
        SDL_UnlockSurface(screen);
        size = screen->w * screen->h;
        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
        sprintf(buf, "This image is %.2f%% black pixels", (100.0 * b) / size);
        text = TTF_RenderText_Solid(font, buf, black);
        rect.x = (screen->w - text->w) / 2;
        rect.y = screen->h / 2 - text->h;
        SDL_BlitSurface(text, NULL, screen, &rect);
        SDL_FreeSurface(text);
        sprintf(buf, "and %.2f%% white pixels.", (100.0 * (size - b)) / size);
        text = TTF_RenderText_Solid(font, buf, black);
        rect.x = (screen->w - text->w) / 2;
        rect.y = screen->h / 2;
        SDL_BlitSurface(text, NULL, screen, &rect);
        SDL_FreeSurface(text);
        SDL_UpdateRect(screen, 0, 0, 0, 0);
        if (b == prevb ? SDL_WaitEvent(&event) : SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT)
                break;
            if (event.type == SDL_VIDEORESIZE)
                SDL_SetVideoMode(event.resize.w, event.resize.h, 32,
                                 SDL_ANYFORMAT | SDL_RESIZABLE);
        }
    }

    TTF_Quit();
    SDL_Quit();
    return 0;
}

Щоб скласти це, вам потрібно визначити, FONTPATHщоб вказати на .ttf файл шрифту, який слід використовувати:

gcc -Wall -o xkcdgolf `sdl-config --cflags`
    -DFONTPATH='"/usr/share/fonts/truetype/freefont/FreeSansBold.ttf"'
    xkcdgolf.c -lSDL_ttf `sdl-config --libs`

На більшості сучасних машин Linux ви можете використовувати fc-matchутиліту для пошуку місця розташування шрифту, тому команда компіляції стає:

gcc -Wall -o xkcdgolf `sdl-config --cflags`
    -DFONTPATH=`fc-match --format='"%{file}"' :bold`
    xkcdgolf.c -lSDL_ttf `sdl-config --libs`

(Звичайно, ви можете замінити потрібний шрифт своїм особистим улюбленим.)

Код спеціально не вимагає антизбудження, щоб вікно містило лише чорні та білі пікселі.

Нарешті, мене надихнуло елегантне рішення @ daniero, що дозволяє змінити розмір вікон. Ви побачите, що інколи програма коливається між підрахунками, застряглими на орбіті навколо атрактора, до якого він ніколи не може досягти. Коли це станеться, просто змініть розмір вікна, поки воно не зупиниться.

І, на запит, ось як це виглядає, коли я запускаю його у своїй системі:

Це зображення становить 3,36% чорних пікселів і 96,64% білих пікселів.

Нарешті, я відчуваю, що мені слід зазначити, якщо хтось тут цього ще не бачив, MAA опублікував інтерв'ю з Рендаллом Манро, в якому він детально обговорює створення мультфільму № 688.


1
Дуже приємне рішення. Чи можете ви розмістити скріншоти програми, що працює, після публікації від @ daniero? :)
Алекс Брукс

+1, дуже приємно! Дякуємо, що додали скріншот :) І посилання на інтерв'ю цікаве, дякую!
WendiKidd

9

введіть тут опис зображення

Зображення розміром 100x100, а цифри є точними, і я маю на увазі точні - я вибрав зображення 10000 пікселів, щоб відсотки могли бути виражені двома десятковими знаками. Метод був трохи математики, трохи здогадів, і деяка кількість хрускіт у Python.

Бачачи, як я заздалегідь знав, що відсоткові відсотки можна виразити чотирма цифрами, я порахував, скільки чорних пікселів було в кожній з цифр від 0 до 9, Arial високою 8 пікселями, про що пишеться в тексті. Я написав швидка функція, weightяка повідомляє, скільки пікселів потрібно записати задане число, залишене нулями, щоб мати 4 цифри:

def weight(x):
    total = 4 * px[0]
    while x > 0:
       total = total - px[0] + px[x % 10]
       x = x / 10
    return total

pxце масив, що відображає цифри до кількості необхідних пікселів. Якщо B - кількість чорних пікселів, а W - кількість білих пікселів, у нас є B + W = 10000, і нам потрібно:

B = 423 + weight(B) + weight(W)
W = 9577 - weight(B) - weight(W)

Звідки взялися константи? 423 - "початкове" число чорних пікселів, кількість чорних пікселів у тексті без цифр. 9577 - кількість початкових білих пікселів. Мені довелося кілька разів коригувати кількість початкових чорних пікселів, перш ніж мені вдалося отримати константи, щоб у вищевказаній системі було навіть рішення. Це було зроблено здогадкою та схрещуванням моїх пальців.

Наведена вище система жахливо нелінійна, тому, очевидно, ви можете забути про її вирішення символічно, але те, що ви можете зробити, це просто провести цикл через кожне значення B, встановити W = 10000 - B, і перевірити рівняння чітко.

>>> for b in range(10000 + 1):
...     if b == weight(b) + weight(10000 - b)+423: print b;
...
562
564

Можливо, зробіть зображення розміром 250 x 400, щоб ви могли дістати його до 3 знаків після коми і тим часом відобразити більше тексту.
Джо З.

Дуже приємне рішення, якась жорстока математика завжди може вирішити подібні проблеми!
КПК

6

QBasic

Тому що ностальгія.

А тому, що я не знаю жодної бібліотеки зображень, це сучасна мова.

SCREEN 9

CONST screenWidth = 640
CONST screenHeight = 350
CONST totalPixels# = screenWidth * screenHeight

accuracy = 6

newWhite# = 0
newGreen# = 0
newBlack# = totalPixels#

DO
    CLS
    white# = newWhite#
    green# = newGreen#
    black# = newBlack#

    ' Change the precision of the percentages every once in a while
    ' This helps in finding values that converge
    IF RND < .1 THEN accuracy = INT(RND * 4) + 2
    format$ = "###." + LEFT$("######", accuracy) + "%"

    ' Display text
    LOCATE 1
    PRINT "Percentage of the screen which is white:";
    PRINT USING format$; pct(white#)
    LOCATE 4
    PRINT white#; "/"; totalPixels#; "pixels"
    LOCATE 7
    PRINT "Percentage of the screen which is black:";
    PRINT USING format$; pct(black#)
    LOCATE 10
    PRINT black#; "/"; totalPixels#; "pixels"
    LOCATE 13
    PRINT "Percentage of the screen which is green:";
    PRINT USING format$; pct(green#)
    LOCATE 16
    PRINT green#; "/"; totalPixels#; "pixels"

    ' Display bar graphs
    LINE (0, 16)-(pct(white#) / 100 * screenWidth, 36), 2, BF
    LINE (0, 100)-(pct(black#) / 100 * screenWidth, 120), 2, BF
    LINE (0, 184)-(pct(green#) / 100 * screenWidth, 204), 2, BF

    newBlack# = pixels#(0)
    newGreen# = pixels#(2)
    newWhite# = pixels#(15)
LOOP UNTIL black# = newBlack# AND white# = newWhite# AND green# = newGreen#

' Wait for user keypress before ending program: otherwise the "Press any
' key to continue" message would instantly make the results incorrect!
x$ = INPUT$(1)


FUNCTION pixels# (colr)
' Counts how many pixels of the given color are on the screen

pixels# = 0

FOR i = 0 TO screenWidth - 1
    FOR j = 0 TO screenHeight - 1
        IF POINT(i, j) = colr THEN pixels# = pixels# + 1
    NEXT j
NEXT i

END FUNCTION

FUNCTION pct (numPixels#)
' Returns percentage, given a number of pixels

pct = numPixels# / totalPixels# * 100

END FUNCTION

Досить простий метод повторного підрахунку результатів. Головне "цікаве", що програма випадковим чином пробує різні точності для відсотків - я виявив, що вона не завжди збігається інакше.

І вихід (тестований на QB64 ):

QBasic метаграфія


3

AWK

... з netpbm та іншими помічниками

Файл 'x':

BEGIN {
        FS=""
        n++
        while(n!=m) {
                c="printf '%s\n' '"m"% black pixels'"
                c=c" '"100-m"% white pixels'"
                c=c" | pbmtext -space 1 -lspace 1 | pnmtoplainpnm | tee x.pbm"
                n=m
                delete P
                nr=0
                while(c|getline==1) if(++nr>2) for(i=1;i<=NF;i++) P[$i]++
                close(c)
                m=100*P[1]/(P[0]+P[1])
                print m"%"
        }
}

Біг:

$ awk -f x
4.44242%
5.2424%
5.04953%
5.42649%
5.27746%
5.1635%
5.15473%
5.20733%
5.20733%

Зображення написано як "x.pbm", я перетворив його в png для завантаження:

x.png

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.