Is it a Bumpy Word?

31

4

(inspired by this challenge over on Puzzling -- SPOILERS for that puzzle are below, so stop reading here if you want to solve that puzzle on your own!)

If a letter in a word occurs alphabetically later than the previous letter in the word, we call that a rise between the two letters. Otherwise, including if it's the same letter, it's called a fall.

For example, the word ACE has two rises (A to C and C to E) and no falls, while THE has two falls (T to H and H to E) and no rises.

We call a word Bumpy if the sequence of rises and falls alternates. For example, BUMP goes rise (B to U), fall (U to M), rise (M to P). Note that the first sequence need not be a rise -- BALD goes fall-rise-fall and is also Bumpy.

The challenge

Given a word, output whether or not it's Bumpy.

Input

  • A word (not necessarily a dictionary word) consisting of ASCII alphabet ([A-Z] or [a-z]) letters only, in any suitable format.
  • Your choice if the input is all uppercase or all lowercase, but it must be consistent.
  • The word will be at least 3 characters in length.

Output

A truthy/falsey value for whether the input word is Bumpy (truthy) or not Bumpy (falsey).

The Rules

  • Either a full program or a function are acceptable.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

Truthy:

ABA
ABB
BAB
BUMP
BALD
BALDY
UPWARD
EXAMINATION
AZBYCXDWEVFUGTHSIRJQKPLOMN

Falsey:

AAA
BBA
ACE
THE
BUMPY
BALDING
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=93005,OVERRIDE_USER=42963;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

AdmBorkBork

Posted 2016-09-12T13:57:49.383

Reputation: 41 581

Dangit. This would be easier if same letter was neither rise nor fall. – mbomb007 – 2016-09-12T14:55:55.287

I don't understand provided examples: if BUMP is listed in Truthy (i.e. Bumpy), why BUMPY is in the Falsey list? What does "rises and falls alternates" means? Two rise s cannot be successively? – VolAnd – 2016-09-13T06:59:57.947

4@VolAnd Yes, it means that a rise is always followed by a fall and vice versa. BUMPY is falsy because MPY gives two consecutive rises. In other words, no substring of length 3 must be sorted ascendingly or descendingly for a word to be bumpy (apart from the special case where two consecutive letters are identical). – Martin Ender – 2016-09-13T07:36:32.793

Can you spoiler the answer to the Puzzling.SE question so others who wish to solve it themselves can do so? – OldBunny2800 – 2016-09-14T00:44:31.730

1@OldBunny2800 I won't put a full spoiler in (I don't want to make my challenge here hard to read by hiding crucial information behind a spoiler), but I'll add some additional text to the top as a warning. Thanks! – AdmBorkBork – 2016-09-14T00:51:04.440

It would be interesting to also have a variation of this based on "visual bumpyness", where h, t, l, d, b, f, i, j, and k are 'taller' than the other letters, and must alternate with them. – Skyler – 2016-09-14T20:39:41.393

@Skyler That sounds kinda neat -- sandbox it up! – AdmBorkBork – 2016-09-14T20:46:45.680

Answers

31

MATL, 4 bytes

d0>d

Explanation:

d     % Implicitly take input. Take difference between each element
 0>   % Check whether diff's are positive. Should result in [0 1 0 1 ...] pattern.
   d  % Again take the difference. Any consecutive rises or falls results in a 
      % difference of 0, which is a falsy value in MATL

This is my first MATL entry, so I wonder how much improvement there can be from this naive port from my MATLAB/Octave attempt (which would be @(a)all(diff(diff(a)>0))). Note that the all is not necessary because any zero makes an array false, so there's no A in the MATL port.

Sanchises

Posted 2016-09-12T13:57:49.383

Reputation: 8 530

See the corrected challenge. There was a typo in a test case. Your approach was correct. In fact, d0>d should work (you don't need the A as per our definition of truthy/falsey) – Luis Mendo – 2016-09-12T15:00:41.653

1Nice work, outgolfing Luis in his own language! I've tried before, and that's no easy task. ;) – James – 2016-09-12T15:06:38.673

@DJMcMayhem Haha. That's what I get for reading the challenge too quickly. In my defense, it's counter-intuitive that two equal letters are a fall. And the (now corrected) misleading test cases didn't help either :-) – Luis Mendo – 2016-09-12T15:08:32.160

1@DJMcMayhem Thanks - although maybe I just got lucky, because I didn't actually think about consecutive equal letters, but that turned out to be exactly what was asked... – Sanchises – 2016-09-12T15:14:19.997

@sanchises You should remove that byte (d0>d) before someone else posts a 4-byte answer in some language... – Luis Mendo – 2016-09-12T15:16:26.197

@LuisMendo I never really liked that definition of truthy/falsy, but I guess you're right. – Sanchises – 2016-09-12T15:30:04.050

... so an array with any 0 elements in it is falsy? – user253751 – 2016-09-14T05:28:17.267

1

@immibis In MATL(AB) and Octave, yes. See this Meta answer.

– Sanchises – 2016-09-14T07:22:07.807

24

JavaScript (ES6), 75 69 63 46 43 bytes

Saved 3 bytes thanks to Neil:

f=([c,...s])=>s[1]?c<s[0]^s[0]<s[1]&&f(s):1

Destructuring the string parameter instead of s.slice(1).


