26
\$\begingroup\$

(Inspired by this challenge.)

Let's say we have a string ABBCBA. We can say that there is a rise between A and B, for B follows A; we can say that there is a run between B and B, for nothing changes; and finally we can say there is a fall between C and B. We can draw a graph like this:

             A   B   B   C   B   A
Rising:        o       o
Continuing:        o
Falling:                   o   o

Without the labels, and minimizing whitespace:

o o
 o
   oo

This is the expected output for input ABBCBA.

You may use any non-whitespace character to replace o in the output. Further, each column may optionally have an extra space between them, like so:

o   o
  o 
      o o

The input will consist of at least three characters. The string will consist entirely of uppercase letters, but you may instead use lowercase letters.

Test cases

TEST CASE
LINE 1
LINE 2
LINE 3

HELLOWORLD
 o oo o
  o
o    o oo

TESTCASE
 oo  o

o  oo o

EXAMINATION
o o o o o

 o o o o o

ZSILENTYOUTH
  o ooo o

oo o   o oo

ABC
oo



ABCBA
oo

  oo
\$\endgroup\$
11
  • \$\begingroup\$ Could there be a space between each consecutive os, or does the output have to be compact? \$\endgroup\$ – JungHwan Min Sep 25 '16 at 0:04
  • \$\begingroup\$ @JHM Sure, that's fine. \$\endgroup\$ – Conor O'Brien Sep 25 '16 at 0:05
  • \$\begingroup\$ Also, does the output have to be a string, or does it only need to look similar to the example? \$\endgroup\$ – JungHwan Min Sep 25 '16 at 0:06
  • \$\begingroup\$ @JHM What do you ahve in mind? \$\endgroup\$ – Conor O'Brien Sep 25 '16 at 0:06
  • \$\begingroup\$ The code I have in mind generates a grid. \$\endgroup\$ – JungHwan Min Sep 25 '16 at 0:07

18 Answers 18

6
\$\begingroup\$

Jelly, 11 bytes

OIṠ“ o ”ṙZY

Try it online! or verify all test cases.

How it works

OIṠ“ o ”ṙZY  Main link. Argument: s (string)

O            Ordinal; replace all characters with their code points.
 I           Increments; compute the differences of consecutive code points.
  Ṡ          Sign function.
   “ o ”ṙ    Rotate that string -1, 0, or 1 unit(s) to the left.
         Z   Zip; transpose rows and columns.
          Y  Join, separating by linefeeds.
\$\endgroup\$
0
11
\$\begingroup\$

Mathematica, 93 83 68 64 bytes

(uses 0, not O)

