15
\$\begingroup\$

I really like times that follow certain patterns. In particular, I like times where all the digits are the same, or all of the digits increase arithmetically by one from left to right. Further, I viscerally hate when people put letters in my times, so all of that AM/PM nonsense is dead to me. Thus, my favorite times are:

0000 0123 1111 1234 2222 2345

For my peace of mind, I need you to write me a single program that, given the current time as input, both: (A) if it is not now one of my favorite times, tells me both (i) how many minutes it's been since my last favorite time as well as (ii) how many minutes from now my next favorite time will occur; and (B) if it is now one of my favorite times, supplies a single 'signal value'.

Input

Your program should accept (by whatever method: function argument, stdin, command line argument, etc.) the current time, in any of the following formats:

  • A four-digit time as a string

  • An integer that can be zero-padded on the left to make a four-digit time as a string

  • A sequence of four (or fewer) integers, ordered such that the first integer in the sequence is the leftmost (significant) digit in the time input (e.g., 0951 could be validly represented as [0, 9, 5, 1] or [9, 5, 1])

    • Representing 0000 as a zero-length sequence is acceptable

In the case of a string input, it should only contain digits, no colons or other punctuation. Inputs can be assumed to always be valid 24-hour times: HHMM, where 0 <= HH <= 23 and 0 <= MM <= 59. Disregard the possibility of a leap second.

Output

Your program must supply (function returns, stdout, etc. are all fine) either (A) or (B), as appropriate to whether or not the input value is a target time.

For (A):

Supply two numeric values in any sensible format, such as:

  • Single-string output with a suitable delimiter

  • Sequential integer/string outputs, e.g., bash printing two lines to stdout:

    49
    34
    
  • Length-two ordered return values, such as a Python list, a C array, etc.: [49, 34]

The values can come in either order. For example, both of the following would be valid outputs for an input of 1200:

49 34
34 49

The order and separator must be the same for all input values, however!

For (B):

Produce any otherwise unattainable result. The same result must be produced for all six of the target times, however. Infinite loops are excluded.

Sample Inputs/Outputs

YAY!!! is used here as a demonstrative example and is not prescriptive.

Input      Output
------    --------
 0000      YAY!!!
 0020      20 63
 0105      65 18
 0122      82 1
 0123      YAY!!!
 0124      1 587
 0852      449 139
 1111      YAY!!!
 1113      2 81
 1200      49 34
 1234      YAY!!!
 1357      83 505
 1759      325 263
 1800      326 262
 1801      327 261
 2222      YAY!!!
 2244      22 61
 2345      YAY!!!
 2351      6 9

This is , so shortest code in bytes wins. Standard loopholes are disallowed.

\$\endgroup\$
  • \$\begingroup\$ Is it OK to return nothing for a favorite time? \$\endgroup\$ – James Holderness Jan 2 '18 at 4:09
  • 1
    \$\begingroup\$ @JamesHolderness Fictional-me gets antsy if I don't get anything at all back from an application (what if the interpreter glitched?!?!), so there has to be some value or output generated. \$\endgroup\$ – hBy2Py Jan 2 '18 at 4:45
2
\$\begingroup\$

Jelly, 34 33 32 31 28 bytes

3 bytes thanks to Mr. Xcoder's .ị and ³ tricks.

d³ḅ60;15j83,588ṁ5¤_\ṠÞAµ.ịxẠ

Try it online!

Some parts are exactly as in Jonathan Allan's answer, but I'm posting it as I think it is sufficiently different from it and independently written based on my Pyth answer (and shorter :D). Should also have room for improvement.

Input is an integer, output is an array of previous and next times or the empty array for special times.

Explanation

Using example input 1200.

  • converts the time to base 100, into hours and minutes: [12,0].
  • ḅ60 converts from base 60 to get total minutes: 720.
  • ;15 pairs it with 15: [720, 15].
  • 83,588 creates the array [83, 588].
  • ṁ5 makes it length 5: [83, 588, 83, 588, 83].
  • ¤ combines the two above actions. Just a technicality.
  • j joins the pair with the array: [720, 83, 588, 83, 588, 83, 15].
  • _\ subtracts each array value from the first and gets intermediate results: [720, 637, 49, -34, -622, -705, -720].
  • ṠÞ stably sorts these by signum: [-34, -622, -705, -720, 720, 637, 49].
  • A takes the absolute values: [34, 622, 705, 720, 720, 637, 49].
  • µ starts a new monadic chain. Again, a technicality.
  • .ị takes the last and first items: [49, 34].
  • ×Ạ repeats that once if there are no zeroes, or zero times otherwise: [49, 34].
