Find the Wavy Words!

18

(Note: this is an easier spin-off of my previous challenge Find the Infinity Words!, which is a spin-off of my other previous challenge Find the Swirling Words! :) )

Definition of a Wavy Word:

  1. If you connect with curves all the characters of a Wavy Word on the alphabet (A-Z) you obtain the path of a wave continuously going toward right or toward left and never changing direction, like in the diagrams below.
  2. A Wavy Word can be:
    • Raising if each consecutive character is at the right (on the alphabet) of the previous one.
    • Decreasing if each consecutive character is at the left (on the alphabet) of the previous one.
  3. All the even connection must be down, all the odd connections must be up.
  4. You can ignore upper/lowercase or consider/convert all to upper case or all to lower case.
  5. The input words are only characters in the alphabet range of A-Z, no spaces, no punctuation, or symbols.
  6. If a word has double characters, like "SPOON", you must collapse the doubles to one character: "SPOON" > "SPON" (because if you go from O to O is zero distance).
  7. The Wavy Words will contain at least 3 distinct characters (even after doubles collapsing).

Here there are some examples:

enter image description here

Task:

Write a full program or function that will take a word from standard input and will output if it is a Wavy Word or not, and in positive case, output if it is raising or decreasing. The output can be True/False/Null, 2/1/0, 1/Null/0, -1/0/1, NO/WR/WD, etc, you decide how to represent it.

Test cases:

WAVY WORDS:
  ADEPT, BEGIN, BILL, BOSS, BOOST, CHIMP,
  KNOW, SPONGE, SPOON, TROLL, WOLF  

ADEPT  > YES > RAISING
BEGIN  > YES > RAISING
BILL   > YES > RAISING
BOSS   > YES > RAISING
BOOST  > YES > RAISING
CHIMP  > YES > RAISING
KNOW   > YES > RAISING
SPONGE > YES > DECREASING
SPOON  > YES > DECREASING
TROLL  > YES > DECREASING
WOLF   > YES > DECREASING

NOT WAVY WORDS:
  WATCH, EARTH, NINON, FOO, BAR, WAVE, SELECTION,
  YES, NO, DEFINITION, WATER, WINE, CODE, AAAHHHH, I, MM, ABCA

Rules:

  • Shortest code wins.

Optional Task:

Find, as a list, as many Wavy Words as you can in an English dictionary, and the longest as well. You can take for example as reference the complete list of English words here.

Mario

Posted 2016-10-28T16:53:23.697

Reputation: 3 043

How did you make the pictures? – Oliver Ni – 2016-10-28T16:57:51.477

@Oliver With Illustrator because I have it for work, but is possible to obtain similar results with Gimp or Inkskape, or others. – Mario – 2016-10-28T17:01:00.187

NO and FOO aren't valid inputs by your rules. – PurkkaKoodari – 2016-10-28T17:27:09.563

@Pietu1998 Yes because of the Definition #7 – Mario – 2016-10-28T17:29:13.497

They're in the test cases though – PurkkaKoodari – 2016-10-28T17:30:17.380

1@Pietu1998 They're in the NOT WAVY WORDS section though, which is correct.. – Kade – 2016-10-28T17:32:07.643

@Shebang The spec says The input words will contain at least 3 distinct characters, not Wavy words will contain (...) – PurkkaKoodari – 2016-10-28T17:32:58.333

@Pietu1998 OK thanks for pointing that out, I clarified the Definition #7 – Mario – 2016-10-28T17:35:33.500

Can you add a test case like ABCA which would wrongly pass the test if someone just removed duplicates instead of collapsing runs? (Sorry, I'm too lazy to come up with an actual word with that property right now.) – Martin Ender – 2016-10-28T19:32:49.087

Do we have to validate whether rule 5 is satisfied for a word to be wavy? "The input words are only characters in the alphabet range of A-Z, no spaces, no punctuation, or symbols." I thought this was a promise on all inputs, but it's listed under "Definition of a Wavy Word". And, rule 7 requires three distinct letters, and there's non-wavy test cases of that. – xnor – 2016-10-28T19:33:23.123

Must there be a single output for each of the three cases? – xnor – 2016-10-28T19:58:04.293

@MartinEnder I added "ABCA" to the test cases since the code was edited by others adding more nonense words :) – Mario – 2016-10-28T21:03:45.833

1@xnor #5 you can assume all the input words are as described, no need to validate. #7 this is the minimum number of letters to make a wave shape. For the rest you decide the output as you prefer. – Mario – 2016-10-28T21:13:15.847