Previous solution:
Saved 17 bytes thanks to ETHproductions:

f=s=>s[2]?s[0]<s[1]^s[1]<s[2]&&f(s.slice(1)):1

What happened from the previous solution step by step:

f=(s,i=0,a=s[i++]<s[i])=>s[i+1]&&(b=a^(a=s[i]<s[i+1]))?f(s,i):b // (63) Original
f=(s,i=0,a=s[i++]<s[i])=>s[i+1]&&(b=a^(s[i]<s[i+1]))?f(s,i):b   // (61) No point in reassigning `a`, it's not used again
f=(s,i=0,a=s[i++]<s[i])=>s[i+1]&&(b=a^s[i]<s[i+1])?f(s,i):b     // (59) Remove unnecessary parentheses
f=(s,i=0)=>s[i+2]&&(b=s[i++]<s[i]^s[i]<s[i+1])?f(s,i):b         // (55) `a` is now just a waste of bytes
f=(s,i=0)=>s[i+2]?(b=s[i++]<s[i]^s[i]<s[i+1])?f(s,i):b:1        // (56) Rearrange conditional expressions to allow for more golfing
f=(s,i=0)=>s[i+2]?(b=s[i++]<s[i]^s[i]<s[i+1])&&f(s,i):1         // (55) Rearrange conditional expression
f=(s,i=0)=>s[i+2]?(s[i++]<s[i]^s[i]<s[i+1])&&f(s,i):1           // (53) `b` is now also a waste of bytes
f=(s,i=0)=>s[i+2]?s[i++]<s[i]^s[i]<s[i+1]&&f(s,i):1             // (51) Remove unnecessary parentheses
f=s=>s[2]?s[0]<s[1]^s[1]<s[2]&&f(s.slice(1)):1                  // (46) Use `s.slice(1)` instead of `i`


Previous solutions:
63 bytes thanks to ETHproductions:

f=(s,i=0,a=s[i++]<s[i])=>s[i+1]&&(b=a^(a=s[i]<s[i+1]))?f(s,i):b

69 bytes:

f=(s,i=0,a=s[i++]<s[i])=>i+1<s.length&&(b=a^(a=s[i]<s[i+1]))?f(s,i):b

75 bytes:

f=(s,a=s[0]<s[1])=>{for(i=1;i+1<s.length&&(b=a^(a=s[i++]<s[i])););return b}

All letters in a word must have the same case.

Hedi

Posted 2016-09-12T13:57:49.383

Reputation: 1 857

2

You can golf it down quite a bit further: https://github.com/ETHproductions/golf/blob/gh-pages/misc/93014.js

– ETHproductions – 2016-09-12T15:36:12.227

@ETHproductions Should I post the content of your link ? – Hedi – 2016-09-12T16:10:56.127

You can if you'd like :-) – ETHproductions – 2016-09-12T16:18:39.020

Can !s[2]|... do the same as s[2]?...:1? – Titus – 2016-09-12T18:20:24.480

@Titus the recursion won't stop. If you mean !s[2]||... it's still 46 bytes – Hedi – 2016-09-12T18:28:55.547

Have you tested it? When !s[2] is true, !s[2]|... is also true and (thanks to short-circuit evaluation) the function call will not be evaluated. – Titus – 2016-09-12T19:01:23.897

@Titus One pipe | is the bitwise operator whithout short-circuit evaluation. To use the short-circuit evaluation I need the boolean operator with two pipes ||. With the boolean operator it works but I don't save any bytes. With the bitwise operator I get InternalError: too much recursion at the execution. – Hedi – 2016-09-12T20:50:12.133

Dread. Why does it work in PHP and not in JS? The short circuit should kick in at the &&. – Titus – 2016-09-12T21:23:51.337

@Titus I got the error with truthy values. I just tested falsy values and it works. For a truthy value, what should be the last recursive call is done with a string of only two char. !s[2] is true so !s[2]|... is true. The second operand of the &&f(s.slice(1)) is evaluated with a string less than 3 char again... – Hedi – 2016-09-12T22:43:53.657

I like the face at the end: :1 – DanTheMan – 2016-09-13T01:52:55.427

1Sorry for being late to the party, but for 43 bytes I give you: f=([c,...s])=>s[1]?c<s[0]^s[0]<s[1]&&f(s):1 – Neil – 2016-09-16T08:51:06.063

14

LabVIEW, 36 equivalent bytes

Golfed down using logical equivalences:

golfed

Ungolfed:

ungolfed

First we convert to lowercase, then to byte array. Trim off the first element of the byte array as it has no precedent. Then, for each element in the array, check if it's greater than the previous one (U8 char maps to ASCII as you expect) and store the result for the next iteration, as well as in an array for viewing overall bumpiness. If the current and prior boolean check are equal, we terminate the loop and it's not bumpy. Else, it's bumpy!

ijustlovemath

Posted 2016-09-12T13:57:49.383

Reputation: 341

1What a cool language! Welcome to PPCG! – James – 2016-09-13T01:31:44.093

1Thanks! I'll never compete with the 4 byte answers, but it's a nice way to improve my skills :) – ijustlovemath – 2016-09-13T01:34:18.533

See here. Your scoring is definitely wrong and overly excessive. I don't think your answer is really 246450 - 246549 bytes.

