Thử thách xkcd: Tỷ lệ phần trăm của màn hình là [x] màu


57

Vì vậy, tôi nghĩ rằng tất cả chúng ta có thể đã xem truyện tranh xkcd này :

http://imss.xkcd.com/comics/elf_description.png:

Điều này có thể quá chung chung hoặc quá khó khăn, tôi không chắc chắn. Nhưng thách thức là tạo ra một chương trình bằng bất kỳ ngôn ngữ nào tạo ra một cửa sổ có ít nhất 2 màu và hiển thị bằng các từ tiếng Anh, tỷ lệ phần trăm của màn hình là mỗi màu.

Ví dụ. Giải pháp đơn giản nhất sẽ là một nền trắng với các chữ màu đen có nội dung "Tỷ lệ phần trăm của hình ảnh này là màu đen: [x]%. Tỷ lệ phần trăm của hình ảnh này là màu trắng: [y]%"

Bạn có thể phát điên hoặc đơn giản như bạn muốn; văn bản đơn giản là một giải pháp hợp lệ nhưng nếu bạn tạo ra những hình ảnh thú vị như trong truyện tranh xkcd thì còn gì tuyệt vời hơn! Người chiến thắng sẽ là giải pháp thú vị và sáng tạo nhất được nhiều phiếu bầu nhất. Vì vậy, đi ra ngoài và làm cho một cái gì đó vui vẻ và xứng đáng với xkcd! :)

Vậy bạn nghĩ như thế nào? Nghe có vẻ như một thử thách thú vị? :)

Vui lòng bao gồm một ảnh chụp màn hình chương trình của bạn đang chạy trong câu trả lời của bạn :)


6
Chương trình "chương trình này có 64 chữ A, 4 B, ... và 34 trích dẫn kép trong mã nguồn" sẽ thú vị hơn :-)
John Dvorak

2
OK ... các tiêu chí chiến thắng khách quan là gì? Làm thế nào để bạn xác định nếu bất kỳ đầu ra cụ thể là hợp lệ? Có đủ rằng nó là đúng và nó mô tả một thuộc tính của chính nó bằng số?
John Dvorak

@JanDvorak Oh, đó là một trong những tốt! Chương trình bảng chữ cái thực sự là những gì khiến tôi nghĩ về điều này ban đầu, nhưng tôi đã không xem xét thêm yếu tố mã nguồn vào nó! Bạn nên đăng nó như một câu hỏi :) Vâng, nó là đủ đúng và mô tả chính nó. Hmm, bạn đã đúng, tôi đã không nghĩ về cách tôi sẽ chứng minh rằng kết quả cuối cùng là chính xác. Tôi sẽ cần một cách để đếm tất cả các pixel của mỗi màu trong một hình ảnh kết quả, tôi cho rằng. Tôi sẽ đi điều tra ngay bây giờ. (Xin lỗi, câu hỏi đầu tiên của tôi có vấn đề ... Tôi đã thử nhưng tôi mới biết điều này! Cảm ơn bạn :))
WendiKidd

nếu tính trung thực và tự tham khảo là đủ các tiêu chí, thì đây là thí sinh chơi golf của tôi: "/.*/"(đọc: [mã nguồn] không chứa một dòng mới)
John Dvorak

@JanDvorak Hmm, tôi đã thử mã của bạn ở đây và đầu ra giống như mã trừ khi không có dấu ngoặc kép. Có lẽ tôi không giải thích điều này đúng, xin lỗi. Phải có ít nhất 2 màu được tạo và trong một số dạng của câu tiếng Anh, đầu ra phải tạo ra các từ thực sự mô tả tỷ lệ phần trăm của màn hình mà mỗi màu chiếm. Có lẽ đây là một ý tưởng ngớ ngẩn. Tôi nghĩ rằng nó sẽ rất vui nhưng nó có thể không hoạt động trong thực tế :)
WendiKidd

Câu trả lời:


35

Cây du

Chưa thấy ai sử dụng kẽ hở này: 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

nhập mô tả hình ảnh ở đây


3
Lỗ hổng lớn!
TimTech

Tôi thích điều này !!! Ít nhất là bây giờ, bạn có được dấu kiểm cho các điểm thông minh tuyệt đối. Yêu nó!
WendiKidd

13
Phần tốt nhất là, tôi vẫn không chắc câu nào đang nói về màu nào.
Brilliand

3
view sourceđược đặt ở đó bởi share-elm.com và không phải là một phần của JS / HTML được biên dịch.
hoosierEE

