xkcd challenge: “[x] renkli ekranın yüzdesi”


57

Sanırım hepimiz muhtemelen bu xkcd çizgi romanını gördük :

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

Bu çok genel veya çok zor olabilir, emin değilim. Ancak zorluk, en az 2 renge sahip bir pencere oluşturan ve ekranın yüzde kaçının renk olduğunu İngilizce kelimelerle gösteren herhangi bir dilde bir program oluşturmaktır.

ex. En basit çözüm, "Siyah olan bu görüntünün yüzdesi: [x]%. Beyaz olan bu görüntünün yüzdesi" yazan siyah harfli beyaz bir arka plan olacaktır.

İstediğin kadar çılgın ya da basit gidebilirsin; düz metin geçerli bir çözümdür, ancak xkcd çizgi romanındaki gibi ilginç görüntüler yaparsanız bu daha da iyi! Kazanan, en fazla oyu alan en eğlenceli ve yaratıcı çözüm olacak. Öyleyse devam edin ve eğlenceli ve xkcd değerinde bir şeyler yapın! :)

Yani ne düşünüyorsun? Eğlenceli bir meydan okuma gibi geliyor mu? :)

Lütfen cevabınıza yazılan programın ekran görüntüsünü ekleyin :)


6
Bir "bu program 64 A, 4 B, ... ve kaynak kodunda 34 çift alıntı" programı daha ilginç olurdu :-)
John Dvorak

2
Tamam ... nesnel kazanma kriterleri nelerdir? Belirli bir çıktının geçerli olup olmadığını nasıl belirlersiniz? Bunun doğru olması ve kendisinin bir özelliğini sayısal olarak tanımlaması yeterli mi?
John Dvorak

@JanDvorak Oh, bu iyi bir tane! Alfabe programı aslında bunu başlangıçta düşündüren şeydi, ancak kaynak kod öğesini eklemeyi düşünmedim! Bunu bir soru olarak göndermelisiniz :) Evet, bunun doğru olması ve kendisini tanımlaması yeterlidir. Hmm, haklısın, sonuçların doğru olduğunu nasıl kanıtlayacağımı düşünmedim. Sanırım, sonuçtaki her bir rengin tüm piksellerini saymak için bir yola ihtiyacım var. Şimdi bunu araştıracağım. (Üzgünüm ilk sorumun sorunları vardı ... Denedim ama bu konuda yeniyim! Teşekkür ederim :))
WendiKidd

truthiness ve kendine referans yeterli kriterler ise, işte golfscript yarışmacı: "/.*/"(okuyun: [kaynak kodu] Yeni satır içermez)
John Dvorak

@JanDvorak Hmm, kodunuzu burada denedim ve çıktı tırnak işaretleri dışında aynıydı. Belki de bu hakkı açıklamıyorum, üzgünüm. Üretilen en az 2 renk olmalı ve bir İngilizce cümle biçiminde çıktı, renklerin her birinin kapladığı ekranın yüzde kaçını tanımlayan gerçek kelimeler üretmelidir. Belki bu aptalca bir fikirdi. Eğlenceli olacağını düşündüm ama pratikte çalışmayabilir :)
WendiKidd

Yanıtlar:


35

Karaağaç

Henüz bu boşluğu kullanan hiç kimse görmedim: 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

görüntü tanımını buraya girin


3
Harika kaçamak!
Timtech

Bunu seviyorum!!! En azından şimdilik, akıllı puanlar için onay işareti alıyorsunuz. Sevdim!
WendiKidd

13
En iyi yanı, hangi cümlenin hangi renkten bahsettiğinden hala emin değilim.
Brilliand

3
Buraya view sourceshare-elm.com tarafından konulur ve derlenen JS / HTML'nin bir parçası değildir.
HoosierEE

1
@ ML Bu, "this" kelimesinin kapsamına bağlıdır. JavaScript programcıları anlıyor ...
hoosierEE

37

HTML ile JavaScript