– Erik the Outgolfer – 2016-09-13T12:20:57.397

I was going off the Memory tab, as I didn't know there was a concept of equivalent bytes for LabVIEW. Will count them up and edit answer later today. – ijustlovemath – 2016-09-13T12:23:35.967

You can assume the input is given in lowercase, if that makes your code shorter. That's the second bullet point under Input. – AdmBorkBork – 2016-09-13T12:52:47.910

It would save the very first node that the string goes into. There are some optimizations with the case structure that could rid the !=0 check, as well as the logical not on the bumpy Boolean, though I think I'd have to add wires to have the equivalent function. I can also get rid of the auto indexed node as that's just for debugging. Could probably shave it down to <30 equivalent bytes, but will have to look at this later. – ijustlovemath – 2016-09-13T14:13:31.207

@EriktheGolfer That link is broken. – Fund Monica's Lawsuit – 2016-09-13T20:03:36.067

@QPaysTaxes Here's the full URL: http://meta.codegolf.stackexchange.com/questions/7502/programming-in-labview-how-to-measure-program-size/7589#7589

– ijustlovemath – 2016-09-13T20:04:45.350

@EriktheGolfer I clicked it, it didn't work when I clicked it. I still get "Problem loading page" when I try using it. Meanwhile, the question itself loads just fine. – Fund Monica's Lawsuit – 2016-09-14T14:11:37.643

1

@Erik I'm on Firefox on Windows, but opening it on mobile also breaks things. Just http://meta.ppcg.lol/ works. Anyway, this is out of scope for comments.

– Fund Monica's Lawsuit – 2016-09-14T14:19:12.477

@QPaysTaxes Well, I think you might be using old software, or it is a problem with your ISP. I will open a chat-room if we continue discussion (I have deleted comments). – Erik the Outgolfer – 2016-09-14T14:39:58.680

8

Python, 56 bytes

lambda s:all((x<y)^(y<z)for x,y,z in zip(s,s[1:],s[2:]))

All test cases are at ideone

Zips through triples of characters in s and tests that all such triples have left and right pairs with different rise/fall properties.
Works for either all uppercase or all lowercase.

Jonathan Allan

Posted 2016-09-12T13:57:49.383

Reputation: 67 804

6

C 59 Bytes

r;f(s)char*s;{for(r=0;r=*s?~r&1<<(*s>=*++s):0;);return!*s;}

cleblanc

Posted 2016-09-12T13:57:49.383

Reputation: 3 360

The solution in 70 bytes returns 1 (True) for case AAA - the first "Falsey" in the examples – VolAnd – 2016-09-13T05:31:38.740

I'm testing using gcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125) and I get false for aaa and excited. In this version non-zero is falsey, and zero is truthy. Actually wondering now if this is allowed. – cleblanc – 2016-09-13T13:44:31.137

Call f("ABCDEFGHIJKLMNOPQRSTUVWXYZ") compiled in Visual Studio 2012 returns value 23 that can be treated as True but in the question this value is in section "Falsey", so value 0 expected. – VolAnd – 2016-09-13T14:01:50.143

I misunderstood what was allowed for True and Falsey. Now I've read the that post and it seems clear what the values must be for "C". – cleblanc – 2016-09-13T14:20:13.353

Here's our standard definitions for truthy and falsey, based on Meta consensus.

– AdmBorkBork – 2016-09-13T19:04:50.657

@cleblanc I tested your solution in 58 bytes (r;f(char*s){for(*++s;r=~r&1<<(*--s>*++s);++s);return !*s;}) and found that for strings from question answer is always 0 - perhaps, you forgot something – VolAnd – 2016-09-14T11:36:11.817

It seems that for input that's starting with a fall "bab" the terminating condition on the for loop goes past the end of the string. It works every time for me with cygwin gcc even though I can see s incremented past the end of the string. When I try with inputs that start with a rise "aba" the terminating condition seems correct as well as the output. I'm looking into it now and hope to post a fix later. Thanks! – cleblanc – 2016-09-14T14:40:53.077

I think this would be a lot clearer if you removed the previous versions. We'll still be able to see them in the revision history. Also, per meta consensus, functions have to be reusable. The second time the function is called, r may have a non-zero value, so you have to reset it from within the function.

– Dennis – 2016-09-15T20:00:27.860

I'm disappointed with the reusable function rule, I wasn't aware of it before. Is it ok to pass the value as an additional parameter to the function? For example this f(r,s)char*s;{for(;r=*s?~r&1<<(*s>=*++s):0;);return !*s;} is only 57 bytes but now the user needs to pass 0 as the first parameter. Do I need to add additional bytes for this? Similarly they could set the global r variable to zero before calling f(...) as well... – cleblanc – 2016-09-15T20:34:59.637

Just saw your xomment by accident (use @Dennis to reply), and no, that isn't allowed. You can leave r as a global though and put r=0 after for(, for only one extra byte. You can get it back by eliminating the space after return. – Dennis – 2016-09-16T04:47:10.477

@Dennis thanks for the tip. – cleblanc – 2016-09-16T12:43:05.377

6

Ruby, 57 48 bytes

Expects input to be all uppercase.

->s{!s.gsub(/.(?=(.)(.))/){($&<$1)^($1<$2)}[?f]}

See it on repl.it: https://repl.it/D7SB

Explanation