I believe rule 6 is a bad. Instead the line should bounce. – rom016 – 2016-10-29T10:11:27.367

Can we expect that there are no words that consist of one character repeated? I.e.: Is AA or AAA possible input or not? – Titus – 2016-10-30T08:04:39.590

@Titus the input should be only real English words that you can find in a dictionary so I don't think that such cases exists (even though my question was edited adding nonsense words). – Mario – 2016-10-30T08:25:39.440

aa and aaa are in the list. No idea what they mean; but the answer to my question is No. – Titus – 2016-10-30T08:40:47.780

@Titus aa is a type of lava found in Hawaii, I think. Not sure about aaa. – FlipTack – 2017-01-31T19:47:14.100

Answers

6

05AB1E, 11 9 bytes (Thanks to Adnan)

Dg2›iÇü‹Ù

Try it online!

Wavy Cases:

0 - Decreasing Wavy

1 - Increasing Wavy

Not Wavy Cases:

[0,1] - Not wavy, initially decreasing, but then has an increase/equality that broke the pattern.

[1,0] - Not wavy, initially increasing, but then has a decrease/equality that broke the pattern

Input String - Not possible to be wavy in the first place due to length.

Explanation:

Dg2›iÇü‹Ù   # Full program

D           # Push 2 copies of input.
 g2›i       # If length is greater than 2. 
     Ç      # Push ASCII values for all characters in the string.
      ü     # Push pairwise array.
       ‹    # Vectorize 1 if negative difference, 0 if positive difference.
        Ù   # Uniquify using right most unique values first.
            # Else just print the string back, letting them know it's not valid input.

Magic Octopus Urn

Posted 2016-10-28T16:53:23.697

Reputation: 19 422

1@JonathanAllan Dangit... I just saw the comments and changes... I took The input words will contain at least 3 distinct characters to mean that I didn't have to handle less than 3 char words. Working on changes, may take awhile; this is my first answer I was able to do in 05AB1E. – Magic Octopus Urn – 2016-10-28T19:12:01.663

1@JonathanAllan Fixed :)! But now you're beating me ;). – Magic Octopus Urn – 2016-10-28T19:30:49.803

1Very nice! One tip, ü‹ is the same as ü-0‹ :) – Adnan – 2016-10-29T14:11:19.750

Hehehe... Man, I may just have to learn python and start helping to expand 05AB1E. This language is impressive. Thanks for the tip! – Magic Octopus Urn – 2016-10-30T03:40:51.977

5

Jelly, 10 bytes

OIṠḟ0µL’aQ

TryItOnline! or run all test cases

Returns:
[1] for wavy increasing
[-1] for wavy decreasing
something else otherwise ([], [0], [-1,1], or [1,-1])

(Declared as unnecessary: For a single value for each OIṠḟ0µL’aQS (11 bytes) will return 1, -1, and 0 respectively.)

How?

OIṠḟ0µL’aQ - Main link: s
O          - cast to ordinals
 I         - incremental differences
  Ṡ        - sign (-1 for decreasing, 0 for no change, 1 for increasing)
   ḟ0      - filter out zeros
     µ     - monadic chain separation
      L    - length
       ’   - decremented
        a  - and
         Q - unique items

Jonathan Allan

Posted 2016-10-28T16:53:23.697

Reputation: 67 804

Are you allowed to have 3 different possible outputs for the neither case? – xnor – 2016-10-28T19:36:38.720

I took "you decide how to represent it" to mean yes, so long as they are different. However your question about rule #5 could invalidate this (and probably every other entry). – Jonathan Allan – 2016-10-28T19:55:55.947

Added an solution to that if need be. – Jonathan Allan – 2016-10-28T20:08:00.940

Can you not just sum the list? – xnor – 2016-10-28T20:13:54.067

Oh, yes, of course >_< thanks. – Jonathan Allan – 2016-10-28T20:15:25.843

3

Python 3, 77 75 bytes

lambda x:(len(set(x))>2)*(list(x)==sorted(x)or(list(x)==sorted(x)[::-1])*2)

Assumes all letters are of the same case.

Returns:

  • 0 if not wavy
  • 1 if forwards wavy
  • 2 if backwards wavy

Removed unnecessary spaces thanks @ETHproductions

C. Smith

Posted 2016-10-28T16:53:23.697

Reputation: 31

2Welcome to PPCG, and nice first answer! However, you also need to make sure that there are at least three distinct chars in the string; if not, it's not a wavy word no matter what. – ETHproductions – 2016-10-28T19:22:14.220