1
@ML Điều đó phụ thuộc vào phạm vi của từ "này". Các lập trình viên JavaScript hiểu ...
hoosierEE 14/03/2016

37

JavaScript với HTML

Tôi đã cố gắng tái tạo truyện tranh gốc chính xác hơn. Ảnh chụp màn hình được chụp bằng thư viện html2canvas. Các con số được tính toán nhiều lần, vì vậy bạn có thể thay đổi kích thước cửa sổ hoặc thậm chí thêm một cái gì đó vào trang trong thời gian thực.

Dùng thử trực tuyến: http://copy.sh/xkcd-688.html

Đây là một ảnh chụp màn hình:

nhập mô tả hình ảnh ở đây

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

Đẹp!! Yêu những điểm tương đồng với truyện tranh xkcd, và thực tế là tôi có thể thay đổi văn bản. Khéo léo! : D
WendiKidd

1
tác phẩm ấn tượng oO
izabera

Tiện lợi ... nhưng tôi nghĩ nó phải ổn định để trở thành một "giải pháp". Không nghĩ hoàn toàn về nó - nhưng vì không nhất thiết phải có giải pháp cho độ chính xác tùy ý khi vẽ từ một tập hợp glyphs chữ số giới hạn, bạn sẽ phải lùi lại độ chính xác nếu không thể giải quyết ở độ chính xác cao hơn bạn đang cố gắng Tôi tưởng tượng rằng việc sử dụng phông chữ đơn cách mà bạn tính toán trước các pixel đen / trắng cũng sẽ cần thiết.
Bác sĩ Rebmu

Bạn đang sử dụng 3 màu, vậy tỷ lệ phần trăm cho màu xám ở đâu? ;)
ML

26

Đang xử lý, 222 ký tự

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

Tôi đã luôn muốn tạo ra phiên bản truyện tranh của riêng mình! Cách đơn giản nhất (duy nhất?) Mà tôi có thể nghĩ đến khi thực hiện việc này là thử và sai - vẽ một cái gì đó, đếm, vẽ lại ...

Chương trình này giải quyết cho một tỷ lệ phần trăm chính xác sau một vài giây. Nó không đẹp lắm, nhưng nó tương tác ; bạn có thể thay đổi kích thước cửa sổ và nó sẽ bắt đầu tính toán lại.

Đã thêm một số dòng mới để dễ đọc:

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;
}

Nó chỉ hiển thị phần trăm pixel trắng; Do khử răng cưa của văn bản, các pixel không phải màu trắng không nhất thiết phải là màu đen. Thời gian hoạt động càng lâu thì càng cần nhiều thời gian để tự cập nhật thay đổi kích thước.

Biên tập:

Vì vậy, đó là một thách thức mã; Tôi sắp xếp nó bằng mọi cách. Có lẽ tôi có thể thêm một số loại biểu đồ sau, nhưng nguyên tắc chung sẽ vẫn như cũ. Sự tương tác là phần gọn gàng tôi nghĩ.


Rất đẹp!! Tôi nghĩ rằng bạn nhận được tín dụng thêm cho sự tương tác; Tôi đã vui vẻ thay đổi kích thước cửa sổ! Rất tuyệt :) Và bạn là phản hồi đầu tiên của tôi! Tôi không biết có ai muốn chơi không, cảm ơn. Bạn đã làm cho ngày của tôi. : D +1! (Mặc dù tôi rất tò mò, tại sao nó lại chậm lại khi thời gian trôi qua và nó tiến gần hơn đến tỷ lệ chính xác? Tôi chỉ tò mò về những gì đang xảy ra, tôi chưa bao giờ thấy ngôn ngữ này trước đây. rất nhiều thứ mới chọc vào trang web này!)
WendiKidd

mũ, ngoại trừ tôi vô tình quên nhấp vào +1. Bây giờ +1 ... haha. Lấy làm tiếc!
WendiKidd

1
Bạn có thể thêm một chức năng khác cho phép người dùng vẽ lên nó bằng chuột, để tăng tính tương tác.
AJMansfield

7
Bóng hộp thần thánh, Người dơi
Bojangles

Nếu bạn muốn chơi gôn, bạn có thể sử dụng background(-1)thay vìbackground(255)
Kritixi Lithos

20

Thử thách lớn. Đây là giải pháp của tôi. Tôi đã cố gắng đến gần nhất có thể với truyện tranh gốc, tôi thậm chí đã sử dụng phông chữ xkcd .