The regular expression /.(?=(.)(.))/ matches each character that's followed by two more characters. (?=...) is a positive lookahead, meaning we match the subsequent two characters but don't "consume" them as part of the match. Inside the curly braces, $& is the matched text—the first character of the three—and $1 and $2 are the captured characters inside the lookahead. In other words, if the string is "BUMPY", it will first match "B" (and put it in $&) and capture "U" and "M" (and put them in $1 and $2). Next it will match "U" and capture "M" and "P", and so on.

Inside the block we check if the first pair of characters ($& and $1) is a rise and the second ($1 and $2) is a fall or vice versa, much like most of the other answers. This ^ expression returns true or false, which gets converted to a string and inserted in place of the match. As a result, our example "BUMPY" becomes this:

"truetruefalsePY"

Since we know the input is all uppercase, we know "f" will only occur as part of "false" and !result[?f] gives us our answer.

Jordan

Posted 2016-09-12T13:57:49.383

Reputation: 5 001

How does it work? – GreenAsJade – 2016-09-13T08:44:01.383

1@GreenAsJade I've added an explanation to my answer. – Jordan – 2016-09-13T12:45:04.993

6

C#, 64 63 55 bytes

unsafe bool B(char*s)=>1>s[2]||*s<s[1]!=*++s<s[1]&B(s);

-8 bytes from Scepheo's suggestions

This is a port of Hedi's solution to C#. I also came up with a recursive solution, but the recursion wasn't as good. My original solution is below.

My Original C#, 96 94 91 bytes

unsafe bool B(char*s,bool f=1>0,int i=0)=>1>s[1]||(s[0]<s[1]?f:1>i?!(f=!f):!f)&B(s+1,!f,1);

-2 bytes by using 1>0 instead of true.

-3 bytes from Scepheo's suggestions for the port solution above

Calls itself recursively checking that the rising/falling alternates each time.

Ungolfed:

// unsafe in order to golf some bytes from string operations.
// f alternates with each recursive call
// i is 0 for the first call, 1 for all subsequent calls
unsafe bool B(char* s, bool f = 1 > 0, int i = 0) =>
    1 > s[1] ? 1 > 0// (instead of 1 == s.Length) check if s[1] = NULL, and return true.
    : (
        s[0] < s[1] ? f // Rising, so use f...
        : // Else falling
            1 > i ? !(f=!f) // But this is the first call, so use true (but flip f)...
            : !f // Not first call, so use !f...
    )
    & B(s+1, !f, 1) // ...AND the previous value with a recursive call
                    // s+1 instead of s.Substring(1)
;

milk

Posted 2016-09-12T13:57:49.383

Reputation: 3 043

Seems like the last one can do without the ?: operator or parentheses: unsafe bool B(char*s)=>1>s[2]|s[0]<s[1]!=s[1]<s[2]&B(s+1); – Scepheo – 2016-09-13T13:19:01.167

Actually, although I can't test this, manipulating the pointer itself seems even terser: unsafe bool B(char*s)=>1>s[2]|*s<s[1]!=*++s<s[1]&B(s); – Scepheo – 2016-09-13T13:36:38.840

@Scepheo I got StackOverflowExceptions with those suggestions, but they work using boolean OR || instead of bitwise OR |. Updated the post, thanks. – milk – 2016-09-13T19:26:19.343

5

JavaScript (ES6), 65 bytes

s=>[...s].map(C=>(c?(R=c<C,i++?t&=r^R:0,r=R):t=1,c=C),c=r=i="")|t

.map is definitely not the best solution.

ETHproductions

Posted 2016-09-12T13:57:49.383

Reputation: 47 880

5

Python 2, 88 bytes

Simple solution.

s=input()
m=map(lambda x,y:y>x,s[:-1],s[1:])
print all(x-y for x,y in zip(m[:-1],m[1:]))

Try it online

If same letters in a row were neither a rise nor a fall, the solution would be 79 bytes:

s=input()
m=map(cmp,s[:-1],s[1:])
print all(x-y for x,y in zip(m[:-1],m[1:]))

mbomb007

Posted 2016-09-12T13:57:49.383

Reputation: 21 944

5

Jelly, 6 bytes

OI>0IẠ

Based on @sanchises' answer.

Try it online! or Verify all.

Explanation

OI>0IẠ  Input: string S
O       Convert each char in S to an ordinal
 I      Get the increments between each pair
  >0    Test if each is positive, 1 if true else 0
    I   Get the increments between each pair
     Ạ  Test if the list doesn't contain a zero, 1 if true else 0

miles

Posted 2016-09-12T13:57:49.383

Reputation: 15 654

5

Perl, 34 bytes

Includes +3 for -p (code contains ' so -e can't be used)

Give uppercase input on STDIN:

bump.pl <<< AAA

bump.pl

#!/usr/bin/perl -p
s%.%$&.z lt$'|0%eg;$_=!/(.)\1./

Ton Hospel

Posted 2016-09-12T13:57:49.383

Reputation: 14 114

5

Jelly, 6 5 bytes

-1 byte thanks to @Dennis (use a cumulative reduction)

<2\IẠ

All test cases are at TryItOnline

How?

