xkcd challenge:“ เปอร์เซ็นต์ของหน้าจอที่เป็น [x] สี”


57

ดังนั้นฉันคิดว่าเราทุกคนคงเคยเห็นการ์ตูน xkcd นี้ :

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

นี่อาจเป็นเรื่องทั่วไปหรือยากเกินไปฉันไม่แน่ใจ แต่ความท้าทายคือการสร้างโปรแกรมในภาษาใด ๆ ที่สร้างหน้าต่างที่มีอย่างน้อย 2 สีและแสดงเป็นคำภาษาอังกฤษเปอร์เซ็นต์ของหน้าจอคือแต่ละสี

อดีต วิธีที่ง่ายที่สุดจะเป็นพื้นหลังสีขาวพร้อมตัวอักษรสีดำที่อ่าน "เปอร์เซ็นต์ของภาพนี้ที่เป็นสีดำ: [x]% ร้อยละของภาพนี้ที่เป็นสีขาว: [y]%"

คุณสามารถไปบ้าหรือง่ายเท่าที่คุณต้องการ; ข้อความล้วนเป็นทางออกที่ถูกต้อง แต่ถ้าคุณสร้างภาพที่น่าสนใจเหมือนในการ์ตูน xkcd นั่นก็ดีกว่า! ผู้ชนะจะเป็นทางออกที่สนุกและสร้างสรรค์ที่สุดที่ได้รับคะแนนโหวตสูงสุด ดังนั้นออกไปทำสิ่งที่สนุกและคุ้มค่ากับ xkcd! :)

ดังนั้นสิ่งที่คุณคิดว่า? ฟังดูเหมือนเป็นเรื่องสนุก :)

โปรดรวมภาพหน้าจอของโปรแกรมของคุณที่ทำงานอยู่ในคำตอบของคุณ :)


6
A "โปรแกรมนี้มี 64 A, 4 B's, ... และ 34 อัญประกาศคู่ในซอร์สโค้ด" โปรแกรมน่าสนใจยิ่งขึ้น :-)
John Dvorak

2
ตกลง ... เกณฑ์การชนะอย่างมีวัตถุประสงค์คืออะไร? คุณจะกำหนดได้อย่างไรว่าผลลัพธ์เฉพาะใด ๆ ที่ถูกต้อง? มันเพียงพอหรือไม่ที่จะเป็นจริงและอธิบายคุณสมบัติของตัวเองเป็นตัวเลข?
John Dvorak

@JanDvorak โอ้มันเยี่ยมมาก! จริงๆแล้วโปรแกรมตัวอักษรเป็นสิ่งที่ทำให้ฉันนึกถึงสิ่งนี้ แต่ฉันไม่ได้พิจารณาที่จะเพิ่มองค์ประกอบซอร์สโค้ดลงไป! คุณควรโพสต์เป็นคำถาม :) ใช่มันก็เพียงพอแล้วที่จะเป็นจริงและอธิบายตัวเอง อืมคุณพูดถูกฉันไม่ได้คิดว่าฉันจะพิสูจน์ได้อย่างไรว่าผลลัพธ์สุดท้ายนั้นถูกต้อง ฉันต้องการวิธีการนับจำนวนพิกเซลทั้งหมดของแต่ละสีในภาพผลลัพธ์ ฉันจะไปตรวจสอบว่าตอนนี้ (ขออภัยคำถามแรกของฉันมีปัญหา ... ฉันพยายาม แต่ฉันใหม่ที่นี้ขอบคุณ :))
WendiKidd

หากความจริงและการอ้างอิงตนเองเป็นเกณฑ์ที่เพียงพอนี่คือผู้แข่งขัน golfscript ของฉัน: "/.*/"(อ่าน: [ซอร์สโค้ด] ไม่มีการขึ้นบรรทัดใหม่)
John Dvorak