Đó là một ứng dụng WPF, nhưng tôi thường System.Drawinglàm các phần vẽ vì tôi lười biếng.

Khái niệm cơ bản: Trong WPF, windows là Visuals, có nghĩa là chúng có thể được hiển thị. Tôi kết xuất toàn bộ phiên bản Window lên một bitmap, đếm màu đen và toàn màu đen hoặc trắng (bỏ qua các màu xám trong phần làm mịn phông chữ và nội dung) và cũng đếm chúng cho mỗi phần 3 của hình ảnh (cho mỗi bảng). Sau đó, tôi làm lại trên một bộ đếm thời gian. Nó đạt đến trạng thái cân bằng trong vòng một hoặc hai giây.

Tải xuống:

MEGA Luôn kiểm tra các tệp bạn tải xuống để tìm virus, v.v.

Bạn sẽ cần cài đặt phông chữ ở trên vào hệ thống của mình nếu bạn muốn xem nó, nếu không thì đó là phông chữ mặc định của 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>

Mã số:

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;
        }
    }
}

Mã không được dọn sạch, nhưng nó sẽ hơi dễ đọc, xin lỗi.


2
Một mục cuối, nhưng một trong những tốt nhất.
primo

14

C (với SDL và SDL_ttf): Giải pháp thang độ xám

Đây là một giải pháp tận dụng hình thức biểu đồ hình tròn để thu được toàn bộ phổ màu sắc của thang độ xám, xung quanh chỉ dưới 100 dòng.

#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;
}

Như với giải pháp trước đây của tôi, đường dẫn đến tệp phông chữ cần được mã hóa cứng trong nguồn hoặc được thêm vào lệnh xây dựng, ví dụ:

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

Đầu ra của chương trình trông như thế này:

Biểu đồ hình tròn hiển thị phân phối màu pixel đầy đủ thang độ xám

Đây là một điều thú vị để xem, bởi vì tất cả các phép toán làm chậm việc vẽ lại đến nơi bạn có thể thấy chương trình 0 trong giải pháp ổn định. Ước tính đầu tiên rất tự nhiên (vì bề mặt bắt đầu toàn màu đen), và sau đó thu nhỏ xuống kích thước cuối cùng sau khoảng một chục lần lặp lại.

Mã này hoạt động bằng cách lấy số lượng dân số của từng màu pixel trong hình ảnh hiện tại. Nếu số lượng dân số này không khớp với số cuối cùng, thì nó sẽ vẽ lại hình ảnh. Mã lặp lại trên mỗi pixel, nhưng nó biến đổi tọa độ x, y thành tọa độ cực, tính toán trước bán kính (sử dụng tâm của hình ảnh làm gốc). Nếu bán kính nằm trong vùng biểu đồ hình tròn thì nó sẽ tính theta. Theta dễ dàng được chia tỷ lệ theo số lượng dân số, xác định màu pixel. Mặt khác, nếu bán kính nằm ngay trên đường viền của biểu đồ hình tròn, thì giá trị chống răng cưa được tính để vẽ vòng tròn xung quanh bên ngoài biểu đồ. Tọa độ cực làm cho mọi thứ dễ dàng!


Bạn chủ yếu sử dụng các floatphiên bản của các hàm thư viện toán học, nhưng sau đó không fabsnên fabsf?
kẻ lừa đảo người lái xe

Về mặt kỹ thuật, có lẽ, nhưng fabs()là di động hơn.
hộp bánh mì

Đúng, tôi đã gặp rắc rối với việc không được xác định trong các tiêu đề ngay cả khi có mặt trong thư viện. Ngoài ra có hiệu suất ít hơn để đạt được hơn so với siêu việt. :)
kẻ lừa đảo kẻ lừa đảo

10

C (với SDL và SDL_ttf)

Đây là một cách thực hiện rất đơn giản, trong khoảng 60 dòng mã 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;
}

Để biên dịch điều này, bạn cần xác định FONTPATHđể trỏ đến tệp .ttf của phông chữ sẽ sử dụng:

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

Trên hầu hết các máy Linux hiện đại, bạn có thể sử dụng fc-matchtiện ích để tìm kiếm các vị trí phông chữ, vì vậy lệnh biên dịch trở thành:

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

(Tất nhiên bạn có thể thay thế phông chữ được yêu cầu bằng yêu thích cá nhân của bạn.)