<2\IẠ - main link takes an argument, s,    e.g. "BUMP"    or "BUMPY"
<    - less than comparison (a dyad)
 2   - literal 2 (a nilad)
  \  - n-wise overlapping reduction when preceded by a dyad-nilad chain
       (i.e. reduce the list by pairs with less than)
                                           e.g. [1,0,1]   or [1,0,1,1]
   I  - consecutive differences,           e.g. [-1,1]    or [-1,1,0]
    Ạ - All, 0 if any values are 0 else 1, e.g. 1         or 0

Works for either all uppercase or all lowercase.

Jonathan Allan

Posted 2016-09-12T13:57:49.383

Reputation: 67 804

5

Python, 51 bytes

g=lambda a,b,c,*s:((a<b)^(b<c))*(s==()or g(b,c,*s))

Takes input like g('B','U','M','P') and outputs 1 or 0.

Uses argument unpacking to take the first three letters and check if the first two compare differently from the second two. Then, recurses on the remainder, using multiplication for and.

xnor

Posted 2016-09-12T13:57:49.383

Reputation: 115 687

Nice input golf. ;-) – AdmBorkBork – 2016-09-13T12:53:59.773

4

Java 7, 157 153 150 125 117 bytes

int c(char[]z){for(int i=2,a,b,c;i<z.length;i++)if(((a=z[i-1])<(c=z[i])&(b=z[i-2])<a)|(a>=c&b>=a))return 0;return 1;}

Ungolfed & test cases:

Try it here.

class M{
  static int c(char[] z){
    for(int i = 2, a, b, c; i < z.length; i++){
      if(((a = z[i-1]) < (c = z[i]) & (b = z[i-2]) < a) | (a >= c & b >= a)){
        return 0; //false
      }
    }
    return 1; //true
  }