Row[Column@Insert[{,},0,2-#]&/@Sign@Differences@LetterNumber@#]&

Explanation

LetterNumber@#

Gets the position in the alphabet of each characters of the input.

Sign@Differences@

Takes the difference between each consecutive elements, and takes the sign (-1 for negative/falling, 0 for 0/continuing, 1 for positive/rising)

Insert[{,},0,2-#]&

Inserts a 0 in a list of two Nulls, in the first position if rising, middle if continuing, and third position if falling.

Row[Column@ ... ]

Formats the output.


If the output could look different from the one in the question, the above code could be shortened to 41 bytes:

ListPlot@*Sign@*Differences@*LetterNumber

... which creates something like this (for "ABBCBA"):

enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ How does the 41 byte look? \$\endgroup\$ – Conor O'Brien Sep 24 '16 at 23:54
  • \$\begingroup\$ @ConorO'Brien please see edit. \$\endgroup\$ – JungHwan Min Sep 24 '16 at 23:56
10
\$\begingroup\$

MATL, 15, 14 bytes

dZSqtQtQv~79*c

Try it online!

Explanation:

They say a picture is worth a thousand words, so here is a beta online interpreter that shows you the value on top of the stack live as it updates. Note that it's still in beta, so you might need to hit run several times.

So first, we call dZS. d gives us the difference between each consecutive element, and ZS gives us the sign (-1, 0, or 1) of each element. So with 'HELLOWORLD' as input, after the first step we'll have:

-1  1  0  1  1 -1  1 -1 -1

Now, we just use q to decrement this and get:

-2  0 -1  0  0 -2  0 -2 -2

And then two times we duplicate the top of the stack and increment the array (tQ) After this we'll have

-2  0 -1  0  0 -2  0 -2 -2
-1  1  0  1  1 -1  1 -1 -1
0   2  1  2  2  0  2  0  0

Now all of the '0's are where we want to output a character. So, we join these three arrays into a matrix (v), and logically negate it (~). Then we multiply every value in the matrix by the ASCII value of 'O', (79*) and display it as a string with c.

\$\endgroup\$
9
  • \$\begingroup\$ Once you have the vector [-1, 1, 0, 1,...], you could use them as the row indices of a sparse matrix with column indices [1,2,3,4,...], then convert it to a full matrix. \$\endgroup\$ – Nick Alger Sep 25 '16 at 3:44
  • \$\begingroup\$ OK nevermind, tried that suggestion, doesn't seem to save anything \$\endgroup\$ – Nick Alger Sep 25 '16 at 4:13
  • \$\begingroup\$ @NickAlger Thanks for the tip anyway! Out of curiosity, could I see what you came up with? \$\endgroup\$ – DJMcMayhem Sep 25 '16 at 4:14
  • \$\begingroup\$ Sure. The following is 19 chars, though it could probably be improved a few, dZS2+tn:tnZ?XPg79*c \$\endgroup\$ – Nick Alger Sep 25 '16 at 4:23
  • \$\begingroup\$ Got it to 16 with a couple optimizations, dZSqq_tn:lZ?79*c \$\endgroup\$ – Nick Alger Sep 25 '16 at 4:33
8
\$\begingroup\$

Haskell, 63 bytes

f w=[do(e,y)<-zip w$tail w;max" "['o'|b e y]|b<-[(<),(==),(>)]]

Returns a list of three strings, representing the lines of output. Contains no subliminal messages.

dianne saved three bytes by using do notation and max instead of a list comprehension and last.

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Great, it contains no subliminal messages! What are those? \$\endgroup\$ – Conor O'Brien Sep 25 '16 at 0:27
  • 5
    \$\begingroup\$ ['o'|b e y].. \$\endgroup\$ – izabera Sep 25 '16 at 14:53
  • \$\begingroup\$ Yes, my master Wait what's going on? \$\endgroup\$ – CalculatorFeline Mar 3 '17 at 16:35
7
\$\begingroup\$

CJam, 19 bytes

l2ew{:-g)S3*0t}%zN*

Uses 0 instead of o.

Try it online!

Explanation

l      e# Read input.
2ew    e# Get all pairs of consecutive letters.
{      e# Map this block over the pairs...
  :-   e#   Compute the difference between the two letters.
  g    e#   Signum. Gives -1 for rises, 1 for falls, 0 otherwise.
  )    e#   Increment. Gives 0 for rises, 2 for falls, 1 otherwise. Call this i.
  S3*  e#   Push a string with three spaces.
  0t   e#   Replace the i'th space (zero-based) with a zero.
}%
z      e# Transpose.
N*     e# Join with linefeeds.
\$\endgroup\$
6
\$\begingroup\$

Python 2, 76 71 bytes

lambda s:[''.join(' o'[cmp(*x)==n]for x in zip(s,s[1:]))for n in-1,0,1]

Thanks to @xnor for notifying me that returning a list of strings is allowed.

Test it on Ideone.

\$\endgroup\$
3
  • \$\begingroup\$ You're allowed to output a list of three strings, which lets you do a lambda. \$\endgroup\$ – xnor Sep 25 '16 at 5:41
  • \$\begingroup\$ I am? That changes everything. \$\endgroup\$ – Dennis Sep 25 '16 at 5:54
  • \$\begingroup\$ I asked in the comments because Lynn's Haskell answer was doing it. \$\endgroup\$ – xnor Sep 25 '16 at 6:03
6
\$\begingroup\$

JavaScript (ES6), 96 95 89 87 82 bytes

2 bytes saved by using 0 instead of o, as suggested by Conor O'Brien
2 6 bytes saved thanks to ETHproductions

let f =

s=>[1,0,-1].map(k=>s.replace(/./g,(c,i)=>i--?(c>s[i])-(c<s[i])-k&&' ':'')).join`
`

console.log(f("HELLOWORLD"));
console.log(f("EXAMINATION"));

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Since you can use any character, does replacing 'o' with 0 help any? \$\endgroup\$ – Conor O'Brien Sep 25 '16 at 0:17
  • \$\begingroup\$ @ConorO'Brien - Indeed, it does. ;) \$\endgroup\$ – Arnauld Sep 25 '16 at 0:19
  • 1
    \$\begingroup\$ I think s=>[1,0,-1].map(k=>[...s].map(c=>(r=p?(c>p)-(c<p)-k&&' ':'',p=c,r),p=0).join``).join`\n` would work, saving 2 bytes. \$\endgroup\$ – ETHproductions Sep 25 '16 at 1:27
  • \$\begingroup\$ You can save another byte by grabbing the previous character each time instead of manually keeping track of it: s=>[1,0,-1].map(k=>[...s].map((c,i)=>(p=s[i-1])?(c>p)-(c<p)-k&&' ':'').join``).join`\n` . s.replace will also save you several bytes over [...s].map().join(). \$\endgroup\$ – ETHproductions Sep 25 '16 at 1:36
4
\$\begingroup\$

Perl, 47 bytes

Includes +1 for -p

Give input on STDIN:

bumpy.pl <<< ABBCBA

bumpy.pl:

#!/usr/bin/perl -p
$_ x=3;s%.%/\G(.)(.)/?$2cmp$1^$.&&$":--$.>0%eg
\$\endgroup\$
4
\$\begingroup\$

MATL, 16 14 Bytes

dZSqq_tn:79Z?c

Try it online!

This grew out of a discussion of DJMCMahem's answer. Even though this answer is 2 characters longer the same length, the method is somewhat different so it may be of independent interest.

Thanks to Luis Mendo for a suggestion saving 2 bytes (see comments)

Explanation:

'dZS' gets a vector where each entry is the sign of the differences between sucessive characters, then 'qq_' decrements each entry by two and flips the sign, so now if the character increases it is 1, if it stays the same 2, and if it decreases 3. For example,

dZSqq_ applied to 'HELLOWORLD' creates the vector [3 1 2 1 1 3 1 3 3]

Next, 't' makes a copy of the previous vector on the stack, then 'n:' places the vector [1,2,3,4,...] on the stack as well. Then '79' places the value 79 on the stack. The value 79 is chosen because it is the number for the unicode character 'o', which will be our output later. (Thanks to Luis Mendo for the idea to put the value 79 here rather than later)

tn:79 applied to [3 1 2 1 1 3 1 3 3] creates the following items:
[3 1 2 1 1 3 1 3 3]   <-- first item on the stack
[1 2 3 4 5 6 7 8 9]   <-- second item on the stack
79                    <-- third item on the stack

At this point we have precisely the row indices, column indices, and nonzero value of a sparse matrix that has the value 79 wherever we want the output character, and 0 wherever we want to output whitespace. We take these three items off the stack and create this sparse matrix with MATL's sparse matrix command 'Z?'. That is,

dZSqq_tn:79 Z? applied to 'HELLOWORLD' outputs the following:
[0  79 0  79 79 0  79 0  0 ]
[0  0  79 0  0  0  0  0  0 ]   <-- 3-by-n sparse matrix
[79 0  0  0  0  79 0  79 79]

All that is left is to convert the matrix from numbers to unicode characters, which is done by the command 'c'. The 79's become 'o', and the 0's become spaces:

dZSqq_tn:79Z?c applied to 'HELLOWORLD' outputs:
[  o   o o   o    ]
[    o            ]   <-- 3-by-n sparse matrix of characters.
[o         o   o o]

The resulting matrix of chars is then implicitly displayed.

\$\endgroup\$
2
  • \$\begingroup\$ You can directly use 79 as the nonzero value for the sparse matrix, thus saving two bytes. Also, I think this is the first time that sparse matrices are used in a MATL answer :-) \$\endgroup\$ – Luis Mendo Sep 25 '16 at 12:46
  • \$\begingroup\$ @LuisMendo Thanks! I edited the post to make the change you suggest \$\endgroup\$ – Nick Alger Sep 25 '16 at 18:37
