Is it an Ordered Word?

26

(inspired by this post over on Puzzling. CAUTION: SPOILERS FOR THAT PUZZLE ARE BELOW.)

The standard telephone keypad correlates letters to numbers as follows:

1 ->
2 -> ABC
3 -> DEF
4 -> GHI
5 -> JKL
6 -> MNO
7 -> PQRS
8 -> TUV
9 -> WXYZ
0 ->

A given input word is defined to be an Ordered Word if, when translated to keypad presses using the above, the resulting number is either non-decreasing or non-increasing. In other words, the resultant number cannot both increase and decrease.

For example, the word CAT translates to 228, which is non-decreasing, and thus an Ordered Word. However, the word DOG is 364, which both increases and decreases, and thus is not an Ordered Word.

The challenge

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

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 consistent truthy/falsey value for whether the input word is Ordered (truthy) or not Ordered (falsey).

Rules

  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so other people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

Here are some Ordered Words (i.e., truthy), and there are more on the linked Puzzling puzzle.

CAT
TAC
AAA
DEMONS
SKID
LKJONMSRQP
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Here are some non-Ordered Words (i.e., falsey)

DOG
GOD
ROSE
COFFEE
JKLMNOGHI

AdmBorkBork

Posted 2017-07-31T15:34:58.957

Reputation: 41 581

Related and Related I'm not sure this isn't a dupe, the only change between abc->t9 and this challenge is checking monotonicity? – nmjcman101 – 2017-07-31T15:49:23.247

1@nmjcman101 Yes, those are related, but there could be other (better?) ways than strictly abc->t9. – AdmBorkBork – 2017-07-31T15:57:00.427

That makes sense, I do hope to see something beat that method – nmjcman101 – 2017-07-31T15:58:22.380

1Also slightly related. – totallyhuman – 2017-07-31T16:08:44.380

Test case request: AAA – Business Cat – 2017-07-31T16:12:38.980

Do the output values matter, as long as they're consistent? For example, can we output 0 for true and 1 for false? – Shaggy – 2017-07-31T16:59:19.890

@Shaggy As long as those are truthy/falsey in your language of choice. – AdmBorkBork – 2017-07-31T17:52:42.017

Answers

13

Python 2, 164 148 132 77 bytes

-16 bytes thanks to Rod's suggestion elsewhere. A frickin' -55 bytes thanks to Arnold Palmer.

n=[min(int((ord(i)-58)/3.13),9)for i in input()]
print sorted(n)in[n,n[::-1]]

Try it online!

Input must be uppercase. Outputs True or False based on its orderedness.


Explanation

The first line maps each letter to a number.

                               for i in input()   # iterate over the input string
            ord(i)                                # take the ASCII ordinal
                  -58                             # subtract 58
           (         )/3.13                       # divide by 3.13
       int(                )                      # chop off the fractional part
   min(                     ,9)                   # choose the minimum between the number and 9
n=[                                            ]  # assign the resulting list to n

This works based on:

          | A   B   C  | D   E   F  | G   H   I  | J   K   L  | M   N   O  | P   Q   R   S  | T   U   V  | W   X   Y   Z
----------+------------+------------+------------+------------+------------+----------------+------------+-----------------
ord(x)    | 65  66  67 | 68  69  70 | 71  72  73 | 74  75  76 | 77  78  79 | 80  81  82  83 | 84  85  86 | 87  88  89  90
----------+------------+------------+------------+------------+------------+----------------+------------+-----------------
x - 58    | 7   8   9  | 10  11  12 | 13  14  15 | 16  17  18 | 19  20  21 | 22  23  24  25 | 26  27  28 | 29  30  31  32
----------+------------+------------+------------+------------+------------+----------------+------------+-----------------
x ÷ 3.13* | 2.2 2.6 2.9| 3.2 3.5 3.8| 4.2 4.5 4.8| 5.1 5.4 5.8| 6.1 6.4 6.7| 7.0 7.3 7.7 7.9| 8.3 8.6 8.9| 9.3 9.6 9.9 10.2
----------+------------+------------+------------+------------+------------+----------------+------------+-----------------
int(x)    | 2   2   2  | 3   3   3  | 4   4   4  | 5   5   5  | 6   6   6  | 7   7   7   7  | 8   8   8  | 9   9   9   10
----------+------------+------------+------------+------------+------------+----------------+------------+-----------------
min(x, 9) | 2   2   2  | 3   3   3  | 4   4   4  | 5   5   5  | 6   6   6  | 7   7   7   7  | 8   8   8  | 9   9   9   9