  public static void main(String[] a){
    System.out.print(c("ABA".toCharArray()) + ", ");
    System.out.print(c("ABB".toCharArray()) + ", ");
    System.out.print(c("BAB".toCharArray()) + ", ");
    System.out.print(c("BUMP".toCharArray()) + ", ");
    System.out.print(c("BALD".toCharArray()) + ", ");
    System.out.print(c("BALDY".toCharArray()) + ", ");
    System.out.print(c("UPWARD".toCharArray()) + ", ");
    System.out.print(c("EXAMINATION".toCharArray()) + ", ");
    System.out.print(c("AZBYCXDWEVFUGTHSIRJQKPLOMN".toCharArray()) + ", ");

    System.out.print(c("AAA".toCharArray()) + ", ");
    System.out.print(c("ACE".toCharArray()) + ", ");
    System.out.print(c("THE".toCharArray()) + ", ");
    System.out.print(c("BUMPY".toCharArray()) + ", ");
    System.out.print(c("BALDING".toCharArray()) + ", ");
    System.out.print(c("ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) + ", ");
  }
}

Output:

1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0

Kevin Cruijssen

Posted 2016-09-12T13:57:49.383

Reputation: 67 575

@TimmyD Hmm, so it's rise when a > b, but fall when a <= b, instead of > and <? – Kevin Cruijssen – 2016-09-12T14:51:48.317

@TimmyD Ok, it's fixed, and even saves 3 bytes. :) – Kevin Cruijssen – 2016-09-12T14:58:44.940

1you can redefine your method to accept char[] so you dont have to transform your input string to char array. that should save a few bytes. PS: java ftw! – peech – 2016-09-12T15:01:04.850

@peech Thanks.. sometimes I forget the most obvious golfing things.. Normally I always use char[] input when I can, but now I just forgot to.. Thanks for the reminder! It saved 25 bytes. ;p – Kevin Cruijssen – 2016-09-12T15:04:21.740

1Did you perhaps means to change String s --> char[]z? – None – 2016-09-13T13:54:29.877

1You can return a truthy or falsey value, so make your method an int and return 1 or 0 :).. Puts you down to 117 bytes – Shaun Wild – 2016-09-14T08:46:24.153

4

Japt, 8 bytes

Uä> ä- e

Test it online!

How it works

Uä> ä- e  // Implicit: U = input string
Uä>       // Map each pair of chars X, Y in U to X > Y.
    ä-    // Map each pair of items in the result to X - Y.
          // If there are two consecutive rises or falls, the result contains a zero.
       e  // Check that every item is truthy (non-zero).
          // Implicit: output last expression

ETHproductions

Posted 2016-09-12T13:57:49.383

Reputation: 47 880

Same as my solution. Except 11x shorter. :P – mbomb007 – 2016-09-12T15:18:19.367

4

C# 105 104 Bytes

bool f(char[]x){int t=1;for(int i=2,p=x[1],f=x[0]-p>>7;i<x.Length;)f^=t&=p<(p=x[i++])?1-f:f;return t>0;}

105 bytes Solution:

bool f(char[]x){bool t=1>0,f=x[0]<x[1];for(int i=2,p=x[1];i<x.Length;)f^=t&=p<(p=x[i++])?!f:f;return t;}

Try it online

Using an array of chars saved one byte since the space can be omitted after the brackets. f(string x) vs f(char[]x)

It is 101 bytes if I can return an int 1/0 instead of bool true/false

int f(char[]x){int t=1;for(int i=2,p=x[1],f=x[0]-p>>7;i<x.Length;)f^=t&=p<(p=x[i++])?1-f:f;return t;}

pinkfloydx33

Posted 2016-09-12T13:57:49.383

Reputation: 308

4

Haskell, 52 bytes

f x=and$g(/=)$g(>)x
  where g h y=zipWith h(tail y)y

I suspect I could get this a chunk smaller if I managed to get rid of the "where" construct, but I'm probably stuck with zipWith.

This works by making a list of the rises (True) and falls (False), then making a list of if the ajacent entries in this list are different


This is my first attempt at one of these, so I'll go through my thought process in case I've gone horribly wrong somewhere.

Ungolfed Version (168 bytes)

isBumpy :: [Char] -> Bool
isBumpy input = and $ areBumps $ riseFall input
  where
    riseFall ax@(x:xs) = zipWith (>) xs ax
    areBumps ax@(x:xs) = zipWith (/=) xs ax

Shorten names, remove type information (100 bytes)

f x = and $ g $ h x
  where
    h ax@(x:xs) = zipWith (>) xs ax
    g ax@(x:xs) = zipWith (/=) xs ax

Move h into the main function as it is only used once (86 bytes)

f ax@(x:xs) = and $ g $ zipWith (>) xs ax
  where
    g ax@(x:xs) = zipWith (/=) xs ax

Realise that areBumps and riseFall are similar enough to abstract (73 bytes)

f x  = and $ g (/=) $ g (>) x
  where
    g h ya@(y:ys) = zipWith h ys ya

Note that (tail y) is shorter than ya@(y:ys) (70 bytes)

f x  = and $ g (/=) $ g (>) x
  where
    g h y = zipWith h (tail y) y

Tidy up; remove unneeded spaces (52 bytes)

f x=and$g(/=)$g(>)x
  where g h y=zipWith h(tail y)y

Teron

Posted 2016-09-12T13:57:49.383

Reputation: 141

... and I've just noticed a shorter Haskell answer that was posted before mine that does basically the same thing. I am terrible at spotting things. – Teron – 2016-09-14T17:12:09.650

You mean the one that doesn't work? ;-) You may use g h=tail>>=zipWith h and make it a global function to avoid the where keyword. – Christian Sievers – 2016-09-19T13:28:06.830

@ChristianSievers Fixed it, and I just noticed this answer which now does exactly the same thing as mine, rendering my answer better suited as a comment to this one. – BlackCap – 2016-09-19T15:47:32.717

3

PowerShell v2+, 83 bytes

param($n)($a=-join(1..($n.Length-1)|%{+($n[$_-1]-lt$n[$_])}))-eq($a-replace'00|11')

A little bit of a different approach. This loops through the input $n, each iteration seeing whether the previous character $n[$_-1] is -lessthan the current character $n[$_], then casting the result of that Boolean operator to an int with +. Those are -joined together into a string, stored into $a. We then check whether $a is -equal to $a with any substrings of 00 or 11 removed.

AdmBorkBork

Posted 2016-09-12T13:57:49.383

Reputation: 41 581

3

Python 2.7, 84 bytes

s=input()
b=s[0]<s[1]
o=1
for i in range(len(s)-1):o&=(s[i]<s[i+1])==b;b^=1
print o

Returns 1 for bumpy, 0 for otherwise

Learned some cool stuff with bitwise & and ^.
Starts with boolean b defining first pair as up/down, then tests and flips b for each following pair.
o flips to false if test fails and sticks.
Requires quotes around input (+4 bytes for raw_input() if that breaks some rule)

Test It

greyShift

Posted 2016-09-12T13:57:49.383

Reputation: 221

3

05AB1E, 9 bytes

SÇ¥0›¥_O_

Explanation

SÇ          # convert to list of ascii values
  ¥         # take delta's
   0›       # check if positive, giving a list of 1's and 0's
            # if they alternate, the word is bumpy
     ¥      # take delta's again, if we have any 0's in the list the word is not bumpy
      _     # logical negation, turning 0 into 1 and everything else to 0
       O    # sum, producing 0 for a bumpy word and 1 for a non-bumpy word
        _   # logical negation, inverting the previous 1 into 0 and vice versa

Try it online!

Emigna

Posted 2016-09-12T13:57:49.383

Reputation: 50 798

2

PHP, 80 bytes

$s=$argv[1];for($c=$s[0];$n=$s[++$i];$c=$n,$d=$e)if($d===$e=$n>$c)break;echo!$n;

or

for($c=$argv[1][0];$n=$argv[1][++$i];$c=$n,$d=$e)if($d===$e=$n>$c)break;echo!$n;

empty output for false, 1 for true

or Hedi´s recursive approach ported and a little golfed for 70 bytes:

function f($s){return!$s[2]|$s[0]<$s[1]^$s[1]<$s[2]&&f(substr($s,1));}

Actually, this should recurse infinitely for bumpy words, but it does not!

Titus

Posted 2016-09-12T13:57:49.383

Reputation: 13 814

2

Python 2.7 (again, 84 83 bytes)

def a(s):x=s[1:];return[cmp(s[0],x)]+a(x) if x else []
print len(set(a(input())))>1

Or, 78 77 bytes without the print.

By the way, the above 56 byte Python 2.7 example breaks on, for example, "abbab" or any other input with repeated characters. Never mind, didn't read instructions. Revising.

Okay, down to 83. The triples one is nicer though.

Timothy Teräväinen

Posted 2016-09-12T13:57:49.383

Reputation: 121

Here's some tips for ya. 1. Remove some whitespace a(x)if x else[]. 2. Use a lambda instead a=lambda s:[cmp(s[0],s[1:])]+a(s[1:])if s[1:]else[] 3. Use a lambda at the end instead of printing. lambda s:len(set(a(s)))>1 4. if len(set(a(s))) isn't greater than 1, than it's already falsy, so you can take off >1 – James – 2016-09-13T02:12:16.310

2

CJam, 15 bytes

l2ew::<2ew::^:*

Try it online! (As a linefeed-separated test-suite.)

Explanation

l    e# Read input.
2ew  e# Get all (overlapping) pairs.
::<  e# Check whether each pair is strictly ascending (1) or not (0).
2ew  e# Get all (overlapping) pairs.
::^  e# Take the bitwise XOR of each pair, giving 1 if a rise and a fall alternate,
     e# and zero if there are two rises or two falls in succession.
:*   e# Product. Gives 1 only if the previous step yielded a list of 1s, meaning
     e# that any two consecutive rises/falls will turn this into a zero.

Martin Ender

Posted 2016-09-12T13:57:49.383

Reputation: 184 808

2

Haskell, 30 37 bytes

q f=tail>>=zipWith f;k=and.q(/=).q(>)

Usage:

Prelude> k <$> words "ABA ABB BAB BUMP BALD BALDY UPWARD EXAMINATION AZBYCXDWEVFUGTHSIRJQKPLOMN"
[True,True,True,True,True,True,True,True,True]

Prelude> k <$> words "AAA BBA ACE THE BUMPY BALDING ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[False,False,False,False,False,False,False]

BlackCap

Posted 2016-09-12T13:57:49.383

Reputation: 3 576

That doesn't accept "bald", foldl1(/=) doesn't do what you think it does. – Christian Sievers – 2016-09-19T13:18:17.743

@ChristianSievers Auch, you're right. Thanks for the heads up – BlackCap – 2016-09-19T15:33:22.143

2

PHP 7, 137 118 bytes

for($i=0;$i<strlen($argv[1])-2;$i++)if(((($s[$i]<=>$s[$i+1])<0)?1:0)==((($s[$i+1]<=>$s[$i+2])<0)?1:0)){echo"0";break;}

Empty output for Bumpy, 0 for Not Bumpy.

This is my first attempt at code golfing and I have to improve a lot, but it was a wonderful method to learn new things for me. I also wanted to challenge myself on that task by using the new PHP 7 Spaceship Operator which seems very interesting.

Anyway I'm not satisfied about it, first of all for the fact that I had to add an extra if(isset($s[$i+2])) to check if the variable exist because I did not find another workaround to the problem, but this is it for now. (Note: I fixed that simply by changing strlen($s)-1 to strlen($s)-2, I couldn't really see that before...).