3
\$\begingroup\$

PHP, 95 Bytes

for($b[1]=$b[0]=$b[-1]=" ";($s=$argv[1])[++$i];)$b[$s[$i-1]<=>$s[$i]][$i]=8;echo join("\n",$b);

1.Create an array of strings with the index -1 to 1 alternative $b=array_fill(-1,3," ");

2.Fill the strings dependent by the spaceship operator and position of the input

3.Output join the array with a new line

First Way 111 Bytes

for($o=" ";$i<$l=strlen($s=$argv[1])-1;)$o[$l*(1+($s[$i]<=>$s[$i+1]))+$i++]=8;echo join("\n",str_split($o,$l));

Use the spaceship operator <=> spaceship operator

\$\endgroup\$
3
  • 1
    \$\begingroup\$ If you encode your program in Latin-1, is a handy shortcut for "\n". No, seriously! \$\endgroup\$ – Lynn Sep 25 '16 at 0:37
  • 1
    \$\begingroup\$ Same thing for " ", which can be . Example. You want to set your browser encoding to Latin-1 when viewing these. \$\endgroup\$ – Lynn Sep 25 '16 at 0:40
  • \$\begingroup\$ @Lynn or ~³~†~‘~‘ Thank You for the idea. I will prefer unicode \$\endgroup\$ – Jörg Hülsermann Sep 25 '16 at 11:20