Orijinal çizgi romanı daha kesin olarak yeniden üretmeye çalıştım. Html2canvas kütüphanesi kullanılarak bir ekran görüntüsü alınır. Sayılar tekrar tekrar hesaplanır, böylece pencereyi yeniden boyutlandırabilir veya sayfaya gerçek zamanlı olarak bir şey ekleyebilirsiniz.

Çevrimiçi deneyin: http://copy.sh/xkcd-688.html

İşte bir ekran görüntüsü:

görüntü tanımını buraya girin

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

Güzel!! Xkcd çizgi romanına olan benzerlikleri ve metni değiştirebildiğim gerçeğini seviyorum. Temiz! : D
WendiKidd

1
etkileyici çalışma oO
izabera

Şık ... ama bence bir "çözüm" olmak için dengelemek gerekiyor. Tamamen düşünmedim - ancak sınırlı bir sayıdaki glif dizisinden çizim yaparken keyfi bir hassasiyet için mutlaka bir çözüm olmadığından, yüksek hassasiyette çözülemezse kesinliği geri almak zorunda kalırsınız. deniyorsun Siyah / beyaz pikselleri önceden hesapladığınız bir monospace fontu kullanmanın da gerekli olacağını hayal ediyorum.
Doktor Rebmu,

3 renk kullanıyorsunuz, peki gri yüzdeleri nerede? ;)
ML

26

İşleme, 222 karakter

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

Her zaman bu çizgi romanın kendi versiyonunu kendim yapmak istemiştim! Bunu yapmayı düşündüğüm en basit (yalnızca?) Yöntem deneme yanılma oldu - bir şeyler çiz, say, tekrar çek ...

Bu program birkaç saniye sonra doğru bir yüzdeye yerleşir. Çok hoş değil ama etkileşimli ; Pencereyi yeniden boyutlandırabilirsiniz ve yeniden hesaplamaya başlayacaktır.

Okunabilirlik için bazı yeni satırlar eklendi:

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

Yalnızca beyaz piksellerin yüzdesini gösterir; Metnin antialiasing nedeniyle, beyaz olmayan pikseller mutlaka siyah değildir. Ne kadar uzun süre çalışırsa, yeniden boyutlandırmada kendini güncellemesi gerekecek.

Düzenle:

Yani, bir kod-meydan okumadır; Ben yine de golf oynamıştım. Belki sonradan bir çeşit grafik ekleyebilirim, ancak genel ilke aynı kalacaktı. Etkileşim, bence temiz bir bölüm.


Çok hoş!! Bence etkileşim için fazladan kredi alırsın; Pencereyi yeniden boyutlandırırken çok eğlendim! Çok havalı :) Ve sen benim ilk yanıtımsın! Kimse oynamak ister mi bilmiyordum, bu yüzden teşekkürler. Günümü sen yaptın. : D + 1! (Yine de merak ediyorum, zaman geçtikçe neden yavaşlıyor ve doğru yüzdeye ulaşmaya yaklaşıyor? Sadece ne olduğunu merak ediyorum, bu dili daha önce hiç görmedim. Bu siteyi saran yeni şeyler çok!)
WendiKidd

headdesk hariç +1 tuşunu yanlışlıkla unuttum. Şimdi +1 ... haha. Üzgünüm!
WendiKidd

1
Daha fazla etkileşim için kullanıcıların fare ile çizmesine izin veren başka bir işlev ekleyebilirsiniz.
AJMansfield

7
Kutsal kutu gölge, Batman
Bojangles

Golf background(-1)background(255)
oynamak

20

Büyük zorluk. İşte benim çözümüm. Orijinal çizgi romana olabildiğince yaklaşmaya çalıştım, hatta xkcd fontunu bile kullandım .

Bu bir WPF uygulaması, ancak System.Drawingtembel olduğum için çizim parçalarını kullanırdım.