*Values are rounded. :P

The second line outputs if the list of numbers is in ascending or descending order.

print                                             # print whether...
      sorted(n)                                   # n sorted...
               in[n,n[::-1]]                      # is equivalent to n or n reversed

totallyhuman

Posted 2017-07-31T15:34:58.957

Reputation: 15 378

484 bytes – Arnold Palmer – 2017-07-31T16:44:01.990

1Holy cow, that's awesome. Thanks! – totallyhuman – 2017-07-31T16:45:35.730

I was going to post it as an answer cause I wrote it before everyone flooded in with answers, but you sniped me :) – Arnold Palmer – 2017-07-31T16:47:37.953

8

JavaScript (ES6),  83 ... 71  70 bytes

Returns a boolean.

x=>[...x].every(c=>v&=~(k=x,x=parseInt(c,35)*.32|0||10,x<k?2:x>k),v=3)

Test cases

let f =

x=>[...x].every(c=>v&=~(k=x,x=parseInt(c,35)*.32|0||10,x<k?2:x>k),v=3)

test = a => a.forEach(s => console.log(f(s) + " for '" + s + "'"))

console.log('[Truthy]')
test(["AAA", "CAT", "TAC", "DEMONS", "SKID", "LKJONMSRQP", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"])

console.log('[Falsy]')
test(["DOG", "GOD", "ROSE", "COFFEE", "JKLMNOGHI"])


How?

Letter conversion

We use parseInt(c, 35) to convert each letter of the input string to some number in [10 .. 34]. Because it's base-35, "Z" is converted to NaN instead.

The expression * .32 | 0 maps this number into the interval [3 .. 10], leading to 8 correct groups of letters for "A" to "Y". We need || 10 to get the correct value for "Z".

           | A  B  C| D  E  F| G  H  I| J  K  L| M  N  O| P  Q  R  S| T  U  V| W  X  Y   Z
-----------+--------+--------+--------+--------+--------+-----------+--------+------------
parseInt   |10 11 12|13 14 15|16 17 18|19 20 21|22 23 24|25 26 27 28|29 30 31|32 33 34 NaN
-----------+--------+--------+--------+--------+--------+-----------+--------+------------
*.32|0||10 | 3  3  3| 4  4  4| 5  5  5| 6  6  6| 7  7  7| 8  8  8  8| 9  9  9|10 10 10  10

Order test

We keep track of the signs of differences between consecutive numbers into the bitmask v, initially set to 3 (0b11):

  • bit #0: cleared when new_value > previous_value
  • bit #1: cleared when new_value < previous_value

The previous value is stored in the same variable x as the input. This ensures that the first iteration -- where no previous value actually exists -- will not clear any bit, because a string containing only letters is neither greater nor less than any number:

('CAT' > 5) === false
('CAT' < 5) === false

A word is ordered unless both signs are encountered, which leads to v = 0 and makes every() fail.

Arnauld

Posted 2017-07-31T15:34:58.957

Reputation: 111 334

Oh, nice trick to get the number of each letter :) I'm torn as to whether I should borrow it or not, as it would mean I'd tie with you, which doesn't seem right. – Shaggy – 2017-07-31T16:44:42.870

6

Jelly, 28, 27, 25, 23, 22, 21, 19, 18 bytes

_>
O‘ç82ç88:3IṠḟ0E

Try it online!

This was a lot of fun to write!

Explanation:

                # Define a helper link, decrement a if a > b
_               # Subtract
 >              # Boolean greater than
                # Main link:
O               # The ordinals (ASCII points) of the input
 ‘              # Minus one
  ç82           # Decrement if greater than 82
     ç88        # Decrement if greater than 88
        :3      # Divide each number by 3
          I     # Consecutive differences
           Ṡ    # Sign (-1 if < 0, 0 if == 0, and 1 if > 0)
            ḟ0  # Remove all 0's
              E # All elements are equal?

Thanks to @ErikTheOutgolfer, @leakynun and @BusinessCat for all saving bytes. :)

