Draw a Bumpy String

26

1

(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

Conor O'Brien

Posted 2016-09-24T23:09:09.380

Reputation: 36 228

Could there be a space between each consecutive os, or does the output have to be compact? – JungHwan Min – 2016-09-25T00:04:08.180

@JHM Sure, that's fine. – Conor O'Brien – 2016-09-25T00:05:40.133

Also, does the output have to be a string, or does it only need to look similar to the example? – JungHwan Min – 2016-09-25T00:06:06.600

@JHM What do you ahve in mind? – Conor O'Brien – 2016-09-25T00:06:51.250

The code I have in mind generates a grid. – JungHwan Min – 2016-09-25T00:07:57.470

@JHM A grid? Could you give me an example? – Conor O'Brien – 2016-09-25T00:08:23.470

The output looks identical to the requirement, but copy/pasting it gives a list. – JungHwan Min – 2016-09-25T00:11:05.277

@Arnauld no, it is not. – Conor O'Brien – 2016-09-25T00:12:52.720

@JHM I only care about the output. – Conor O'Brien – 2016-09-25T00:13:06.057

May we output a list of three strings? – xnor – 2016-09-25T05:27:49.387

@xnor I suppose, yeah. – Conor O'Brien – 2016-09-25T05:29:53.597

Answers

6

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.

Dennis

Posted 2016-09-24T23:09:09.380

Reputation: 196 637

11

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

JungHwan Min

Posted 2016-09-24T23:09:09.380

Reputation: 13 290

How does the 41 byte look? – Conor O'Brien – 2016-09-24T23:54:07.873

@ConorO'Brien please see edit. – JungHwan Min – 2016-09-24T23:56:06.240

10

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.

James

Posted 2016-09-24T23:09:09.380

Reputation: 54 537

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. – Nick Alger – 2016-09-25T03:44:55.007

OK nevermind, tried that suggestion, doesn't seem to save anything – Nick Alger – 2016-09-25T04:13:17.103

@NickAlger Thanks for the tip anyway! Out of curiosity, could I see what you came up with? – James – 2016-09-25T04:14:01.910

Sure. The following is 19 chars, though it could probably be improved a few, dZS2+tn:tnZ?XPg79*c – Nick Alger – 2016-09-25T04:23:25.553

Got it to 16 with a couple optimizations, dZSqq_tn:lZ?79*c – Nick Alger – 2016-09-25T04:33:15.720

@NickAlger Oh nice! Another byte to take off: the output character is arbitrary, so you could just do 9*c instead of 79*c. You should post that as another answer (even though it's a tad longer) – James – 2016-09-25T04:34:46.603

For some reason it doesn't seem to work with just 9*c – Nick Alger – 2016-09-25T04:40:53.957

@NickAlger Oh, sorry about that. I tested that on your previous version, not the new one. – James – 2016-09-25T04:41:51.853

Ok, wrote it up in another answer here: http://codegolf.stackexchange.com/a/94452/42247

– Nick Alger – 2016-09-25T05:16:52.633

8

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.

Lynn

Posted 2016-09-24T23:09:09.380

Reputation: 55 648

3Great, it contains no subliminal messages! What are those? – Conor O'Brien – 2016-09-25T00:27:55.210

5['o'|b e y].. – izabera – 2016-09-25T14:53:00.203

Yes, my master Wait what's going on? – CalculatorFeline – 2017-03-03T16:35:05.540

7

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.

Martin Ender

Posted 2016-09-24T23:09:09.380

Reputation: 184 808

6

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"));

Arnauld

Posted 2016-09-24T23:09:09.380

Reputation: 111 334

1Since you can use any character, does replacing 'o' with 0 help any? – Conor O'Brien – 2016-09-25T00:17:15.290

@ConorO'Brien - Indeed, it does. ;) – Arnauld – 2016-09-25T00:19:10.347

1I 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. – ETHproductions – 2016-09-25T01:27:29.803

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(). – ETHproductions – 2016-09-25T01:36:28.447

6

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.

Dennis

Posted 2016-09-24T23:09:09.380

Reputation: 196 637

You're allowed to output a list of three strings, which lets you do a lambda. – xnor – 2016-09-25T05:41:32.943

I am? That changes everything. – Dennis – 2016-09-25T05:54:07.003

I asked in the comments because Lynn's Haskell answer was doing it. – xnor – 2016-09-25T06:03:11.790

4

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.

Nick Alger

Posted 2016-09-24T23:09:09.380

Reputation: 376

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 :-) – Luis Mendo – 2016-09-25T12:46:47.943

@LuisMendo Thanks! I edited the post to make the change you suggest – Nick Alger – 2016-09-25T18:37:03.567

4

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

Ton Hospel

Posted 2016-09-24T23:09:09.380

Reputation: 14 114

3

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

Jörg Hülsermann

Posted 2016-09-24T23:09:09.380

Reputation: 13 026

1

If you encode your program in Latin-1, is a handy shortcut for "\n". No, seriously!

– Lynn – 2016-09-25T00:37:28.480

1

Same thing for " ", which can be . Example. You want to set your browser encoding to Latin-1 when viewing these.

– Lynn – 2016-09-25T00:40:07.220

@Lynn or ~³~†~‘~‘ Thank You for the idea. I will prefer unicode – Jörg Hülsermann – 2016-09-25T11:20:13.127

2

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.

ETHproductions

Posted 2016-09-24T23:09:09.380

Reputation: 47 880

2

Ruby, 66 64 bytes

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

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

Jordan

Posted 2016-09-24T23:09:09.380

Reputation: 5 001

2

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

Kevin Cruijssen

Posted 2016-09-24T23:09:09.380

Reputation: 67 575

1I'm not sure whether this works but a,b,c=b=a="" would be shorter. – Frozn – 2016-09-26T14:30:13.403

@Frozn Thanks, edited. It indeed works. PS: you could have checked yourself in the ideone by forking it. ;) – Kevin Cruijssen – 2016-09-26T14:51:48.970

You're right! I'm always overlooking the links and starting up eclipse just for that isn't worth it :) – Frozn – 2016-09-26T15:25:40.020

2

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

OPSXCQ

Posted 2016-09-24T23:09:09.380

Reputation: 151

This seems to be strictly non-competing, as it was created after this challenge. This looks like an interesting lang though! – Conor O'Brien – 2016-09-26T18:36:28.113

1

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

TheBikingViking

Posted 2016-09-24T23:09:09.380

Reputation: 3 674

1

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

aross

Posted 2016-09-24T23:09:09.380

Reputation: 1 583

1You forgot to add -d error_reporting=30709 to your byte count. – Titus – 2016-09-26T19:29:44.677

@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! – aross – 2016-09-27T07:31:38.927

Could also add 2>/dev/null, but that will get rid of ALL errors, including fatal – aross – 2016-09-27T07:35:33.323

Oh, and a reference – aross – 2016-09-27T07:54:51.157

Something like If you get warnings, set the default value with .... Please excuse my pedantery; I didn´t decode that value. – Titus – 2016-09-27T12:23:54.797

0

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

Alex Allen

Posted 2016-09-24T23:09:09.380

Reputation: 91

I think you can golf out some whitespace from, say, t1 = 0? to t1=0? And similar places. – Conor O'Brien – 2016-09-26T21:41:42.527

I will fix that now – Alex Allen – 2016-09-26T22:07:09.207

0

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

Billywob

Posted 2016-09-24T23:09:09.380

Reputation: 3 363

Why noncompeting? – Conor O'Brien – 2016-09-27T11:12:00.693

@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. – Billywob – 2016-09-27T11:22:07.367