draw ASCII function plots

4

1

Consider a function plot like this:

                                                       ###########              
                                                    #################           
                                                  ####################          
                                                 #######################        
                                               ###########################      
                                              #############################     
                                            ################################    
                                           ###################################  
                                          ##################################### 
                                        ########################################
--------------------------------------------------------------------------------
  #####################################                                         
   ###################################                                          
    #################################                                           
      #############################                                             
       ###########################                                              
         #######################                                                
          #####################                                                 
            #################                                                   
               ###########    

This function plot has been created with the J code below, which is not a solution to this challenge.

([: |: ([: |."1 [: #&'#'"0 [: >. [: - (* 0&>)) ,. '-' ,. [: #&'#'"0 [: <. (* 0&<)) 10 * sin 12.7 %~ i. 80

Your task is to write a function or program that takes as input from an implementation defined source that is not the source code of your entry:

  1. Two positive integers
    • w, the width of the plot
    • h, the height of the plot
  2. Two real numbers
    • b, the beginning of the region to plot
    • e, the end of the region to plot
  3. A function f mapping real numbers to real numbers. You may assume that this function does not crash, throw an exception, return a NaN or ±∞ for arguments in the range b to e inclusive. The way in which this function is described is implementation defined, but it should be possible to use any combination of the following:
    • floating point constants except NaN and ±∞
    • addition
    • subtraction
    • multiplication
    • division
    • the ex function
    • natural logarithm
    • sine and cosine

Your function or program shall return or print out an ASCII art plot with dimensions w × h that looks like plot above and plots f in the range b to e inclusive. The plot shall be scaled so that both the topmost and bottommost line contain a # sign or a -. Your output format may diverge from the output format shown above in a meaningful way if that doesn't simplify your solution. In particular, you may exchange # and - for other characters that give the impression of black space and horizontal line.

The score of your submission is the number of tokens your program source consists of. String literals count as the length of the string they describe but at least as one point, numeric literals count as ⌈log256(|n|)⌉ where n is the number described by the numeric literal.

An identifier which is either predefined by the language or a library your submission uses or whose name can be exchanged with any other unused name counts as one character. All other identifiers count as their length in characters.

If the programming language your submission is written does not have the concept of a token, it's score is the total number of characters that can't be removed from the source without changing the meaning of the program.

The scoring rules ensure that you can indent your code and use descriptive names for your variables, etc. and lowers the edge of domain-specific languages for golfing.

The winner is the submission with the least score.

FUZxxl

Posted 2015-02-04T16:46:32.353

Reputation: 9 656

@FryAmTheEggman I didn't know that tag existed. Thank you for the information. – FUZxxl – 2015-02-04T16:51:08.837

Your definitions of how to count tokens are probably going to be abused as they are. E.g. by base64-encoding the code, naming a variable like this (which is a single token) and then getting a string representation of the variable name and base64-decoding it again. – Martin Ender – 2015-02-04T16:51:38.187

@MartinBüttner Hm… That counts as a standard loophole in my opinion. – FUZxxl – 2015-02-04T16:52:10.490

It does not and should be clarified by the OP if he does not intend to let people abuse them, like you did with string and number – Optimizer – 2015-02-04T16:52:54.837

1If your main concern is readability of the code, ask people to include an ungolfed version. If your main concern is golfing languages, then I guess you'll have to go along with scoring by tokens, but in my experience it doesn't really help a lot, because in most languages a function call is 3 tokens (function name plus parentheses) + 1 token for the first argument + 2 tokens for every further argument (because of a delimiter like a comma), whereas in CJam, say, it's just number of arguments + 1. – Martin Ender – 2015-02-04T16:56:23.797

@Optimizer Fixed that loophole. – FUZxxl – 2015-02-04T16:57:03.460

More importantly, how should we the horizontal line be placed if it doesn't fit exactly on a particular row like in your example? (e.g. if the function is a sine, but h is even) – Martin Ender – 2015-02-04T16:57:15.777

Also, it cannot be both code-golf and atomic-code-golf – Optimizer – 2015-02-04T16:57:18.590

@MartinBüttner The horizontal line does not have to be exactly in the center. – FUZxxl – 2015-02-04T16:57:43.377

@FUZxxl Of course, but that doesn't tell me where I should put it if y = 0 falls between two lines of the ASCII output. An example output would be helpful. – Martin Ender – 2015-02-04T16:58:26.263

@MartinBüttner The horizontal line denotes the place where y = 0 on the cartesian coordinate system you are plotting on. The output format is intentionally a little bit fuzzy so you have more freedom for finding a solution. – FUZxxl – 2015-02-04T16:59:37.917

1I like this question, but I think it could have benefited from a pass in the sandbox. – Martin Ender – 2015-02-04T16:59:58.143

@MartinBüttner No. It's correct like it is. Where un(der)specified, your solution is free to choose reasonable behaviour. This is an explicit design decision in crafting this challenge. – FUZxxl – 2015-02-04T17:00:57.037

1The spec needs to explicitly state the criteria for shading a cell, because there are a number of plausible options and we can't tell which is intended. In particular, is the cheap and crappy "shade a pixel iff its midpoint is between 0 and the value at that x-coordinate" intended, or should the program attempt to compute the extrema of the image of the column and either shade the pixel iff its (centre-bottom / midpoint / centre-top) is between 0 and one of the extrema, or shade the pixel iff at least 50% of its area is? – Peter Taylor – 2015-02-04T17:28:31.883

1Or, indeed, am I guessing wrongly that the shaded pixels in the column should always extend to the x-axis? For all I know, the example image shows sin(x)sin(1000x) and the line does actually pass through all of those shaded pixels. – Peter Taylor – 2015-02-04T17:30:40.357

The first behaviour (the "crappy" one) is correct. I'm on a trsin right now, let me amend the specificarion in a minute. – FUZxxl – 2015-02-04T17:38:08.607

@Ypnypn As described in the question, a string counts as one point per character it contains. For instance, the C string "a\n" counts as two characters, the C string u"aä", too. – FUZxxl – 2015-02-04T18:56:34.410

@MartinBüttner Good catch... – FUZxxl – 2015-02-04T20:18:46.063

I think numerics should count like strings, or somebody could take some data consisting of bits bbb... and encode that as a number 0.999bbb..., which counts as pretty much 0 (Log_256(0.999...)). Or perhaps, count numbers without the decimal point or other separators: 1.75 would count as 175, the rational number literal 9992345/10000000r in ruby would count as 999234510000000 (and not as 0.9992345) etc. – blutorange – 2015-05-06T18:48:06.630

@blutorange The scoring scheme is flawed anyway. – FUZxxl – 2015-05-06T19:45:19.820

Answers

2

Ruby (>=2.1), ~28.19812

As @FUZxxl considered that the scoring scheme is flawed anyway, I shall make full use of it.

eval (123125010100101102032105110116040115116114044102109116061034037115034041010098101103105110010115116114061115116114046100117112010115116114046103115117098033040039094039044039042042039041010115116114046103115117098033040047040097099111115104124097115105110104124097116097110104124097116097110050124097116097110124097115105110124097099111115124099111115104124115105110104124116097110104124115105110124099111115124116097110124115113114116124108111103049048124108111103050124103097109109097124108111103124101120112124101114102099124101114102124104121112111116041047105041123034077097116104046035123036049046100111119110099097115101125034125010115116114046103115117098033040047040101040036124091094114120093041124112105041047105041123034077097116104058058035123036049046117112099097115101125034125010101118097108040102109116037115116114041010114101115099117101032069120099101112116105111110061062101010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010101110100010119061105110116040065082071086046115104105102116041046116111095105010104061105110116040065082071086046115104105102116041046116111095105010098061105110116040065082071086046115104105102116041046116111095102010101061105110116040065082071086046115104105102116041046116111095102010102061105110116040065082071086046106111105110040039032039041044034045062120123037115125034041010119105110061065114114097121046110101119040104041123065114114097121046110101119040119041123039032039125125010100120061040101045098041047119046116111095102010098101103105110010121061065114114097121046110101119040119041123124120124102091098043040120043048046053041042100120093125010114101115099117101032069120099101112116105111110010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010114044113061121046109105110109097120010114061048032105102032114062048010113061048032105102032113060048010114045061048046048048049032105102032114061061113010121046109097112033032100111032124122124032010112121061040040122045114041042104047040113045114041046116111095102045048046053041046114111117110100010112121061048032105102032112121032060032048010112121061104045049032105102032112121062061104010112121010101110100010121048061040045114042104047040113045114041046116111095102045048046053041046114111117110100010121048061048032105102032121048060048010121048061104045049032105102032121048062061104010100121061040113045114041047104046116111095102010119046116105109101115032100111032124120124010121049044121050061091121048044121091120093093046109105110109097120010040121049046046121050041046101097099104123124122124119105110091122093091120093061063035125010119105110091121048093091120093061063045010101110100010112117116115032119105110046114101118101114115101046109097112040038058106111105110041046106111105110040034010034041010/123125010100101102032105110116040115116114044102109116061034037115034041010098101103105110010115116114061115116114046100117112010115116114046103115117098033040039094039044039042042039041010115116114046103115117098033040047040097099111115104124097115105110104124097116097110104124097116097110050124097116097110124097115105110124097099111115124099111115104124115105110104124116097110104124115105110124099111115124116097110124115113114116124108111103049048124108111103050124103097109109097124108111103124101120112124101114102099124101114102124104121112111116041047105041123034077097116104046035123036049046100111119110099097115101125034125010115116114046103115117098033040047040101040036124091094114120093041124112105041047105041123034077097116104058058035123036049046117112099097115101125034125010101118097108040102109116037115116114041010114101115099117101032069120099101112116105111110061062101010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010101110100010119061105110116040065082071086046115104105102116041046116111095105010104061105110116040065082071086046115104105102116041046116111095105010098061105110116040065082071086046115104105102116041046116111095102010101061105110116040065082071086046115104105102116041046116111095102010102061105110116040065082071086046106111105110040039032039041044034045062120123037115125034041010119105110061065114114097121046110101119040104041123065114114097121046110101119040119041123039032039125125010100120061040101045098041047119046116111095102010098101103105110010121061065114114097121046110101119040119041123124120124102091098043040120043048046053041042100120093125010114101115099117101032069120099101112116105111110010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010114044113061121046109105110109097120010114061048032105102032114062048010113061048032105102032113060048010114045061048046048048049032105102032114061061113010121046109097112033032100111032124122124032010112121061040040122045114041042104047040113045114041046116111095102045048046053041046114111117110100010112121061048032105102032112121032060032048010112121061104045049032105102032112121062061104010112121010101110100010121048061040045114042104047040113045114041046116111095102045048046053041046114111117110100010121048061048032105102032121048060048010121048061104045049032105102032121048062061104010100121061040113045114041047104046116111095102010119046116105109101115032100111032124120124010121049044121050061091121048044121091120093093046109105110109097120010040121049046046121050041046101097099104123124122124119105110091122093091120093061063035125010119105110091121048093091120093061063045010101110100010112117116115032119105110046114101118101114115101046109097112040038058106111105110041046106111105110040034010034041011r).numerator.to_s.chars.each_slice(3).map{|x|x.join.to_i.chr}.join

Try it online here at repl.it. Click run, then enter a valid argument line, such as 35 15 0 2*pi sin x.

Note that ruby has got numeric literals in rational notation, ie. 4/5r is the number 0.8. For your convenience, that number is in decimal notation:

0.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999187817325507631477699523385795515799913435957136728483704843160446828746942390560409186850860550459503103569586130927727288203772199112576191921844592640902889572035182931044557197282985366759740529782716849115850973388128888140605856016243400934225013988573856465542961369877921225012232953123348907301055390544351983324259941650975914266982601521665336561026433337692479737252981932280375408178656797642567580351663715370847184948090264644342895761006305302658546567374207081251715305393141559888678604977336029384249599993510989638718694557098772678079302066224417461706230825883262839423706745230612246592682896861249489867511258470413422890405366642937755571215609655828342795522353669812478241921849184839881173278930914688691396470788124987284884994811350626430408706034083184877791252901811307637379707951652160630308934802951331036015209780395306897171922455792008341833306929756217105134837856722072340152691999593553044410316914296444316575597487088525352291142399342475681074383014729577969560349972908717460451924770322618430398137345975228390098138869196651815744192409770636367186809979333259806799971376312736295078106749882462806603965702298252800964932469571749077234373118173757367981246728722700185281874663305484854815686267951948417500805081514299284030097759433335422488161129087633379029256009841419395473193916652580757339572787031196350523848595739059934610272262632032121135958705400942675585265747208134940670459504182950490822639691988552469570184285722029155876735451418448434291837262494438475865157329632147682775273525502912629309290525247994344119402352906746562912938813927144960422882419280530188325720273357853282893027151548648597228005528806765612233826918005205637908161744746471586122788946189949197068027339580298342252401459219142053457266988043819308357365906624005185998891437015020338032062403957367331681344553645293069200824975432746819295160780502306565769430776755994267478055740983942989630802287991539070194275453164595814059912284843601522641410777102500263105136878073562527389017443916782604694404080884774270752289843169670231007599978515021264254378508439750915875696503075901715672796427206476124499884915354847212732145752199507692504324028476581994433822922095411336560774187464600857696611043903444276823939715034512911523115906203964192584762514518937414389869657622224007910810557978457559493621672434510900434676685136972372427070800690493574076002506601857966532889163912919790105381442988912454576487941545180577660951785673131001806319591499835474292142459954689545865168183300727693709294406587624795251901082689944668219506486589909889789178251301044755043291325912683548593327027307428216501496164310642944204812200141529560315129763903199886131965593255497607579963064788560238693963956045769026069143853104216790763807120448790598924521987287764993238737

This is a complete program, use it like this from the command line:

~ $ ruby cplot.rb 35 15 0 2*pi 'sin x'

      ######                       
     ########                      
    ##########                     
   ############                    
  ##############                   
 ###############                   
#################                  
-----------------------------------
                  #################
                   ############### 
                   ##############  
                    ############   
                     ##########    
                      ########     
                       ###### 

or

~ $ ruby cplot.rb 35 15 1/pi pi '1/x'
#                                  
#                                  
##                                 
##                                 
###                                
###                                
####                               
######                             
#######                            
#########                          
#############                      
##################                 
#############################      
###################################
-----------------------------------

I count the code as follows:

eval
(
<numeric> [log_256(1)=0]
)
.
numerator
.
to_s
.
chars
.
each_slice
(
<numeric> [log_256(3)=0.19812]
)
.
map
{
|
x
|
.
join
.
to_i
.
chr
}
.
join

blutorange

Posted 2015-02-04T16:46:32.353

Reputation: 1 205

Jupp. This scoring system turned out to be a bad idea. – FUZxxl – 2015-05-07T08:06:14.647

I cant figure it out – Ewan – 2015-05-07T08:27:52.630

@Ewan That long number is of the form a/br, with b=a+1. In ruby, that's a numeric literal and taking the logarithmic gives pretty much zero. The numerator a contains 3*n digits, each group of 3 representing a byte (100=0x64="d"). These bytes are the actual program. Try replacing eval with puts and you can see the program. – blutorange – 2015-05-07T08:50:50.497

i get the scoring trickery, i don't understand how the program functions – Ewan – 2015-05-07T08:51:29.010

ahh ok i see now, v clever! – Ewan – 2015-05-07T08:52:34.570

This is the actual program. Rather straight-forward, but since size was not an issue anyway, I included easy input via cli arguments. It's also using the coordinates of the center of each pixel/block. – blutorange – 2015-05-07T08:59:23.423

1

c# - 70ish?

using System;
using System.Collections.Generic;
using System.Linq;
class P
{
    static void Main()
    {
        Func<double,double> f = x => Math.Sin(x) -0.5;
        string r = Draw(60, 20, -10, 10, f);
        Console.Write(r);
        Console.ReadLine();
    }

    static string Draw(int w, int h, int b, int e, Func<double, double> f)
    {
        IEnumerable<double> values = Enumerable.Range(0, w).Select(i => f(i * (double)(e - b) / w));
        double scale = h / (values.Max() - values.Min());

        return String.Join(Environment.NewLine,
            Enumerable.Range(0, h)
            .Select(y => ((h - y) / scale) - Math.Abs(values.Min()))
            .Select(ypos => Math.Abs(ypos) < 1 / (scale * 2) 
                ? new String('-', w) 
                : new String(values.Select(v => v > ypos ^ ypos < 0 
                    ? '#' 
                    : ' ').ToArray())
                )
        );
    }
}

Ewan

Posted 2015-02-04T16:46:32.353

Reputation: 151