James

Posted 2017-07-31T15:34:58.957

Reputation: 54 537

3

05AB1E, 36 bytes

v.•1нJ©½è`ÇHø¹á₂N¸°…ÈáÀ•#Dʒyå}k}¥0‹Ë

Try it online!

Magic Octopus Urn

Posted 2017-07-31T15:34:58.957

Reputation: 19 422

4You can replace .•1нJ©½è`ÇHø¹á₂N¸°…ÈáÀ•# by A•22ā₂•S£. – Adnan – 2017-07-31T19:22:10.210

3@Adnan rip formatting – Leaky Nun – 2017-07-31T19:22:19.427

3@LeakyNun <s>rip indeed</s> fixed – Adnan – 2017-07-31T19:22:30.927

4@Adnan rip formatting – Leaky Nun – 2017-07-31T19:23:36.163

4@LeakyNun rip indeed – Adnan – 2017-07-31T19:24:08.593

@Adnan you sure? Try it online!

– Magic Octopus Urn – 2017-08-01T13:46:02.963

3

MATL, 26 25 bytes

1Y21K250B-Y{c&m8\dZSu|s2<

Input is in upper-case letters. Output is 1 or 0.

Try it online!

Explanation

1Y2      % Push 'ABC...XYZ'
1        % Push 1
K        % Push 4
250B     % Push 250 in binary, that is, [1 1 1 1 1 0 1 0]
-        % Subtract (from 4, element-wise): gives [3 3 3 3 3 4 1 4]
Y{       % Convert to cell array, splitting into chunks of those lengths
c        % Convert to char matrix. Gives a 4-column matrix. Chunks of length 3
         % are right-padded with a space
&m       % Implicit input. Push (linear) index of membership in char matrix
8\       % Modulo 8. Converts linear index into 0-based row index
d        % Consecutive differences
ZS       % Sign
u        % Unique
|        % Absolute value
s        % Sum
2<       % Less than 2? Implicit display

Luis Mendo

Posted 2017-07-31T15:34:58.957

Reputation: 87 464

Appropriate score for an alphabetic challenge :P – James – 2017-07-31T16:33:53.890

@DJMcMayhem Not anymore :-D – Luis Mendo – 2017-07-31T16:37:46.360

3

Husk, 22 21 19 18 bytes

±S€Ẋ▲`Ṫo±≤"DGJMPTW

Returns 1 for truthy inputs, 0 for falsy ones. Inputs must be in uppercase. Passes all test cases. Try it online!

Explanation

±S€Ẋ▲`Ṫo±≤"DGJMPTW  Implicit input x, e.g. "CAT"
     `Ṫo±≤"DGJMPTW  This part transforms x into a "canonical form" corresponding to the numpad digits
     `Ṫ             Table with flipped arguments
       o±≤          on sign of less-than-or-equal
                    (In Husk, ≤ returns extra information we don't want, so we take sign of the result to get 0 or 1.)
          "DGJMPTW  of this string and x.
                    This gives, for each char in x, a bit array of comparisons with the chars in the string:
                    y = [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[1,1,1,1,1,1,0]]
   Ẋ▲               Maxima of adjacent pairs: [[0,0,0,0,0,0,0],[1,1,1,1,1,1,0]]
 S€                 1-based index in y as sublist: 2
±                   Sign: 1

Zgarb

Posted 2017-07-31T15:34:58.957

Reputation: 39 083

3

Python 2, 60 bytes

a=[3681/ord(c)for c in input()]
print sorted(a)in[a,a[::-1]]

Try it online!

Accepts input in lowercase.

How it works

⌊3681/x⌋ decreases from

  • 38 to 37 at x ≈ 96.8684210526, before a;
  • 37 to 36 at x ≈ 99.4864864865, between c and d;
  • 36 to 35 at x ≈ 102.25, between f and g;
  • 35 to 34 at x ≈ 105.171428571, between i and j;
  • 34 to 33 at x ≈ 108.264705882, between l and m;
  • 33 to 32 at x ≈ 111.545454545, between o and p;
  • 32 to 31 at x ≈ 115.03125, between s and t;
  • 31 to 30 at x ≈ 118.741935484, between v and w;
  • 30 to 29 at x ≈ 122.7, after z.

Anders Kaseorg

Posted 2017-07-31T15:34:58.957

Reputation: 29 242

2

C++, 375 199 195 194 bytes

Thanks to Shaggy's JavaScript answer :
-5 bytes thanks to Zacharý

#include<string>
int o(std::string a){std::string m="22233344455566677778889999";for(auto&b:a)b=m[b-65];int j=1,i=0,d=0;for(;j<a.size();++j){if(a[j]>a[j-1])++i;if(a[j]<a[j-1])++d;}return!(i*d);}

HatsuPointerKun

Posted 2017-07-31T15:34:58.957

Reputation: 1 891

Can you move the int j=1,i=0,d=0 to the for loop? – Zacharý – 2017-07-31T22:57:14.560

@Zacharý Since i and d are used outside of the loop block, i can't – HatsuPointerKun – 2017-07-31T23:17:12.887

i==0||d==0 ==> i*d==0. – Zacharý – 2017-07-31T23:20:49.807

Would !(i*d) work? (removing the space after return) – Zacharý – 2017-07-31T23:25:54.610

@Zacharý Yes, it works – HatsuPointerKun – 2017-07-31T23:28:33.830

@Zacharý miscalculations – HatsuPointerKun – 2017-07-31T23:36:45.710

1

05AB1E, 30 bytes

A3 8×Ƶ0+S£¹δåā>‚øε`*}.«+¥0K0‹Ë

Try it online!

-1 thanks to Magic Octopus Urn.

Erik the Outgolfer

Posted 2017-07-31T15:34:58.957

Reputation: 38 134

Did you use ¥0K0.SË because ¥0‹Ë isn't correct? I can't tell if the 0.S is needed. – Magic Octopus Urn – 2017-07-31T15:52:46.520

@MagicOctopusUrn In fact ¥0K0‹Ë seems to work. – Erik the Outgolfer – 2017-07-31T15:54:03.967

Yeah, if you're removing the 0's it should; in my answer I'm not sure it works. – Magic Octopus Urn – 2017-07-31T15:55:07.447

@MagicOctopusUrn I'm removing the 0s since otherwise there will be false negatives. Your answer might behave differently though. – Erik the Outgolfer – 2017-07-31T15:55:46.707

1

JavaScript (ES6), 107 97 95 92 88 85 bytes

Works with mixed-case strings. Returns 1 for truthy or 0 for falsey.

s=>(s=(a=[...s].map(c=>(parseInt(c,36)-3)/3.13%10|0||9))+"")==a.sort()|s==a.reverse()
  • 10 bytes saved thanks to Rod.

Try It

o.innerText=(f=
s=>(s=(a=[...s].map(c=>(parseInt(c,36)-3)/3.13%10|0||9))+"")==a.sort()|s==a.reverse()
)(i.value="Cat")
oninput=_=>o.innerText=f(i.value)
<input id=i><pre id=o>

Shaggy

Posted 2017-07-31T15:34:58.957

Reputation: 24 623

1Math.min((parseInt(c,36)-3)/3.13|0,9) instead "2..9"[parseInt(c,36)-10] to save some bytes – Rod – 2017-07-31T16:26:59.410

Thanks, @Rod; very nice. I'll have to file that away for future use. – Shaggy – 2017-07-31T16:28:43.943

86 bytes. – None – 2017-07-31T18:38:12.560

Thanks, @ThePirateBay, but,sadly, that fails for input AAA. – Shaggy – 2017-08-01T08:05:15.180

1

Gaia, 29 27 25 17 bytes

ċ⟨):“QX’>¦Σ⁻3/⟩¦o

Try it online!

Explanation

ċ                  Turn the input into a list of code points
 ⟨            ⟩¦   Map this block to each code point:
  )                 Increment it
   :                Copy it
    “QX’            Push [81 88]
        >¦          Check if the code point is greater than each of [81 88]
          Σ         Sum the results
           ⁻        Subtract from the code point
            3/      Integer divide the result by 3
                o  Check if the resulting list is in sorted order (increasing or decreasing)

Business Cat

Posted 2017-07-31T15:34:58.957

Reputation: 8 927

1

05AB1E, 21 17 bytes

Code

A•22ā₂•Sās×J‡Ô¥dË

Uses the 05AB1E encoding.

Try it online! or Verify all test cases!

Explanation

A                   # Push the lowercase alphabet
 •22ā₂•             # Push the number 33333434
       S            # Split into an array
        ā           # Get the range of indices [1 .. length]
         s×         # Swap and string multiply
           J        # Join that array
            ‡       # Transliterate

This now essentially maps the following letters to the following numbers:

abcdefghijklmnopqrstuvwxyz
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
11122233344455566667778888

             Ô      # Remove consecutive duplicates
              ¥     # Compute the delta's of the list
               d    # Check if the number is greater or equal to 0
                Ë   # Check if all elements are the same

Adnan

Posted 2017-07-31T15:34:58.957

Reputation: 41 965

1

Pyth, 23 bytes

One of my first non-trivial Pyth answer! Saved 6 bytes thanks to @LeakyNun. The initial solution is below.

/{_BKmhS,9/a58Cd3.13zSK

Test Suite.

Pyth, 29 bytes

KmhS+9]/-Cd58 3.13w|qKSKqK_SK

Test Suite.


Explanation

/{_BKmhS,9/a58Cd3.13zSKQ - The Q means evaluated input and is implicit at the end

 {                      - Deduplicate
  _                     - Reverse
   B                    - Bifurcate, Create a two-element list, [B, A(B)]
    K                   - Variable with auto-assignement to:
     m              z    - Map over the input:
      hS                  - Minimum (first element of sorted list)
        ,                 - Create a two-element list, [A, B] with these elements:
         9                  - The numeric literal 9
          /                 - The integer division of:
           a58Cd              - The absolute difference between 58 and ord(current_element)   
                3.13          - The numeric literal 3.13
                    SK   - K sorted
/                     Q  - Count the occurrences of the input in [K, K[::-1]]                

Mr. Xcoder

Posted 2017-07-31T15:34:58.957

Reputation: 39 774

123 bytes – Leaky Nun – 2017-07-31T19:43:27.453

1

Retina, 65 bytes

T`_ADGJMPTW`d
}T`L`_L
(.)\1*
$1$*1<
(1+)<(?!\1)
$1>
1

^(<*|>*)>$

Try it online! Link includes test cases. Explanation:

T`_ADGJMPTW`d

Change the first letter on each key to a digit. (This is off by 1 but that doesn't matter for an ascending/descending check. On the other hand, zeros would make my life more difficult, so I left one filler character in.)

}T`L`_L

Shuffle all the remaining letters up 1 and repeat until they've all been converted to digits.

(.)\1*
$1$*1<

Convert the digits into unary, but only once per run of identical digits. The unary values are seprated with a <...

(1+)<(?!\1)
$1>

... but if the LHS turns out to be greater than the RHS, correct the < to >.

1

Delete the 1s which are no longer necessary.

^(<*|>*)>$

Check that the word is ordered. (The trailing > comes from the last digit which always compares greater than the empty space following it.)

Neil

Posted 2017-07-31T15:34:58.957

Reputation: 95 035

That's pretty cool. Thanks for the thorough explanation. – AdmBorkBork – 2017-07-31T20:06:51.370

1

05AB1E, 13 bytes

ÇÍžq÷8
7:Ô¥dË

Whenever I see a numpad question, I have to make a pi-based answer.

Try it online or verify all test cases

Ç                    # ASCII code of each letter in the input
 Í                   # add 2
  žq÷                # divide by pi
     8 7:            # replace 8 with 7
         Ô           # remove duplicates
          ¥          # deltas
           d         # each >= 0 ?
            Ë        # are all elements equal?

Grimmy

Posted 2017-07-31T15:34:58.957

Reputation: 12 521

0

Jelly, 32 bytes

“¢Ç⁺H’D0ẋj1œṗØA⁸=€×"€9Ḋ¤Fḟ0Iḟ0ṠE

Try it online!

Erik the Outgolfer

Posted 2017-07-31T15:34:58.957

Reputation: 38 134

RIP compression – Leaky Nun – 2017-07-31T19:22:37.040

@LeakyNun The compressed number is actually 32222323 so it saves just 2 bytes. – Erik the Outgolfer – 2017-07-31T19:26:18.607

0

Python 3, 143 147 148 149 130 bytes

def g(s,f=lambda c:min(int((ord(c)-58)/3.13),9)):x=[f(a)-f(b)for a,b in zip(s,s[1:])];return any(t<0for t in x)*any(t>0for t in x)

Best I can do for now. Crude function turns the letter into the number based off of ascii code. There are definitely some improvements to be made. 0 is truthy, 1 is falsey (sorry). Saved 10 bytes thanks to Rod, another 3 thanks to Mr. Xcoder.

Try it online!

C McAvoy

Posted 2017-07-31T15:34:58.957

Reputation: 229

you can use x=[f(a)-f(b)for a,b in zip(s,s[1:])] to save some bytes – Rod – 2017-07-31T16:33:38.420

also, min(int((ord(c)-58)/3.13),9) is a shorter way to convert the char – Rod – 2017-07-31T16:34:44.880

140 bytes – Mr. Xcoder – 2017-07-31T16:38:37.327

@Rod Thanks! Very helpful. – C McAvoy – 2017-07-31T16:38:45.107

You'll need to swap your outputs around in order for this to be valid. – Shaggy – 2017-07-31T22:24:54.417

0

Python 2, 111 103 bytes

-8 bytes thanks to @Arnold Palmer:no lower() needed

  • Takes uppercase letters as input.
lambda x:sorted(f(x))in[f(x),f(x)[::-1]]
f=lambda x:['22233344455566677778889999'[ord(i)-65]for i in x]

Try it online!

officialaimm

Posted 2017-07-31T15:34:58.957

Reputation: 2 739

1You can remove the .lower() since the input can be in whatever case you specify. – Arnold Palmer – 2017-07-31T19:28:56.170

0

C# (.NET Core), 133 bytes

using System.Linq;q=>{var u=q.Select(c=>(int)((c-58)/3.13));var z=u.Zip(u.Skip(1),(a,b)=>a-b);return!(z.Any(d=>d<0)&z.Any(d=>d>0));};

Try it online!

I feel like there's some room to save, but C# is not a concise language so maybe not. Ungolfed:

bool Ordered(string word){

    IEnumerable<int> keys = word.Select(character => (int)((character - 58)/3.13)); 
    // convert characters to keypad number

    IEnumerable<int> differences = keys.Zip(keys.Skip(1), (a, b)=> a-b); 
    // difference between consecutive elements

    return !(differences.Any(diff => diff<0) & differences.Any(diff => diff>0)); 
    // false if both positive and negative differences exist
}

In particular I think there's a shorter way to express the final check for validity, possibly a way to inline it with the Zip. Finding a way to express the Zip without needing temporary storage for the Skip would also save something, but I doubt there's something more concise for that.

Kamil Drakari

Posted 2017-07-31T15:34:58.957

Reputation: 3 461

0

CJam, 37 31 30 27 bytes

q{_"SVZY"#g-i3/}%_$_W%](e=g

Try it Online

Of course the ugly version ends up being shorter...

q{        e# For each character in string...
_"SVZY"#g e# Get index of that character in "SVZY". Signum that. (returns 1 or 0 if inside string, -1 if not.)
-i3/      e# Subtract value from character (i.e 'Z' becomes 'Y', 'F' becomes 'G'). Convert to int. Integer divide by 3. (this is just how the math works out for proper mapping of characters to phone digits.)
}%
_$_W%]    e# Put mapped string, sorted version, and reverse sorted version in array.
(         e# Pop mapped string from array onto stack.
e=        e# Count occurences of mapped string in array.
g         e# Signum.

geokavel

Posted 2017-07-31T15:34:58.957

Reputation: 6 352

0

TI-Basic, 92 66 bytes

ΔList(int(seq(inString("BC DEF GHI JKL MNO PQRSTUV WXYZ",sub(Ans,I,1))/4,I,1,length(Ans
0≤min(Ansmax(Ans

Converts each character in the string to an integer from 0 to 7, and takes the difference between each consecutive element; then checks whether the minimum and maximum differences have the same sign (or either is 0).

Timtech

Posted 2017-07-31T15:34:58.957

Reputation: 12 038

I think ΔList(int(4^-1seq(inString("DEF GHI JKL MNO PQRSTUV WXYZ",sub(Ans,I,1))+3,I,1,length(Ans saves one byte. – lirtosiast – 2017-08-25T00:17:09.523

0

PHP 7, 98+1 95+1 84+1 bytes

a golfed port of Arnauld´s answer.

for(;$c=ord($argn[$i]);$v|=$i++?$p>$k?2:$p<$k:0,$p=$k)$k=($c-58)*.32%10?:9;echo$v<3;

accepts uppercase; empty output for falsy, 1 for truthy.

Run as pipe with -nR or try it online.

original post:

for(;$c=$argn[$i++];$p?$a[]=$p<=>$k:0,$p=$k)$k=(ord($c)-58)/3.13-($c>Y)|0;echo min($a)*max($a)>=0;

Titus

Posted 2017-07-31T15:34:58.957

Reputation: 13 814

0

C (gcc), 183 169 153 117 bytes

#define a(b)(int)fmin(*(b c)/3.2,27)
d(char*c){int r=1,p=1;for(;1<strlen(c);)r&=a()<=a(1+),p&=a()>=a(++);return r|p;}

Try it online!

Old solution:

#define a(b)(int)((int)(b*.32-17.6)*.9)
d(char*c){int l=~-strlen(c),i=0,r=1,p=1;for(;i<l;++i)r&=a(c[i])<=a(c[i+1]),p&=a(c[l-i])<=a(c[l-i-1]);return r+p;}

Saved 8 bytes thanks to ThePirateBay.

Old old solution:

d(char*c){char*a="22233344455566677778889999";int l=strlen(c)-1,i=0,r=1,p=1;for(;i<l;++i){if(a[c[i]-65]>a[c[i+1]-65])r=0;if(a[c[l-i]-65]>a[c[l-i-1]-65])p=0;}return r+p;}

Old old old solution:

d(char*c){char*a="22233344455566677778889999";int l=strlen(c);int i,r=1,p=1;for(;i<l-1;++i)if(a[c[i]-65]>a[c[i+1]-65])r=0;for(i=l-1;i>0;--i)if(a[c[i]-65]>a[c[i-1]-65])p=0;return r+p;}

Matej Mulej

Posted 2017-07-31T15:34:58.957

Reputation: 101

0

Zsh, 73 69 57 bytes

-12 bytes by using @anders-kaseorg's 3681/code conversion.

for c (${(s::)1})((y=3681/#c,A|=y<p,D|=p&&p<y,p=y,!D|!A))

Try it online! Try it online! Try it online!

A few things we abuse:

  • ((statement,statement,...)) is a sequence of arithmetic expressions which returns truthy if the last statement is non-zero.
  • The return value of a loop is the return value of the last statement in a loop.
  • Arithmetic operator precedences were pretty nice to us, as only one pair of no parentheses were used. One byte could be saved if ! bound less tightly than &.
  • Unset parameters expand to 0 in arithmetic expansions.
  • The function we use to map to the keypad number is CODE / 3.2 - 18 (with a special case for Z), but since we only need the change between codes, we don't do the linear adjustment.
for c (${(s::)1})           # split into characters
    (( y = #c-90 ? 0^(#c/3.2) : 27,   # this sets y to the keypad number + 18
       A |= y < p,          # set the A flag if we detect it is not ascending
       D |= p && p < y,     # ditto descending, don't compare on first iteration
       p = y,               # save the current character
       !D | !A              # return false if D and A are both set
    ))

2 bytes can be saved if the truthy/falsey values can be swapped.

GammaFunction

Posted 2017-07-31T15:34:58.957

Reputation: 2 838