xkcd挑战:“ [x]彩色屏幕的百分比”


57

所以我想我们所有人都可能看过这个xkcd漫画

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

我不确定这可能太笼统或太难了。但是挑战在于用任何一种语言创建一个程序,该程序将创建一个窗口,该窗口至少具有两种颜色,并用英语显示每种颜色在屏幕上所占的百分比。

例如 最简单的解决方案是在白色背景上写上黑色字母,上面写着“此图像的百分比为黑色:[x]%。此图像的百分比为白色:[y]%”

您可以根据自己的意愿去疯狂或简单;纯文本是一种有效的解决方案,但如果您制作有趣的图像(如xkcd漫画中的图像),那就更好了!获胜者将是获得最多选票的最有趣和最具创造力的解决方案。因此,继续做一些有趣的事,值得xkcd!:)

所以你怎么看?听起来像是一个有趣的挑战?:)

请在答案中包含正在运行的程序的屏幕截图:)


6
一个“该程序在源代码中具有64个A,4个B,...和34个双引号”程序将更有趣:-)
John Dvorak

2
好...客观的获胜标准是什么?您如何确定任何特定输出是否有效?它是真的,并用数字描述其自身的属性是否足够?
约翰·德沃夏克

@JanDvorak哦,这是一个好人!字母程序实际上是让我最初想到这一点的原因,但是我没有考虑将源代码元素添加到其中!您应该将其发布为问题:)是的,只要它是真实的并描述自己就足够了。嗯,虽然您是对的,但我没有考虑过如何证明最终结果是正确的。我想,我需要一种方法来计算结果图像中每种颜色的所有像素。我现在去调查。(对不起,我的第一个问题有问题……我尝试过,但是我是新手!谢谢:))
WendiKidd 2013年

如果诚实和自我推荐是足够的标准,那么这是我的golfscript竞赛者:("/.*/"阅读:[源代码]不包含换行符)
John Dvorak

@JanDvorak嗯,我在这里尝试了您的代码,除了没有引号之外,输出与代码相同。抱歉,我可能没有解释这个权利。必须至少生成2种颜色,并且以英语句子的某种形式,输出必须生成真实的词,以描述每种颜色在屏幕上所占的百分比。也许这是一个愚蠢的想法。我认为这会很有趣,但实际上可能不起作用:)
WendiKidd 2013年

Answers:


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 2014年

13
最好的部分是,我仍然不确定哪个句子在谈论哪种颜色。
Brilliand 2014年

3
view source由share-elm.com放在那里,而不是编译JS / HTML的一部分。
hoosierEE 2014年

1
@ML取决于单词“ this”的范围。JavaScript程序员了解...
hoosierEE

37

带有HTML的JavaScript

我试图更精确地复制原始漫画。屏幕截图是使用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 2013年

1
令人印象深刻的工作
izabera 2014年

漂亮...但是我认为它必须稳定下来才能成为“解决方案”。还没有完全考虑过-但是当从有限的一组数字字形中进行绘制时,由于不一定存在任意精度的解决方案,因此如果无法以更高的精度解决它,就必须放弃精度你在努力。我认为使用等宽字体预先计算黑色/白色像素也是必要的。
Rebmu博士2014年

您正在使用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)
Kritixi Lithos 17-4-23

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
迟到,但最好的之一。
primo 2014年

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坐标转换为极坐标,首先计算半径(使用图像的中心作为原点)。如果半径在饼图区域内,则计算theta。theta很容易按比例缩放到人口数,这决定了像素的颜色。另一方面,如果半径恰好在饼图的边框上,则将计算抗锯齿值以在图表外部绘制圆。极坐标使一切变得简单!


您主要使用的float是数学库函数的版本,但是不应该fabs这样fabsf吗?
luser droog

从技术上讲,也许是,但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 ,他会在Randall Munroe的采访中详细讨论#688卡通的制作。


1
非常好的解决方案。在@daniero的帖子发表之后,您能否放入程序运行的屏幕截图?:)
Alex Brooks

+1,非常好!感谢您添加屏幕截图:)采访链接很有趣,谢谢!
WendiKidd

9

在此处输入图片说明

图片是100x100,数字是精确的,我的意思是精确-我选择了10000像素的图像,以便百分比可以用两位小数表示。该方法有点数学,有点猜测,并且在Python中有些数字运算。

预先知道可以用4位数字表示百分比,因此我计算出0到9的每个数字中有多少个黑色像素(在8像素高的Arial中),这就是文本的写法。快速功能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位并同时显示更多文本。
Joe Z.

很好的解决方案,有些蛮力数学总是可以解决这类问题!
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测试):

Q基本字形


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.