Ah, right. Should've looked closer at the definition of a wavy word. Fixed. – C. Smith – 2016-10-28T20:16:57.200

Nice! I'm not a Python expert, but I think you can remove the space on either side of the or. – ETHproductions – 2016-10-28T20:36:40.050

Yep, you're right. Forgot to remove them after surrounding the expressions with parentheses. Thanks for the catch! – C. Smith – 2016-10-28T21:38:59.510

3

Python 2, 54 bytes

lambda s:[2<len(set(s))<s[::b]==sorted(s)for b in-1,1]

Takes input as a list of characters. Outputs:

[False, True] for ascending
[True, False] for descending
[False, False] for neither

Checks if the sorted input string equals its original or reverse. Does so by slicing with step sizes of 1 and -1. At the same time, we check whether the word has at least 2 distinct letters.

If "exit with error" can be used an output for the neither case, we can go down to 51 bytes:

lambda s:[s,s[::-(len(set(s))>2)]].index(sorted(s))

xnor

Posted 2016-10-28T16:53:23.697

Reputation: 115 687

Pretty sure you can take a list of characters since it isn't specified as a string: http://meta.codegolf.stackexchange.com/a/2216/8478

– Jonathan Allan – 2016-10-28T20:51:58.053

3

JavaScript (ES6), 84 81 bytes

s=>(new Set(t=[...s]).size>2)*(!t.some((c,i)=>c>s[i+1])-!t.some((c,i)=>c<s[i+1]))

Assumes the input is all in the same case. Returns 1 for raising wavy, -1 for decreasing wavy, 0 or -0 (both are falsy) for not wavy. Edit: Saved 3 bytes thanks to @RobertHickman.

Neil

Posted 2016-10-28T16:53:23.697

Reputation: 95 035

I'm not an expert on the newer features, but can you remove new? – Cyoce – 2016-10-29T17:28:49.243

@Cyoce Annoyingly the newer features require you to use new. – Neil – 2016-10-29T18:05:55.057

@Neil, I believe, You can save a byte by initializing another variable inside of the Set() function t=[...s] and using t instead of [...s] in those two spots you have it. – Robert Hickman – 2016-11-01T19:36:37.890

3

R, 96 95 bytes

function(x,d=diff(rle(utf8ToInt(x))$v))if(any(d>0)&any(d<0)|sum(1|d)<2)3 else`if`(all(d<1),2,1)

Returns:

  • 1 for wavy and raising
  • 2 for wavy and decreasing
  • 3 for non-wavy

Explained

  • d=diff(rle(utf8ToInt(x))$v): Generates a variable d by first converting the string into it's ASCII values using utf8ToInt which conveniently returns a vector. Subsequently perform run length encoding using rle. rle(...)$v returns the non-repeating values of the sequence (i.e. collapsing all runs). Finally take the difference.
  • if(any(d>0)&any(d<0)|sum(1|d)<2)3: If at least one of the differences are positive and at least one negative, or if the difference sequence has less than 2 elements (equivalent to the original word having less than 3 characters), the word is non-wavy and return 3
  • else``if``(all(d<1),2,1): Else if all differences are negative, return 2 for wavy and decreasing, else return 1 for wavy and raising.

Try all the test cases at R-fiddle (note that it's named such that it can be vectorized for the test cases).

Billywob

Posted 2016-10-28T16:53:23.697

Reputation: 3 363

3

Javascript (ES6), 84 80 78 bytes

i=>new Set(s=[...i]).size>2?[i,s.reverse().join``].indexOf(s.sort().join``):-1

Where wavy increasing is 0, decreasing is 1, and -1 is not wavy.

Thanks to @Neil for helping me save 2 bytes.

Robert Hickman

Posted 2016-10-28T16:53:23.697

Reputation: 661

1new Set(s=[...i]) saves you 2 bytes. (It works by iterating i, turning it into an array, iterating the array, and turning that into a set. Convoluted but you don't worry about that sort of thing when you're golfing.) – Neil – 2016-11-01T22:05:37.840

2

Pyth, 12 bytes

x*<2lrQ8_BQS

Try it online. Test suite.

PurkkaKoodari

Posted 2016-10-28T16:53:23.697

Reputation: 16 699

2

PHP, 96 Bytes

for(;($t=$argv[1])[++$i];)$s+=$r[]=$t[$i-1]<=>$t[$i];echo(max($r)-min($r)<2)*(0<=>$s)*(1<$s*$s);

or 98 Bytes

$s=str_split($t=$argv[1]);sort($s);echo(-($t==strrev($j=join($s)))|$t==$j)*!!count_chars($t,3)[2];

0 not wavy 1 raising -1 decreasing

Jörg Hülsermann

Posted 2016-10-28T16:53:23.697

Reputation: 13 026

- instead of 2* (-1 for decreasing: -1 byte). *(!!...) needs no parentheses. (-2) – Titus – 2016-10-29T14:37:16.910

$s*$s>1 instead of abs($s)>1 (-2) – Titus – 2016-10-30T08:34:27.053

@Titus Done Thank You – Jörg Hülsermann – 2016-10-30T09:27:37.937

2

Python 2, 53 52 50 bytes

Expects input enclosed in quotes, e.g. "watch"

As unnamed lambda:

lambda s:(sum(map(cmp,s[1:],s))+1)/min(len(s)-1,3)

Sums the sign of difference between each letters and integer-divides by len-1. If all were 1 (increasing) the sum is len-1 it displays 1, similar for decreasing -1 and for mixed 1,-1 the sum is smaller than len-1 so it displays 0.

-1 byte for changing cmp,s[1:],s[:-1]) to cmp,s[1:],s)+1