Testing code:

$as = array("ABA", "ABB", "BAB", "BUMP", "BALD", "BALDY", "UPWARD", 
            "EXAMINATION", "AZBYCXDWEVFUGTHSIRJQKPLOMN", "AAA", "BBA", 
            "ACE", "THE", "BUMPY", "BALDING", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");

foreach ($as as $s) {
    for($i=0;$i<strlen($s)-2;$i++)if(((($s[$i]<=>$s[$i+1])<0)?1:0)==((($s[$i+1]<=>$s[$i+2])<0)?1:0)){echo"0";break;}
}

Test online

Mario

Posted 2016-09-12T13:57:49.383

Reputation: 3 043

Hello, and welcome to PPCG! Great first post! – NoOneIsHere – 2016-09-16T16:13:20.127

Welcome to PPCG! Nice first post. Check out Tips for PHP for some additional golfing suggestions.

– AdmBorkBork – 2016-09-16T16:29:23.357

1

Javascript ES6, 100 bytes

d="charCodeAt";a=b=>{f=r=0;for(i=1;i<b.length;i++){if(b[d](i)<=b[d](i-1)){f=1}else{r=1}}return f&&r}

Try it here:

d="charCodeAt";a=b=>{f=r=0;for(i=1;i<b.length;i++){if(b[d](i)<=b[d](i-1)){f=1}else{r=1}}return f&&r}
alert(a(prompt()));

Oh come on two people already beat me to it by 40 bytes... whatever

Bald Bantha

Posted 2016-09-12T13:57:49.383

Reputation: 463

Hint: "A"<"B", so you don't need to get the chars' charcodes. – ETHproductions – 2016-09-12T15:42:39.783

Also, this returns 1 for BUMPY (or anything else that contains both a rise and a fall). – ETHproductions – 2016-09-12T15:57:40.830

This doesn't seem to quite work right. – AdmBorkBork – 2016-09-13T12:39:09.173

1

Python 3, 148 139 127 bytes

def _(w):*r,=map(lambda a,b:0>ord(a)-ord(b)and-1or 1,w,w[1:]);s=len(r)%2==0and r+[r[0]]or r;return sum(s)in(-1,1)and s==s[::-1]

testing code

positives = ('ABA', 'ABB', 'BAB', 'BUMP', 'BALD', 'BALDY', 'UPWARD', 'EXAMINATION', 'AZBYCXDWEVFUGTHSIRJQKPLOMN')
negatives = ('AAA', 'BBA', 'ACE', 'THE', 'BUMPY', 'BALDING', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')

for w in positives:
    print(_(w), w)
    assert _(w)

for w in negatives:
    print(_(w), w)
    assert not _(w)

Jeffrey04

Posted 2016-09-12T13:57:49.383

Reputation: 131

i really suck at this #facepalm – Jeffrey04 – 2016-09-13T02:33:24.240

Welcome to PPCG! Check out Tips for Golfing in Python, and take inspiration from the other answers.

– AdmBorkBork – 2016-09-13T12:55:24.377

1

C, 65 57 60 bytes

 r;f(char*s){for(r=0;*++s&&(r=~r&1<<(*s>*(s-1))););return r;}

is fix of

r;f(char*s){for(;*++s&&(r=~r&1<<(*s>*(s-1))););return r;}

that works correctly with any data only at single function call (when the global variable r is initialized to zero).

But in any case this is shorter than previous solution (65 bytes) due to use of for instead of while. But previous (the following) is a little easier to understand:

r;f(char*s){while(*++s)if(!(r=~r&1<<(*s>*(s-1))))break;return r;}

My solution is based on bitwise & with inverted previous and current direction code, where direction code can be 2 (1<<1) for character code increase (*s > *(s-1)) or 1 (1<<0) otherwise. Result of this operation became 0 if we use the same direction code as previous and current, i.e. when word is not Bumpy.

UPDATE:

Code for testing:

#include <stdio.h>
#include <string.h>

r;f(char*s){for(;*++s&&(r=~r&1<<(*s>*(s-1))););return r;}

int main(void)
{
    char * Truthy[] = { "ABA", 
                        "ABB", 
                        "BAB",
                        "BUMP",
                        "BALD",
                        "BALDY",
                        "UPWARD",
                        "EXAMINATION",
                        "AZBYCXDWEVFUGTHSIRJQKPLOMN" };
    char * Falsey[] = { "AAA",
                        "BBA",
                        "ACE",
                        "THE",
                        "BUMPY",
                        "BALDING",
                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    int posTestNum = sizeof(Truthy) / sizeof(char *);
    int negTestNum = sizeof(Falsey) / sizeof(char *);
    int i;
    int rate = 0;
    int tests = 0;
    int res = 0;
    printf("Truthy (%d tests):\n", posTestNum);
    for (i = 0; i < posTestNum; i++)
    {
        tests++;
        printf("%s - %s\n", Truthy[i], f(Truthy[i]) ? (rate++, "OK") : "Fail");
        r = 0;
    }
    printf("\nFalsey (%d tests):\n", negTestNum);
    for (i = 0; i < negTestNum; i++)
    {
        tests++;
        printf("%s - %s\n", Falsey[i], f(Falsey[i]) ? "Fail" : (rate++, "OK"));
        r = 0;
    }
    printf("\n%d of %d tests passed\n", rate, tests);
    return 0;
}

VolAnd

Posted 2016-09-12T13:57:49.383

Reputation: 296

Per meta consensus, functions have to be reusable. That means you cannot reset r to 0 for free, but must do so from within the function.

– Dennis – 2016-09-15T20:00:35.617

@Dennis You're right, initialization is required, but only for repeated calls. Let's assume that for a single call that works with any data because compiler provide initialisation for global variables – VolAnd – 2016-09-16T04:28:23.970

I think you should make the 60 byte solution your main one, since the 57 byte version isn't valid by that meta post I cited. – Dennis – 2016-09-16T04:49:03.823

@Dennis Done! +3 bytes – VolAnd – 2016-09-16T07:47:38.960

1

PHP, 100 bytes

for($s=$argv[1];$i<strlen($s)-1;$i++)$s[$i]=$s[$i+1]>$s[$i]?r:f;echo str_replace([rr,ff],'',$s)==$s;

Replaces every char of the string (except the last one obviously) with an r for rise or an f for fall and then checks whether rr or ff occur in the string. To avoid that the last remaining character interfers with that, input must be all uppercase.

I'm very unsatisfied with the loop, for example I have a feeling that there must be a way to combine the $i++ into one of the several $is used in the loop, but I failed to find that way. Maybe someone else sees it.

(That's also why I posted my code, despite it being 20 (!) bytes longer than Titus' nice solution.)

Christallkeks

Posted 2016-09-12T13:57:49.383

Reputation: 377

0

Java 8, 114 90 bytes

(c,b)->{b=c[0]<c[1];for(int i=2;i<c.length;i++)if(c[i]>c[i-1]!=(b=!b))return 0;return 1;};

Ungolfed test program

public static void main(String[] args) {
    BiFunction<char[], Boolean, Integer> func = (c, b) -> {
        b = c[0] < c[1];
        for (int i = 2; i < c.length; i++) {
            if (c[i] > c[i - 1] != (b = !b)) {
                return 0;
            }
        }
        return 1;
    };

    System.out.println(func.apply("ABCDEFG".toCharArray(), false));
    System.out.println(func.apply("AZBYCXDGEF".toCharArray(), false));
    System.out.println(func.apply("ZXZXZX".toCharArray(), false));
    System.out.println(func.apply("ZXCYZ".toCharArray(), false));
    System.out.println(func.apply("AAA".toCharArray(), false));
}

Shaun Wild

Posted 2016-09-12T13:57:49.383

Reputation: 2 329