| Bytes | Lang | Time | Link |
|---|---|---|---|
| 128 | Charcoal | 241207T012017Z | Neil |
| 103 | AWK | 241206T195648Z | xrs |
| 089 | 05AB1E | 241206T165808Z | Kevin Cr |
Charcoal, 128 bytes
Nθ≔E³Sη≔⌈Eη∧№ι.⌕⮌ι.ζUMη⁺ι×ζ0UMηI⎇№ι.…⁻ι.⁺ζ⌕ι.ι≔Eθ↨⊕ιηε≔⌈Φ⊕⌈↔ε∧ι¬⌈﹪ειδ←⮌E⁺²÷⁻⌈ε⌊εδ⁺|⮌I∕⁻⌈ε×ιδXχζJ⁰¦⁰+Fθ«P↑⁺× ⊕÷⁻§ει⌊εδOP⁺¶I⊕ιL⊕ι→
Try it online! Link is to verbose version of code. Takes input in the order V, M, N, C. Explanation:
Nθ
Input V as a number.
≔E³Sη
Input M, N, C as strings.
≔⌈Eη∧№ι.⌕⮌ι.ζ
Find the maximum number of decimal places in any of the three values.
UMη⁺ι×ζ0
Append that many zeros to each value.
UMηI⎇№ι.…⁻ι.⁺ζ⌕ι.ι
Truncate each value to that many decimals, then remove the decimal point.
≔Eθ↨⊕ιηε
Calculate the y values for x in the range 1 to V.
≔⌈Φ⊕⌈↔ε∧ι¬⌈﹪ειδ
Slowly find the GCD of all of the y values, which will become the y tick step.
←⮌E⁺²÷⁻⌈ε⌊εδ⁺|⮌I∕⁻⌈ε×ιδXχζ
Print all of the y-axis with labels from the highest to the lowest y value, plus one more which will become the origin. (Replace I with ﹪﹪%%.0%dfζ to get the values padded with trailing zeros.)
J⁰¦⁰+
Replace the | at the origin with a +.
Fθ«
Loop over the V values.
P↑⁺× ⊕÷⁻§ει⌊εδO
Output the O in the appropriate position.
P⁺¶I⊕ι
Output the x-axis label.
L⊕ι→
Output the x-axis. (Use Lθ→ if you want all of the x-axis to be the same width.)
AWK, 135 104 103 bytes
{for(;i++<$4;p=p" "i){s=sprintf("%5.1f|%"2*i-1"i\n",$1*i^2+$2*i+$3,0)s;t=t"- "}}$0=s" +"t"\n "p
AWK, 103 bytes
Limited to V=5
{for(;i++<$4;)s=sprintf("%5.1f|%"2*i-1"s\n",$1*i^2+$2*i+$3,"*")s}$0=s" +- - - - -\n 1 2 3 4 5"
{for(;i++<$4;) # for V
s=sprintf # create pretty string
("%5.1f|%"2*i-1"s\n",$1*i^2+$2*i+$3,"*")s} # * at point on line
$0=s # set output
" +- - - - -\n 1 2 3 4 5" # X axis
05AB1E, 89 bytes
Lβ©Zs[ÐïQ#T*¼}￾°/DU/₄z+ÝXz/'|«Déθgj®¾.òR'O¹·ú¹L·._ø'|ýDéθgjR®Xz*ǝR`¨©'+«„- ¹×«¹L®gðך)»
Two loose inputs in the order and format \$V\$ and \$[M,N,C]\$, where \$[M,N,C]\$ are floats.
y-axis of the output will also always be floats.
Try it online or verify all test cases.
Explanation:
Step 1: Same as the previous two challenges:
L # Push a list in the range [1, first (implicit) input V]
β # Convert the second (implicit) input-triplet [M,N,C] from a
# base-v list to base-10 a integer for each v in the
# [1,V]-ranged list
© # Store this list in variable `®`
Step 2: Calculate the step-size of the y-axis:
Z # Push the maximum of the list (without popping)
s # Swap so the list is at the top again
[ # Loop indefinitely:
Ð # Triplicate the current list
ï # Truncate/floor the current values to integers
Q # Check if the top two lists are the same
# # If they are: stop the infinite list
T* # Else: multiply each value by 10
¼ # Increase the counter variable `¾` by 1 (0 by default)
} # After the infinite loop
ï¿ # (Cast to integers) and take the GCD (Greatest Common Divisor)
¾° # Push 10 to the power the counter variable `¾`
/ # Divide the GCD by this 10**¾
DU # Store a copy in variable `X`
Try just the first two steps online.
Step 3a: Create the generic y-axis rows:
/ # Divide the values in the list by this
₄z+ #†Add 1/1000 to each
Ý # Pop and push a list in [0,int(^)]
Xz/ #†Multiply each by value `X`
'|« '# Append "|" to each
Déθg # Push its longest value (without popping)
D # Duplicate the list
é # Sort by length (shortest to longest)
θ # Pop and push the last/longest
g # Pop and push its length
j # Add leading spaces to make all strings that length
Step 3b: Create the rows containing the Os:
® # Push list `®`
¾.ò #†Round each to `¾` amount of floating points
R # Reverse the list from highest to lowest
'O '# Push "O"
¹ # Push the first input V
· # Double it
ú # Add that many leading spaces to the "O"
¹L # Push a list in the range [1,V]
· # Double each value in that ranged list as well
._ # Rotate the space-padded "O" that many times left
ø # Pair the values in the lists together
'|ý '# Join each inner pair by "|"
Déθgj # Add leading spaces again if necessary
Step 3c: Insert those O-rows:
R # Reverse the list
® # Push list `®` again
Xz* #†Divide each by `X` to convert them to 1-based indices
ǝ # Insert them into the big list at those 0-based indices
R # Reverse this entire list
Try just the first three steps online.
Step 4: Add the bottom two rows, join by newlines, and output the result:
` # Pop and push all rows separately to the stack
¨ # Remove the last character of the last string (the "|" of
# row 0.0)
© # Store this space-padded "0.0" in variable `®` (without
# popping)
'+« '# Append a "+" instead
„- # Push string "- "
¹× # Repeat it the first input V amount of times
« # Append that to the space-padded "0.0+"
¹L # Push a list in the range [1,input V]
®g # Push the length of the space-padded "0.0" from variable `®`
ð× # Pop and push a string of that many spaces
š # Prepend it to the [1,V]-ranged list
) # Wrap all items on the stack into a list again
» # Join the [1,V]-ranged list with prepended string by spaces,
# and then join each line by newlines
# (after which the result is output implicitly)
† These are all to account for floating-point inaccuracies..
₄z+: Add \$\frac{1}{1000}\$ (aka 0.001) before truncating it to an integer for the [0,value]-ranged listÝ.Xz/(divide by \$\frac{1}{X}\$) instead ofX*(multiply by \$X\$) andXz*(multiply by \$\frac{1}{X}\$) instead ofX/(divide by \$X\$) seem to help to prevent floating-point inaccuracies at those steps.¾.ò: Even though all values should already be at that decimal point, the additional round is to fix any floating point inaccuracies from the very first step.
Try it online. without these counter-measures for floating-point inaccuracies to see what goes wrong.