2
\$\begingroup\$

JavaScript (ES6), 81 bytes

s=>[s,s,s].map(f=([c,...s],n)=>(p=s[0])?((c<p)-(c>p)+n-1&&" ")+f(s,n):"").join`
`

Written from scratch, though it was heavily inspired by @Arnauld's answer. Uses recursion to calculate the contents of each row.

\$\endgroup\$
2
\$\begingroup\$

Ruby, 66 64 bytes

->s{(-1..1).map{|n|s.gsub(/.(?=(.))/){"o  "[n+($1<=>$&)]}.chop}}

See it on eval.in: https://eval.in/649503

\$\endgroup\$
2
\$\begingroup\$

Java 7, 158 156 bytes

String c(char[]z){String a,b,c=a=b="";for(char i=1,q=z[0],o=79,s=32,x;i<z.length;a+=(x=z[i])>q?o:s,b+=x==q?o:s,c+=x<q?o:s,q=z[i++]);return a+"\n"+b+"\n"+c;}

2 bytes saved thanks to @Frozn.

Ungolfed & test cases:

Try it here.

class M{
  static String c(char[] z){
    String a,
           b,
           c = a = b = "";
    for(char i = 1,
             q = z[0],
             o = 79,
             s = 32,
             x; i < z.length; a += (x = z[i]) > q
                                     ? o
                                     : s,
                              b += x == q
                                     ? o
                                     : s,
                              c += x < q
                                     ? o
                                     : s,
                              q = z[i++]);
    return a + "\n" + b + "\n" + c;
  }

  public static void main(String[] a){
    print("HELLOWORLD");
    print("TESTCASE");
    print("EXAMINATION");
    print("ZSILENTYOUTH");
    print("ABC");
    print("ABCBA");
    print("ABBCBA");
    print("UVVWVVUVVWVVUVVW");
  }

