Задача xkcd: «Процент экрана, на котором [x] цвет»


57

Поэтому я думаю, что мы все, наверное, видели этот комикс xkcd :

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

Это может быть слишком общим или слишком сложным, я не уверен. Но задача состоит в том, чтобы создать программу на любом языке, которая создает окно, которое имеет как минимум 2 цвета и отображает английскими словами, какой процент экрана составляет каждый цвет.

ех. Простейшим решением будет белый фон с черными буквами, на которых написано: «Процент этого изображения черного цвета: [x]%. Процент этого изображения белого цвета: [y]%»

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

Так что ты думаешь? Звучит как забавный вызов? :)

Пожалуйста, включите скриншот вашей программы в ответ :)


6
«Эта программа имеет 64 A, 4 B, ... и 34 двойные кавычки в исходном коде», программа была бы более интересной :-)
Джон Дворжак

2
ОК ... каковы объективные критерии победы? Как вы определяете, является ли какой-либо конкретный вывод действительным? Достаточно ли того, что оно истинно и численно описывает свойство себя?
Джон Дворак

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

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

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

Ответы:


35

вяз

Еще никто не использовал эту лазейку: demo

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
изабера

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

Вы используете 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! (Хотя мне любопытно, почему он замедляется с течением времени и приближается к достижению правильного процента? Мне просто любопытно, что происходит, я никогда раньше не видел этот язык. Я вижу вокруг этого сайта много нового!)
WendiKidd

Headdesk Кроме того, что я случайно забыл нажать +1. Теперь +1 ... хаха. Сожалею!
WendiKidd

1
Вы можете добавить другую функцию, которая позволяет пользователям рисовать на ней мышью, для дополнительной интерактивности.
AJMansfield

7
Шкатулка теней, Бэтмен
Bojangles

Если вы хотите background(-1)background(255)
играть

20

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

Это приложение WPF, но я System.Drawingрисовал детали, потому что я ленивый.

Основная концепция: в WPF окна есть Visuals, что означает, что они могут быть отображены. Я рендерим весь экземпляр Window на растровое изображение, подсчитываю черный и общий черный или белый (игнорируя серые цвета в сглаживании шрифтов и прочее), а также подсчитываю их для каждого третьего изображения (для каждой панели). Затем я делаю это снова по таймеру. Это достигает равновесия в течение секунды или двух.

Скачать:

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?
Люзер Дрог

Технически, возможно, но fabs()более портативно.
хлебница

Правда, у меня были проблемы с тем, что он не был определен в заголовках, даже когда он присутствует в библиотеке. Кроме того, можно добиться меньшей производительности, чем с трансцендентными. :)
luser droog

10

C (с SDL и SDL_ttf)

Вот очень простая реализация, примерно в 60 строках кода C:

#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утилиту для поиска местоположения шрифтов, поэтому команда compile становится такой:

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.

Поскольку я заранее знал, что проценты могут быть выражены в 4 цифры, я посчитал, сколько черных пикселей было в каждой из цифр от 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 десятичными разрядами и тем временем отобразить больше текста.
Джо З.

Очень хорошее решение, математика грубой силы всегда может решить такие проблемы!
CCP

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 metagraph


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.