Mã đặc biệt yêu cầu không khử răng cưa, để cửa sổ chỉ chứa các pixel đen và trắng.

Cuối cùng, tôi đã được truyền cảm hứng bởi giải pháp tao nhã của @ daniero để cho phép thay đổi kích thước cửa sổ. Bạn sẽ thấy rằng đôi khi chương trình dao động giữa các số đếm, bị mắc kẹt trong một quỹ đạo xung quanh một công cụ thu hút mà nó không bao giờ có thể chạm tới. Khi điều đó xảy ra, chỉ cần thay đổi kích thước cửa sổ một chút cho đến khi nó dừng lại.

Và, theo yêu cầu, đây là giao diện khi tôi chạy trên hệ thống của mình:

Hình ảnh này là 3,36% pixel đen và 96,64% pixel trắng.

Cuối cùng, tôi cảm thấy rằng tôi nên chỉ ra, trong trường hợp bất kỳ ai ở đây chưa từng thấy nó, MAA đã xuất bản một cuộc phỏng vấn với Randall Munroe, trong đó ông thảo luận về việc tạo ra phim hoạt hình # 688 một cách chi tiết.


1
Giải pháp rất hay. Bạn có thể đặt một số ảnh chụp màn hình của chương trình đang chạy, sau bài đăng của @ daniero không? :)
Alex Brooks

+1, rất hay! Cảm ơn đã thêm ảnh chụp màn hình :) Và liên kết phỏng vấn thật thú vị, cảm ơn!
WendiKidd

9

nhập mô tả hình ảnh ở đây

Hình ảnh có kích thước 100x100 và các con số là chính xác và ý tôi là chính xác - tôi đã chọn một hình ảnh 10000 pixel để tỷ lệ phần trăm có thể được biểu thị bằng hai chữ số thập phân. Phương pháp này là một chút toán học, một chút đoán và một số số giòn trong Python.

Thấy rằng tôi biết trước rằng tỷ lệ phần trăm có thể được biểu thị bằng 4 chữ số, tôi đã đếm được có bao nhiêu pixel đen trong mỗi chữ số 0 đến 9, trong Arial cao 8 pixel, đó là những gì văn bản được viết. Tôi đã viết hàm nhanh weightcho bạn biết cần bao nhiêu pixel để viết một số đã cho, được đệm bằng số không để có 4 chữ số:

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

pxlà một chữ số ánh xạ mảng đến số pixel cần thiết. Nếu B là số pixel đen và W là số pixel trắng, chúng ta có B + W = 10000và chúng ta cần:

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

Các hằng số đến từ đâu? 423 là số pixel đen "ban đầu", số pixel đen trong văn bản không có số. 9577 là số pixel trắng ban đầu. Tôi đã phải điều chỉnh lượng pixel đen ban đầu nhiều lần trước khi tôi có được các hằng số sao cho hệ thống trên thậm chí có một giải pháp. Điều này đã được thực hiện bằng cách đoán và vượt qua các ngón tay của tôi.

Hệ thống trên là phi tuyến tính khủng khiếp, vì vậy rõ ràng bạn có thể quên việc giải quyết nó một cách tượng trưng, ​​nhưng những gì bạn có thể làm chỉ là lặp qua mọi giá trị của B, đặt W = 10000 - B và kiểm tra các phương trình một cách rõ ràng.

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

Có thể thực hiện một hình ảnh 250 x 400 để bạn có thể đưa nó đến 3 vị trí thập phân và hiển thị nhiều văn bản hơn trong khi chờ đợi.
Joe Z.

Giải pháp rất hay, một số toán học vũ phu luôn có thể giải quyết loại vấn đề này!
ĐCSTQ

6

QBasic

Vì nỗi nhớ.

Và bởi vì tôi không thực sự biết bất kỳ thư viện hình ảnh nào là ngôn ngữ hiện đại.

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

Phương pháp đầu ra-đếm-lặp lại khá đơn giản. Điều "thú vị" chính là chương trình thử ngẫu nhiên các tỷ lệ khác nhau cho tỷ lệ phần trăm - tôi thấy rằng nó không phải lúc nào cũng hội tụ theo cách khác.

Và đầu ra (được thử nghiệm trên QB64 ):

Đoạn QBasic


3

AWK

... với netpbm và những người trợ giúp khác

Tệp '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"%"
        }
}

Việc chạy:

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

Hình ảnh được viết là 'x.pbm', tôi đã chuyển đổi nó thành png để tải lên:

x.png

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.