  static void print(String s){
    System.out.println(c(s.toCharArray()));
    System.out.println("-------------------------");
  }
}

Output:

 O OO O  
  O      
O    O OO
-------------------------
 OO  O 
       
O  OO O
-------------------------
O O O O O 
          
 O O O O O
-------------------------
  O OOO O  
           
OO O   O OO
-------------------------
OO
  
  
-------------------------
OO  
    
  OO
-------------------------
O O  
 O   
   OO
-------------------------
O O   O O   O O
 O  O  O  O  O 
   O O   O O   
-------------------------
\$\endgroup\$
3
  • 1
    \$\begingroup\$ I'm not sure whether this works but a,b,c=b=a="" would be shorter. \$\endgroup\$ – Frozn Sep 26 '16 at 14:30
  • \$\begingroup\$ @Frozn Thanks, edited. It indeed works. PS: you could have checked yourself in the ideone by forking it. ;) \$\endgroup\$ – Kevin Cruijssen Sep 26 '16 at 14:51
  • \$\begingroup\$ You're right! I'm always overlooking the links and starting up eclipse just for that isn't worth it :) \$\endgroup\$ – Frozn Sep 26 '16 at 15:25
2
\$\begingroup\$

Clora (20 bytes)

<IN?o ;=IN?o ;>IN?o

Explanation:

There are 3 Clora programs, one for each output line.

First program, <IN?o