\$\endgroup\$
  • \$\begingroup\$ @JamesHolderness Fixed for no size change (changed , to ; since it was being picked up as a list literal). \$\endgroup\$ – PurkkaKoodari Jan 2 '18 at 6:17
  • \$\begingroup\$ Funnily enough, I tried to port your Pyth answer to Jelly and I got 28 bytes. I don't think it is different enough to be a separate answer, so feel free to use it (and the cute test suite :P). (note that using ³ instead of 100 is allowed) The YAY!!! value is [0, 0], always the same. \$\endgroup\$ – Mr. Xcoder Jan 2 '18 at 11:44
  • \$\begingroup\$ Nice, thanks! I think the main improvement is the half-indexing trick, I never thought about that one. \$\endgroup\$ – PurkkaKoodari Jan 2 '18 at 18:08
  • \$\begingroup\$ Are you planning to update with my suggestions? (Just a reminder, I have the feeling that you have forgot to edit?) \$\endgroup\$ – Mr. Xcoder Jan 3 '18 at 17:19
  • \$\begingroup\$ @Mr.Xcoder Yeah, forgot to edit. I'll use xẠ as the zero filter since I kind of prefer [] over [0, 0] because it's more clearly different. \$\endgroup\$ – PurkkaKoodari Jan 4 '18 at 6:37
2
\$\begingroup\$

JavaScript (ES6), 87 83 bytes

Saved 4 bytes thanks to @l4m2

Takes input as a string. Returns either 0 or a 2-element array.

t=>[i=0,83,588,83,588,83,15].every(d=>(k=t-(t/25>>2)*40)>(j=i,i+=d))|i-k&&[k-j,i-k]

Test cases

let f =

t=>[i=0,83,588,83,588,83,15].every(d=>(k=t-(t/25>>2)*40)>(j=i,i+=d))|i-k&&[k-j,i-k]

console.log(f('0000')) // YAY!!!
console.log(f('0020')) // 20 63
console.log(f('0105')) // 65 18
console.log(f('0122')) // 82 1
console.log(f('0123')) // YAY!!!
console.log(f('0124')) // 1 587
console.log(f('0852')) // 449 139
console.log(f('1111')) // YAY!!!
console.log(f('1113')) // 2 81
console.log(f('1200')) // 49 34
console.log(f('1234')) // YAY!!!
console.log(f('1357')) // 83 505
console.log(f('1759')) // 325 263
console.log(f('1800')) // 326 262
console.log(f('1801')) // 327 261
console.log(f('2222')) // YAY!!!
console.log(f('2244')) // 22 61
console.log(f('2345')) // YAY!!!
console.log(f('2351')) // 6 9

How?

We do not care about the result of the .every() loop. Provided that the input is valid, it will always be falsy. What we're really interested in is when we exit this loop.

We exit as soon as we find a favorite time i (expressed in minutes) which is greater than or equal to the reference time k (the input time t converted in minutes). We then return 0 if i == k or the 2 delays otherwise.

\$\endgroup\$
  • 2
    \$\begingroup\$ t%100+(t/25>>2)*60 => t-(t/100|0)*40 \$\endgroup\$ – l4m2 Jan 2 '18 at 4:35
2
\$\begingroup\$

Befunge-93, 88 85 86 80 74 bytes

&:"d"/58**-:"S"-:"b"6*-:"S"v
@._v#!:<\-*53:-"S":-*6"b":-<
:$#<$$\^@.._\#`0

Try it online!

Outputs the number of minutes since the last favourite time, followed by the number of minutes until the next favourite time (separated by the two character sequence: space, hyphen). If it is already a favourite time, then a single zero is returned.

\$\endgroup\$
1
\$\begingroup\$

C, 121 bytes

*p,l[]={0,83,671,754,1342,1425,1440};f(t){t=t%100+t/100*60;for(p=l;t>*p;++p);*p-t?printf("%d %d",t-p[-1],*p-t):puts("");}

Outputs a newline if the time is a favourite time.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Clean, 126 bytes

import StdEnv
f=[1440,1425,1342,754,671,83,0]
?t#t=t rem 100+t/100*60
=(\(a,b)=(t-hd b,last a-t))(span(\a=t<a||isMember t f)f)

Defines the function ?, taking Int and returning (Int, Int).
When the argument is a favourite time, it crashes the calling program with hd of [].

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Pyth, 48 45 42 bytes

&*FJ.u-NY+P*3,83 588 15isMcz2 60,eK._DJ_hK

Try it online. Test suite.

The code takes in a time string and outputs the previous and next times as an array, or 0 if the time is special.