Temel kavram: WPF'de pencereler Visuals, yani oluşturulabilecekleri anlamına gelir. Tüm Window örneğini bir bitmap üzerinde oluşturuyorum, siyah ve toplam siyah veya beyazı sayıyorum (yazı tipi yumuşatması ve öğelerinde grileri yok sayarak) ve ayrıca görüntünün her 3'ünde de (her panel için) sayıyorum. Sonra tekrar bir zamanlayıcıda yapıyorum. Bir veya iki saniye içinde dengeye ulaşır.

İndir:

MEGA Her zaman indirdiğiniz dosyaları virüs, vb. İçin kontrol edin.

Görmek istiyorsanız yukarıdaki yazı tipini sisteminize yüklemeniz gerekir, aksi takdirde WPF varsayılanıdır.

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>

Kod:

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

Kod temizlenmedi, ancak biraz okunabilir olmalı, üzgünüm.


2
Geç giriş, ancak en iyilerinden biri.
primo

14

C (SDL ve SDL_ttf ile): Gri Tonlamalı çözüm

İşte, gri tonlamalı piksel renklerinin tam spektrumunu yakalamak ve sadece 100 çizginin altında saatlemek için pasta grafik formundan faydalanan bir çözüm.

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

Önceki çözümümde olduğu gibi, yazı tipi dosyasının yolunun kaynakta kodlanmış veya build komutuna eklenmiş olması gerekir, örneğin:

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

Programın çıktısı şuna benzer:

Tam gri tonlamalı piksel renk dağılımını gösteren pasta grafiği

Bunu izlemek eğlencelidir, çünkü bütün matematik programı kararlı bir çözümde sıfırda görebileceğiniz yeniden çizimleri yavaşlatır. İlk tahmin, çılgınca kapalı (yüzey tamamen siyah başladığı için) ve sonra yaklaşık bir düzine kadar tekrarlamanın ardından son boyuta büzülüyor.

Kod, geçerli görüntüdeki her piksel renginin bir popülasyon sayısını alarak çalışır. Bu popülasyon sayımı sonuncuyla uyuşmuyorsa, resmi yeniden çizer. Kod her piksele göre yinelenir, ancak x, y koordinatlarını kutupsal koordinatlara dönüştürür, önce yarıçapı hesaplar (görüntünün merkezini kaynak olarak kullanır). Yarıçapı pasta grafik alanı içinde ise, o zaman theta hesaplar. Teta, piksel rengini belirleyen popülasyon sayımlarına kolayca ölçeklendirilir. Öte yandan, yarıçap, pasta grafiğinin sınırında sağ ise, daireyi grafiğin dışına çekmek için kenar yumuşatılmış bir değer hesaplanır. Polar koordinatlar her şeyi kolaylaştırır!


Sen çoğunlukla kullandığınız floatmatematik-kütüphane fonksiyonlarının versiyonlarını, ama o zaman olmamalıdır fabsolmak fabsf?
luser droog

Teknik olarak, belki, ama fabs()daha taşınabilir.
breadbox

Doğru, kütüphanede bulunduğum zaman bile başlıklarda tanımlanmadığı konusunda sorun yaşadım. Ayrıca aşkınlara göre kazanılması gereken daha az performans var. :)
luser droog

10

C (SDL ve SDL_ttf ile)

İşte 60 satırlık C kodunda çok basit bir uygulama:

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

Bunu derlemek FONTPATHiçin kullanılacak fontun bir .ttf dosyasına işaret etmesini tanımlamanız gerekir :

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

Çoğu modern Linux makinesinde fc-matchyazı tipi konumlarını aramak için yardımcı programı kullanabilirsiniz , böylece derleme komutu şöyle olur:

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

(Elbette istenen yazı tipini kişisel favorinizle değiştirebilirsiniz.)

Kod özellikle kenar yumuşatma istemez, böylece pencere yalnızca siyah beyaz pikselleri içerir.