Check if current input char I is smaller < than the next char N. Save the result in a global flag. Check the flag result ? and if is true, output o, else a blank space (yes, there is a blank space there.

All other programs, follow the same rule and are separated by ;, every program is executed and receives the input as argument.

You can test it by yourself including clora.js and executing it with

(function() {
  var x = new Clora('<IN?o ;=IN?o ;>IN?o ');
  x.execute('EXAMINATION', function(r) {
    console.log(r)
  })
})();
\$\endgroup\$
1
  • \$\begingroup\$ This seems to be strictly non-competing, as it was created after this challenge. This looks like an interesting lang though! \$\endgroup\$ – Conor O'Brien Sep 26 '16 at 18:36
1
\$\begingroup\$

Pyth, 21 bytes

jCmX*3\ h._d0-M.:CMz2

A program that takes input of an unquoted string on STDIN and prints the result.

This uses a similar idea to @MartinEnder's CJam answer.

Try it online or Verify all test cases.

How it works

jCmX*3\ h._d0-M.:CMz2  Program. Input: z
                 CMz   Map ordinal over z, yielding the code-points of the characters
               .:   2  Yield all length-2 sublists of that
             -M        Map subtraction over that
  m                    Map the following over that with variable d:
         ._d            Yield the sign of d
        h               Increment that (i)
    *3\                 Yield string literal of 3 spaces, "   "
   X        0           Replace the space at index i with 0
 C                     Transpose that
j                      Join that on newlines
                       Implicitly print
\$\endgroup\$
1
\$\begingroup\$

PHP 7, 81 80 77 bytes

Note: uses Windows-1252 encoding

for($x=2;~$x--;print~õ)for($a=$argn;$c=$a[$$x+1];)echo$c<=>$a[$$x++]^$x?~ß:o;

Run like this:

echo HELLOWORLD | php -nR 'for($x=2;~$x--;print"\n")for($a=$argn;$c=$a[$$x+1];)echo$c<=>$a[$$x++]^$x?" ":o;';echo

Explanation

Iterates over lines (numbered 1, 0, -1). Then iterates over the input string for every line. When the result of spaceship comparison equals the line number, output an o, otherwise, output a space. After every line, print a newline.

Tweaks

  • Stop iterating when $x is -1, which we can find by binary negation (result 0). Saves a byte compared to adding 1 (or 2 with pre-increment).
  • Saved 3 bytes by using $argn
\$\endgroup\$
5
  • 1
    \$\begingroup\$ You forgot to add -d error_reporting=30709 to your byte count. \$\endgroup\$ – Titus Sep 26 '16 at 19:29
  • \$\begingroup\$ @Titus Why in the world would I need to add that to the byte count? It's only so PHP Notices (which are ignorable) are not printed! \$\endgroup\$ – aross Sep 27 '16 at 7:31
  • \$\begingroup\$ Could also add 2>/dev/null, but that will get rid of ALL errors, including fatal \$\endgroup\$ – aross Sep 27 '16 at 7:35
  • \$\begingroup\$ Oh, and a reference \$\endgroup\$ – aross Sep 27 '16 at 7:54
  • \$\begingroup\$ Something like If you get warnings, set the default value with .... Please excuse my pedantery; I didn´t decode that value. \$\endgroup\$ – Titus Sep 27 '16 at 12:23
0
\$\begingroup\$

Lua 326 303 bytes tl=0 s=io.read() o1,o2,o3="","","" t={} for i=1,#s do t[i]=s:sub(i,i) tl=tl+1 end for v=1,tl-1 do if t[v]t[v+1] then o1=o1.." " o2=o2.." " o3=o3.."o" end end print(o1.."\n"..o2.."\n"..o3)

An ungolfed version

tl = 0 --set the tables length to 0
s = io.read() --Get the string from input
o1,o2,o3="","","" --Set the 3 output rows to empty strings
t = {} --Make a table for the string to be sent into
for i = 1, #s do --Loop from 1 to the length of the string
    t[i] = s:sub(i, i) --Set the I-th term in the table to the I-th character in the string
    tl = tl+1 --Add 1 to the table length
end --End the loop
for v=1,tl-1, 1 do --Loop from 1 to the tables length - 1, incrementing by 1
    if t[v] < t[v+1] then --Lua supports greater than less than and equals to with charactes, so this if statement detects if the string is rising
        o1=o1.."o" --Adds an o to the end of the first line of output
        o2=o2.." " --Adds a space to the second line
        o3=o3.." " --Adds a space to the third line
    elseif t[v] == t[v+1] then --Detects if the string is continuing
        o1=o1.." " --Adds a space to the first line
        o2=o2.."o" --Adds an o to the second line
        o3=o3.." " --Adds a space to the third line
    elseif t[v] > t[v+1] then --Detects if string is falling
        o1=o1.." " --Adds a space to the first line
        o2=o2.." " --Adds a space to the second line
        o3=o3.."o" --Adds an o to the third line
    end --Ends the if statement
end --Ends the loop
print(o1.."\n"..o2.."\n"..o3) --Prints the output
\$\endgroup\$
2
  • \$\begingroup\$ I think you can golf out some whitespace from, say, t1 = 0? to t1=0? And similar places. \$\endgroup\$ – Conor O'Brien Sep 26 '16 at 21:41
  • \$\begingroup\$ I will fix that now \$\endgroup\$ – Alex Allen Sep 26 '16 at 22:07
0
\$\begingroup\$

R, 114 bytes

A non-competing R answer.

v=y=z=rep(" ",length(x<-diff(utf8ToInt(scan(,"")))));v[x>0]="#";y[x==0]="#";z[x<0]="#";cat(v,"\n",y,"\n",z,sep="")

Explanation

  1. Read input from command line and convert into ascii decimal vector
  2. Take 1st difference and create an 3x vectors of the same length with white spaces
  3. Then replace the white space vectors with # if the differences are >0, ==0 or <0.
  4. Coerce the vectors and print them separated by newlines
\$\endgroup\$
2
  • \$\begingroup\$ Why noncompeting? \$\endgroup\$ – Conor O'Brien Sep 27 '16 at 11:12
  • \$\begingroup\$ @ConorO'Brien I guess it's competing against other R answers but the original solution was way to long and not unique enough to be interesting in the general sense. \$\endgroup\$ – Billywob Sep 27 '16 at 11:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.