Interestingly, an imperative approach is also 42 bytes:

V+_isMcz2 60+P*3,83 588 15KZIg0=-ZNIZK)_ZB

Explanation

  • cz2 splits input (z) into two-character pieces.
  • sM evaluates them as integers.
  • i60 parses the resulting two-item array as base 60.
  • ,83 588 represents the array [83, 588].
  • *3 triplicates that to [83, 588, 83, 588, 83, 588].
  • P removes the last 588.
  • +15 adds 15 to the end.
  • .u-NY starts from the parsed number, subtracts each number in the array from it and returns the intermediate values. These are the differences from each special time.
  • J assigns these differences to J.
  • *F computes the product of the differences. This will be 0 if the time was special.
  • & stops the evaluation here and returns 0 if the time was special.
  • ._DJ stable-sorts the differences by sign.
  • K saves that array in K.
  • e takes the last item in the array.
  • _hK takes the first item in the array and negates it.
  • , returns the two as an array.
\$\endgroup\$
  • \$\begingroup\$ And that's a fine, sneaky way of absorbing the negative sign. \$\endgroup\$ – hBy2Py Jan 1 '18 at 22:44
  • \$\begingroup\$ Save a byte by switching from cz2 60 to c2z60 (they are equivalent for 4-element lists) \$\endgroup\$ – Mr. Xcoder Jan 2 '18 at 11:27
1
\$\begingroup\$

Jelly,  33 32  34 bytes

 +3  +2 bytes to fix up so all liked time outputs are equal.

gotta be a shorter way!

s2Ḍḅ60
83,588ṁ5“¡Ð‘j+\ṡ2>E¥ÞÇḢạÇa\

A monadic link taking a list of the four digits and returning a list containing two integers
- if it's a liked time the result both entries will be zeros.

Try it online! or see the test-suite.

How?

s2Ḍḅ60 - helper link, getMinuteOfDay: list of digits, D   e.g. [1,2,3,3]
 2     - literal two                                           2
s      - split into chunks of length                           [[1,2],[3,3]]
  Ḍ    - un-decimal (convert from base 10) (vectorises)        [12,33]
    60 - literal sixty                                         60
   ḅ   - un-base (convert from base)                           753

83,588ṁ5“¡Ð‘j+\ṡ2>E¥ÞÇḢạÇa\ - Link: list of digits        e.g. [1,2,3,3]
83,588                      - literal list of integers         [83,588]
       5                    - literal five                     5
      ṁ                     - mould like (implicit range of) [83,588,83,588,83]
        “¡Ð‘                - code-page index list             [0,15]
            j               - join                           [0,83,588,83,588,83,15]
              \             - cumulative reduce with:
             +              -   addition                     [0,83,671,754,1342,1425,1440]
                2           - literal two                      2
               ṡ            - overlapping slices of length     [[0,83],[83,671],[671,754],[754,1342],[1342,1425],[1425,1440]]
                     Ç      - last link (1) as a monad f(D)    753
                    Þ       - sort by:
                   ¥        -   last two links as a dyad:
                 >          -     greater than? (vectorises)    [0, 0] [ 0,  0] [  0,  1] [  1,   1] [   1,   1] [   1,   1]
                  E         -     equal?                          1       1         0         1           1           1
                            -                             -->  [[671,754],[0,83],[83,671],[754,1342],[1342,1425],[1425,1440]]
                      Ḣ     - head                             [671,754]
                        Ç   - last link (1) as a monad f(D)    753
                       ạ    - absolute difference (vectorises) [ 82,  1]
                          \ - cumulative reduce with:
                         a  -   AND                            [ 82,  1]
                            -   -- such that if "liked" then the [0,x] result becomes [0,0] so they are all equal
\$\endgroup\$
  • \$\begingroup\$ I don't think the input format (digit array) is allowed in the question, nor is the changing output for special times. \$\endgroup\$ – PurkkaKoodari Jan 1 '18 at 22:06
  • \$\begingroup\$ Fixed, but I don't know if it was the true intent to necessitate such transforms... \$\endgroup\$ – Jonathan Allan Jan 1 '18 at 22:15
  • \$\begingroup\$ True, but I think answers should still match the current written rules of the challenge even if the original intent of the OP was different. \$\endgroup\$ – PurkkaKoodari Jan 1 '18 at 22:17
  • \$\begingroup\$ @Pietu1998 Originally I'd never even considered a list of digits as a useful input form. Per discussion in the main comments, I've formally revised the challenge to allow sequence-of-digits input. \$\endgroup\$ – hBy2Py Jan 1 '18 at 22:54
1
\$\begingroup\$

Husk, 36 bytes