@JanDvorak อืมฉันลองใช้รหัสของคุณที่นี่และผลลัพธ์นั้นเหมือนกับรหัสยกเว้นโดยไม่มีเครื่องหมายคำพูด บางทีฉันอาจจะอธิบายไม่ถูกต้องขอโทษด้วย ต้องมีอย่างน้อย 2 สีที่สร้างขึ้นและในบางรูปแบบของประโยคภาษาอังกฤษผลลัพธ์จะต้องสร้างคำจริงที่อธิบายว่าร้อยละของหน้าจอแต่ละสีมี บางทีนี่อาจเป็นความคิดที่โง่ ฉันคิดว่ามันจะสนุก แต่มันอาจจะไม่ทำงานในทางปฏิบัติ :)
WendiKidd

คำตอบ:


35

ไม้ต้นจำพวก ulmus

ยังไม่เคยเห็นใครใช้ช่องโหว่นี้: สาธิต

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
izabera

ดี ... แต่ฉันคิดว่ามันต้องมีเสถียรภาพเพื่อเป็น "ทางออก" ไม่ได้คิดอย่างถี่ถ้วน - แต่เนื่องจากไม่จำเป็นต้องมีวิธีแก้ปัญหาสำหรับความแม่นยำโดยพลการเมื่อวาดจากร่ายมนตร์ตัวเลข จำกัด คุณจะต้องถอยกลับแม่นยำหากไม่สามารถแก้ไขได้ที่ความแม่นยำสูงกว่า คุณกำลังพยายาม ฉันคิดว่าการใช้แบบอักษร monospace ที่คุณคำนวณพิกเซลขาวดำจะมีความจำเป็นเช่นกัน
ดร. Rebmu

คุณใช้ 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

20

ความท้าทายที่ยิ่งใหญ่ นี่คือทางออกของฉัน ฉันพยายามที่จะได้รับใกล้เคียงเป็นไปได้ที่จะการ์ตูนต้นฉบับผมยังใช้ตัวอักษร xkcd

มันเป็นแอพพลิเคชั่น WPF แต่ฉันเคยSystem.Drawingทำส่วนวาดรูปเพราะฉันขี้เกียจ

แนวคิดพื้นฐาน: ใน WPF มี windows Visualsซึ่งหมายความว่าสามารถแสดงผลได้ ฉันแสดงอินสแตนซ์ของหน้าต่างทั้งหมดลงบนบิตแมปนับจำนวนสีดำและสีดำทั้งหมดหรือสีขาว (ไม่คำนึงถึงสีเทาในแบบอักษรและสิ่งที่ราบเรียบ) และยังนับสิ่งเหล่านี้สำหรับแต่ละภาพที่ 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

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

เช่นเดียวกับโซลูชันก่อนหน้าของฉันพา ธ ไปยังไฟล์ฟอนต์ต้องเป็นฮาร์ดโค้ดในแหล่งที่มาหรือเพิ่มในคำสั่ง build เช่น:

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

ผลลัพธ์ของโปรแกรมมีลักษณะดังนี้:

แผนภูมิวงกลมแสดงการกระจายสีพิกเซลสีเทาแบบเต็ม

อันนี้สนุกกับการดูเพราะคณิตศาสตร์ทั้งหมดช้าลงการวาดใหม่ไปยังตำแหน่งที่คุณสามารถดูโปรแกรมเป็นศูนย์ในการแก้ปัญหาที่มั่นคง การประมาณการครั้งแรกจะปิดลงอย่างดุเดือด (เนื่องจากพื้นผิวเริ่มเป็นสีดำทั้งหมด) จากนั้นย่อขนาดลงสู่ขนาดสุดท้ายหลังจากทำซ้ำประมาณหนึ่งโหลหรือประมาณนั้น

รหัสทำงานโดยการนับจำนวนประชากรของแต่ละพิกเซลในภาพปัจจุบัน หากจำนวนประชากรนี้ไม่ตรงกับประชากรสุดท้ายมันจะทำการวาดภาพใหม่ โค้ดจะวนซ้ำทุกพิกเซล แต่จะแปลงพิกัด x, y เป็นพิกัดเชิงขั้วคำนวณรัศมีก่อน (ใช้จุดศูนย์กลางของภาพเป็นจุดกำเนิด) หากรัศมีอยู่ภายในพื้นที่แผนภูมิวงกลมมันจะคำนวณ theta ทีต้าจะถูกปรับสัดส่วนตามจำนวนประชากรอย่างง่ายดายซึ่งกำหนดสีของพิกเซล ในทางกลับกันหากรัศมีอยู่บนเส้นขอบของแผนภูมิวงกลมค่าที่ต่อต้านนามแฝงจะถูกคำนวณเพื่อวาดวงกลมรอบ ๆ ด้านนอกของแผนภูมิ พิกัดของโพลาร์ทำให้ทุกอย่างง่ายขึ้น!