Karl Napf

Posted 2016-10-28T16:53:23.697

Reputation: 4 131

Will return 1 for "NO" – Jonathan Allan – 2016-10-28T20:57:00.267

@JonathanAllan LMNOP so O is after N which means increasing which means 1 – Karl Napf – 2016-10-28T21:05:03.947

Yep, but any word of less than 3 characters (after removing any duplicate letters) was defined as not wavy ("NO" is in the not wavy test cases). – Jonathan Allan – 2016-10-28T21:06:30.143

@JonathanAllan fixed the len issue, but i the repeating chars are still a problem – Karl Napf – 2016-10-28T22:10:59.143

2

Ruby, 54 bytes

->w{c=w.chars.uniq;c==(s=c.sort)?2:(c==s.reverse)?1:0}

Returns 0 if the word is not wavy, 1 if backwards wavy, and 2 if forwards wavy.

Lee W

Posted 2016-10-28T16:53:23.697

Reputation: 521

2

PHP, 100 bytes

$n=$m=$l=str_split($argv[1]);sort($n);rsort($m);echo(($n==$l)-($m==$l))*(count(array_unique($l))>2);

Returns:

  • -1 for wavy, decreasing.
  • 0 for not wavy.
  • 1 for wavy, raising.

chocochaos

Posted 2016-10-28T16:53:23.697

Reputation: 547

!!array_unique($s)[2] instead of count(array_unique($l))>2 – Jörg Hülsermann – 2016-10-29T13:14:44.770

Actually, the problem with that is that array_unique will preverse keys. Thus an input like aaabc will falsely output 0 when using array_unique. – chocochaos – 2016-10-30T11:36:45.000

2

Groovy - 56 bytes

{d=it[0];c=[0]*3;it.each{a->c[(a<=>d)]=1;d=a};c[1..-1]}

Outputs [1,0] for raising wavy, [0,1] for decreasing wavy, [0,0] for single character input or [1,1] for non-wavy.

NOTE: Assumes input is either a String or a char[] and all letters are of the same case.

GolfIsAGoodWalkSpoilt

Posted 2016-10-28T16:53:23.697

Reputation: 101

1

C, 164 bytes

main(){char s[99];scanf("%s",s);char *c=&s;int p=*c;while(*c^0){if(p>*c){if(c-&s[0]>1)return 0;while(*c^0){if(p<*c)return 0;p=*c;c++;}return 2;}p=*c;c++;}return 1;}

Returns 0 if not wawy, 1 if wawy and raising, 2 if decreasing.

Steadybox

Posted 2016-10-28T16:53:23.697

Reputation: 15 798

1

Racket 321 bytes

(let*((ld(λ(sl)(for/list((i(sub1(length sl))))(-(list-ref sl(add1 i))(list-ref sl i)))))(l(ld(remove-duplicates(map
(λ(x)(char->integer x))(string->list s)))))(am andmap)(N"Not WAVY")(d displayln))(cond[(<(length l)2)(d N)][(am(λ(x)(>= x 0))l)
(d"YES; RAISING")][(am(λ(x)(<= x 0))l)(d"YES; DECREASING")][else(d N)])))

Ungolfed:

(define (f s)
  (let*  ((ld (lambda(sl)          ; sub-fn to get differences in list elements
                (for/list ((i (sub1(length sl))))
                  (- (list-ref sl (add1 i))
                     (list-ref sl i) ) )))
          (l (ld
              (remove-duplicates
               (map
                (lambda(x)
                  (char->integer x))
                (string->list s)))))
          (am andmap)
          (N "Not WAVY")
          (d displayln))
    (cond
      [(< (length l) 2)(d N)]
      [(am (lambda(x) (>= x 0)) l) (d "YES; RAISING")]
      [(am (lambda(x) (<= x 0)) l) (d "YES; DECREASING")]
      [else (d N)]
      )))

Testing:

(f "ADEPT"); > YES > RAISING
(f "BEGIN"); > YES > RAISING
(f "BILL"); > YES > RAISING
(f "BOSS"); > YES > RAISING
(f "BOOST"); > YES > RAISING
(f "CHIMP"); > YES > RAISING
(f "KNOW"); > YES > RAISING
(f "SPONGE"); > YES > DECREASING
(f "SPOON"); > YES > DECREASING
(f "TROLL"); > YES > DECREASING
(f "WOLF"); > YES > DECREASING

(f "WATCH")
(f "EARTH")
(f "NINON")
(f "FOO")
(f "BAR")
(f "WAVE")
(f "SELECTION")

Output:

YES; RAISING
YES; RAISING
YES; RAISING
YES; RAISING
YES; RAISING
YES; RAISING
YES; RAISING
YES; DECREASING
YES; DECREASING
YES; DECREASING
YES; DECREASING
Not WAVY
Not WAVY
Not WAVY
Not WAVY
Not WAVY
Not WAVY
Not WAVY

rnso

Posted 2016-10-28T16:53:23.697

Reputation: 1 635

1

Java 7, 254 240 bytes

import java.util.*;int c(String s){char[]a=s.toCharArray(),x=a.clone();Arrays.sort(x);return s.replaceAll("(.)\\1{1,}","$1").length()<3?0:Arrays.equals(a,x)|Arrays.equals(x,(new StringBuffer(s).reverse()+"").toCharArray())?a[0]>a[1]?1:2:0;}

Outputs 0 if the input string isn't wavy, 1 if it's a raising wave, and 2 if it's a decreasing wave.

Ungolfed & test code:

Try it here.

import java.util.*;
class M{
  static int c(String s){
    char[] a = s.toCharArray(),
           x = a.clone();
    Arrays.sort(x);
    return s.replaceAll("(.)\\1{1,}", "$1").length() < 3
            ? 0
            : Arrays.equals(a, x) | Arrays.equals(x, (new StringBuffer(s).reverse()+"").toCharArray())
               ? a[0] > a[1]
                  ? 1
                  : 2
               : 0;
  }

  public static void main(String[] a){
    System.out.print(c("ADEPT") + ", ");
    System.out.print(c("BEGIN") + ", ");
    System.out.print(c("BILL") + ", ");
    System.out.print(c("BOSS") + ", ");
    System.out.print(c("BOOST") + ", ");
    System.out.print(c("CHIMP") + ", ");
    System.out.println(c("KNOW"));

    System.out.print(c("SPONGE") + ", ");
    System.out.print(c("SPOON") + ", ");
    System.out.print(c("TROLL") + ", ");
    System.out.println(c("WOLF"));

    System.out.print(c("WATCH") + ", ");
    System.out.print(c("EARTH") + ", ");
    System.out.print(c("NINON") + ", ");
    System.out.print(c("FOO") + ", ");
    System.out.print(c("BAR") + ", ");
    System.out.print(c("WAVE") + ", ");
    System.out.print(c("SELECTION") + ", ");
    System.out.print(c("YES") + ", ");
    System.out.print(c("NO") + ", ");
    System.out.print(c("DEFINITION") + ", ");
    System.out.print(c("WATER") + ", ");
    System.out.print(c("WINE") + ", ");
    System.out.print(c("CODE") + ", ");
    System.out.print(c("AAAHHHH") + ", ");
    System.out.print(c("I") + ", ");
    System.out.print(c("MM") + ", ");
    System.out.println(c("ABCA"));
  }
}

Output:

2, 2, 2, 2, 2, 2, 2
1, 1, 1, 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

Kevin Cruijssen

Posted 2016-10-28T16:53:23.697

Reputation: 67 575

int c(char[]s){int t=s[0],f=s.length,a=1,b=1,i;for(i=1;i<f;){if(s[i]-s[i-1]>=0)++a;if(s[i]-s[i++-1]<1)++b;}return a==f?1:b==f?-1:0;}(132 bytes) – Numberknot – 2016-10-31T12:55:13.297

Output 1 if wavy raising,output -1 if wavy decreasing,0 if not wavy – Numberknot – 2016-10-31T12:56:32.567