Sonunda, @ daniero'nun pencerenin yeniden boyutlandırılmasına izin veren zarif çözümünden ilham aldım. Bazen programın, asla ulaşamayacağı bir çekicinin etrafındaki bir yörüngede sıkışmış sayılar arasında salındığını göreceksiniz. Bu olduğunda, pencereyi durana kadar biraz yeniden boyutlandırın.

Ve istek başına, işte sistemde çalıştırdığımda nasıl göründüğü:

Bu görüntü% 3,36 siyah piksel ve% 96,64 beyaz pikseldir.

Sonunda, burada hiç kimse görmemişse, MAA’nın Randall Munroe ile röportajını yayınladığı , # 688 karikatürünün yapımını ayrıntılı olarak tartıştığını belirtmem gerektiğini düşünüyorum .


1
Çok güzel bir çözüm. @ Daniero'nun gönderisinin ardından, çalışan programın bazı ekran görüntülerini girebilir misiniz? :)
Alex Brooks,

+1, çok hoş! Ekran görüntüsünü eklediğiniz için teşekkür ederiz :) Ve röportaj linki ilginç, teşekkürler!
WendiKidd

9

görüntü tanımını buraya girin

Görüntü 100x100 ve sayılar kesindir ve kesin demek istediğim - Yüzdelerin iki ondalık basamakla ifade edilebilmesi için 10000 piksel bir görüntü seçtim. Yöntem, biraz matematik, biraz tahmin ve Python'da bazı sayılar oldu.

Yüzdelerin 4 basamakta ifade edilebileceğini önceden bildiğim gibi, 0'dan 9'a kadar olan basamakların her birinde kaç tane siyah piksel olduğunu, 8 piksel yüksekliğinde olan Arial olarak saydım. weightBelirli bir sayıyı yazmanız için kaç piksel gerektiğini, 4 rakamı olacak şekilde sıfırlarla dolu bıraktığınız hızlı fonksiyon :

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

pxgerekli piksel sayısına kadar dizi eşleştirme hanesidir. B, siyah piksellerin sayısı ve W, beyaz piksellerin sayısı ise, biz B + W = 10000ve ihtiyacımız olan:

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

Sabitler nereden geldi? 423, siyah piksellerin "ilk" sayısıdır, metindeki siyah piksellerin rakamsızdır. 9577, başlangıçtaki beyaz piksellerin sayısıdır. Yukarıdaki sistemin bile bir çözümü olacak şekilde sabitleri almayı başarmadan önce ilk siyah piksel miktarını birkaç kez ayarlamak zorunda kaldım. Bu parmaklarımı tahmin edip geçerek yapıldı.

Yukarıdaki sistem korkunç derecede doğrusal değildir, bu yüzden açıkça sembolik olarak çözmeyi unutabilirsiniz, ancak yapabileceğiniz şey sadece B'nin her bir değerinde döngü yapmak, W = 10000 - B olarak ayarlamak ve denklemleri açıkça kontrol etmek.

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

Belki 250 x 400 görüntü yapabilir, böylece 3 ondalık basamağa götürebilir ve bu arada daha fazla metin görüntüleyebilirsiniz.
Joe Z.

Çok güzel bir çözüm, bazı kaba kuvvet matematik her zaman bu tür sorunları çözebilir!
ÇKP

6

QBasic

Çünkü nostalji.

Çünkü hiçbir resim kütüphanesini gerçekten bilmiyorum, modern dillerdir.

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

Oldukça basit çıktı-sayım tekrarı yöntemi. Asıl "ilginç" şey, programın rasgele yüzdeler için farklı kesinlikler denemesidir - her zaman başka türlü birleşmediğini tespit ettim.

Ve çıktı ( QB64'te test edilmiştir ):

QBasic metagrafı


3

AWK

... netpbm ve diğer yardımcılarla

'X' dosyası:

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"%"
        }
}

Koşmak:

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

Resim 'x.pbm' olarak yazılmıştır, yüklemek için onu png'ye dönüştürdüm:

x.png

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.