ส่วนใหญ่คุณกำลังใช้floatรุ่นของฟังก์ชันทางคณิตศาสตร์ห้องสมุด แต่แล้วก็ไม่ควรfabsจะเป็นfabsf?
luser droog

ในทางเทคนิคบางที แต่fabs()สามารถพกพาได้มากกว่า
breadbox

จริงฉันมีปัญหากับสิ่งที่ไม่ได้ถูกกำหนดในส่วนหัวแม้ว่าจะอยู่ในห้องสมุด นอกจากนี้ยังมีประสิทธิภาพที่จะได้รับน้อยกว่ากับคนธรรมดา :)
luser droog

10

C (พร้อม SDL และ SDL_ttf)

นี่คือการใช้งานที่ง่ายมากโดยมีรหัส C ประมาณ 60 บรรทัด:

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

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

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

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

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

ในการรวบรวมสิ่งนี้คุณต้องกำหนดFONTPATHให้ชี้ไปที่ไฟล์. ttf ของแบบอักษรที่จะใช้:

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

บนเครื่องลีนุกซ์ที่ทันสมัยที่สุดคุณสามารถใช้fc-matchยูทิลิตี้นี้เพื่อค้นหาตำแหน่งตัวอักษรดังนั้นคำสั่งคอมไพล์จึงกลายเป็น:

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

(แน่นอนคุณสามารถแทนที่แบบอักษรที่ร้องขอด้วยตัวคุณเองที่คุณชื่นชอบ)

รหัสร้องขอการไม่ใช้นามแฝงโดยเฉพาะเพื่อให้หน้าต่างมีเพียงพิกเซลขาวดำ

ในที่สุดฉันก็ได้รับแรงบันดาลใจจากโซลูชันที่สง่างามของ @ daniero เพื่ออนุญาตให้ปรับขนาดหน้าต่าง คุณจะเห็นว่าบางครั้งโปรแกรมแกว่งไปมาระหว่างการนับติดอยู่ในวงโคจรรอบตัวดึงดูดที่มันไม่สามารถเข้าถึงได้ เมื่อสิ่งนั้นเกิดขึ้นให้ปรับขนาดหน้าต่างอีกเล็กน้อยจนกว่าจะหยุด

และตามคำขอนี่คือสิ่งที่ดูเหมือนว่าเมื่อฉันเรียกใช้ในระบบของฉัน:

ภาพนี้เป็นพิกเซลสีดำ 3.36% และพิกเซลสีขาว 96.64%

ในที่สุดฉันรู้สึกว่าฉันควรชี้ให้เห็นในกรณีที่ใครที่นี่ยังไม่เคยเห็นมาก่อน MAA ตีพิมพ์บทสัมภาษณ์กับ Randall Munroeซึ่งเขาพูดถึงการสร้างการ์ตูน # 688 ในรายละเอียดบางอย่าง


1
ทางออกที่ดีมาก คุณสามารถใส่ภาพหน้าจอบางส่วนของโปรแกรมที่กำลังทำงานอยู่หลังจากโพสต์ของ @ daniero หรือไม่ :)
Alex Brooks

+1 ดีมาก! ขอบคุณที่เพิ่มภาพหน้าจอ :) และลิงค์สัมภาษณ์น่าสนใจขอบคุณ!
WendiKidd

9

ป้อนคำอธิบายรูปภาพที่นี่

ภาพมีขนาด 100x100 และตัวเลขนั้นแน่นอนและฉันหมายถึงแน่นอน - ฉันเลือกภาพขนาด 10,000 พิกเซลเพื่อให้เปอร์เซ็นต์สามารถแสดงด้วยทศนิยมสองตำแหน่ง วิธีการคือคณิตศาสตร์การเดาและการกระทืบตัวเลขใน 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 = 10,000 - 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 ):

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.