?↑2↑0Πṙ_1†aÖ±↔Ġ-::15t*3e588 83B60†d½

Try it online!

Thanks to Zgarb for explaining me how ternaries work in chat. Trying to golf ↑0, but I didn't get it to work otherwise for some reason (?). This is my first non-trivial Husk answer, and letting the aforementioned aside, I am pretty satisfied with it. The value used instead of YAY!!! is [] (but I hope that will change for golfing purposes).

Explanation

?↑2↑0Πṙ_1†aÖ±↔Ġ-::15t*3e588 83B60†d½ | Input as a digit list from CLA, output to STDOUT.

                                   ½ | Split the list into two halves.
                                 †d  | Turn each half into a base-10 integer.
                              B60    | Convert from base 60.
                :                    | Append the above to ↓ ([15, 83, 588, 83, 588, 83]).
                       e588 83       | Create the two element list [588, 83].
                     *3              | Repeat three times.
                    t                | Remove the first element.
                 :15                 | Prepend a 15.
              Ġ-                     | Apply cumulative subtraction from the right.
             ↔                       | Reverse.
           Ö±                        | Stable sort by the sign (-1, 0 or 1).
         †a                          | Map absolute value.
      ṙ_1                            | Rotate one right.
?    Π                               | If the product is truthy, then:
 ↑2                                  | Take the first two elements.
   ↑0                                | Return an empty list otherwise.
\$\endgroup\$
1
\$\begingroup\$

Kotlin, 293 bytes

{fun i(l:List<Int>)=l.all{it==l[0]}|| l.mapIndexed{a,b->b-a}.all{it==l[0]}
val a=(0..1439+0).map{val h=it/60
val m=it%60
listOf(h/10,h%10,m/10,m%10)}+listOf(listOf(0,0,0,0))
val s=a.indexOf(it)
if(i(it))0 to 0 else
s-a.subList(0,s).indexOfLast{i(it)}to a.subList(s,a.size).indexOfFirst{i(it)}}

Beautified

{
    fun i(l:List<Int>)=l.all { it ==l[0] } || l.mapIndexed { a, b -> b - a }.all { it ==l[0] }
    val a = (0..1439 + 0).map {
        val h = it/60
        val m = it%60
        listOf(h/10,h%10,m/10,m%10)
    } + listOf(listOf(0,0,0,0))
    val s = a.indexOf(it)
    if (i(it)) 0 to 0 else
        s - a.subList(0, s).indexOfLast {i(it)} to a.subList(s, a.size).indexOfFirst {i(it)}
}

Test

var t:(i:List<Int>)-> Pair<Int, Int> =
{fun i(l:List<Int>)=l.all{it==l[0]}|| l.mapIndexed{a,b->b-a}.all{it==l[0]}
val a=(0..1439+0).map{val h=it/60
val m=it%60
listOf(h/10,h%10,m/10,m%10)}+listOf(listOf(0,0,0,0))
val s=a.indexOf(it)
if(i(it))0 to 0 else
s-a.subList(0,s).indexOfLast{i(it)}to a.subList(s,a.size).indexOfFirst{i(it)}}

data class Test(val input: List<Int>, val output: Pair<Int, Int>)

val TEST = listOf(
    Test(listOf(0,0,0,0), 0 to 0),
    Test(listOf(0,0,2,0), 20 to 63),
    Test(listOf(0,1,0,5), 65 to 18),
    Test(listOf(0,1,2,2), 82 to 1),
    Test(listOf(0,1,2,3), 0 to 0),
    Test(listOf(0,1,2,4), 1 to 587),
    Test(listOf(0,8,5,2), 449 to 139),
    Test(listOf(1,1,1,1), 0 to 0),
    Test(listOf(1,1,1,3), 2 to 81),
    Test(listOf(1,2,0,0), 49 to 34),
    Test(listOf(1,2,3,4), 0 to 0),
    Test(listOf(1,3,5,7), 83 to 505),
    Test(listOf(1,7,5,9), 325 to 263),
    Test(listOf(1,8,0,0), 326 to 262),
    Test(listOf(1,8,0,1), 327 to 261),
    Test(listOf(2,2,2,2), 0 to 0),
    Test(listOf(2,2,4,4), 22 to 61),
    Test(listOf(2,3,4,5), 0 to 0),
    Test(listOf(2,3,5,1), 6 to 9)
)

fun main(args: Array<String>) {
    for (t in TEST) {
        val v = t(t.input)
        if (v != t.output) {
            throw AssertionError("$t $v")
        }
    }
}

TIO

TryItOnline

\$\endgroup\$

Your Answer

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

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