21
\$\begingroup\$

Task

Given a string composed of ASCII printable characters, return how many strings could fit the given pattern with character literals and regex-like ranges.

Pattern string

The pattern string follows this grammar (the | means an option and the * means 0 or more occurrences of whatever was immediately to the left):

pattern := '' | pattern_string
pattern_string := (SAFE_CHAR | ASCII_RANGE) pattern_string*
ASCII_RANGE := '[' CHAR '-' CHAR ']'

where CHAR is any ASCII character in the range [32, 127] and SAFE_CHAR is any CHAR except the three characters [, - and ].

Examples

Examples of pattern strings would be a, [0-*]4fj, [a-z][4-9]D[d-B].

Input

The pattern string. You can assume all ranges are well-formed and that all the second characters in the ranges have their ASCII codepoints >= than the corresponding first characters in the range.

Output

The integer corresponding to the number of strings that match the given pattern string.

Test cases

"" -> 1
"a" -> 1
"[*-0]" -> 7
"[0-9][0-9]" -> 100
"[a-z]d[A-z]" -> 1508
"[<->]" -> 3
"[!-&]" -> 6
"[d-z]abf[d-z]fg" -> 529
"[[-]]" -> 3
"[a-a][b-b]cde[---]" -> 1
"[0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1]" -> 4096
"[--[][--]]" -> 2303
"[[-[].[]-]]" -> 1

You can check this Python reference implementation that I used to generate the test cases.

This is so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it... And happy golfing!


This is the second challenge of the RGS Golfing Showdown. If you want to participate in the competition, you have 96 hours to submit your eligible answers. Remember there is still 400 reputation in prizes! (See 6 of the rules)

Also, as per section 4 of the rules in the linked meta post, the "restricted languages" for this second challenge are: 05AB1E, W, Jelly, Japt, Gaia, MathGolf and Stax, so submissions in these languages are not eligible for the final prize. But they can still be posted!!

Otherwise, this is still a regular challenge, so enjoy!

\$\endgroup\$
  • 5
    \$\begingroup\$ please don't leave comments consisting of only things like "+1, good answer" -- these are noise and produce clutter when left on almost every solution \$\endgroup\$ – Doorknob Mar 2 at 7:10
  • \$\begingroup\$ @Doorknob ok, sorry for that. It was not my intention to produce clutter! \$\endgroup\$ – RGS Mar 2 at 7:42

41 Answers 41

14
\$\begingroup\$

CP-1610 machine code (Intellivision),  23  22 DECLEs1 ≈ 28 bytes

As per the exception described in this meta answer, the exact score is 27.5 bytes (220 bits)

A routine taking a null-terminated string as an inline argument through R4 and returning the result in R1.

2B9 001     |         MVII    #1,     R1
2A0         | @@read  MVI@    R4,     R0
080         |         TSTR    R0
204 00F     |         BEQ     @@rtn
378 05B     |         CMPI    #'[',   R0
22C 007     |         BNEQ    @@read
2A0         |         MVI@    R4,     R0
00C         |         INCR    R4
320         |         SUB@    R4,     R0
020         |         NEGR    R0
008         |         INCR    R0
004 11C 1DC |         CALL    MULT
091         |         MOVR    R2,     R1
220 012     |         B       @@read
0A7         | @@rtn   JR      R4

A note about subroutine calls

The CP-1610 instruction for calling subroutines is JSR Rx, $address. This instruction saves the return address in Rx instead of pushing it on the stack as many other CPUs do.

This allows to pass a block of arguments that immediately follows the function call. This is a common practice in CP-1610 programming and that's what we use here.

        JSR     R4,     count     ; call to subroutine through R4
        STRING  "[*-0]", 0        ; argument
        ...                       ; we will return here

Obviously, the subroutine is responsible for reading the correct number of arguments and eventually jumping to the expected return address.

Full commented test code

        ROMW    10                ; use 10-bit ROM width
        ORG     $4800             ; map this program at $4800

PNUM    QEQU    $18C5             ; EXEC routine: print a number
MULT    QEQU    $1DDC             ; EXEC routine: signed multiplication

        ;; ------------------------------------------------------------- ;;
        ;;  main code                                                    ;;
        ;; ------------------------------------------------------------- ;;
main    PROC

        SDBD                      ; set up an interrupt service routine
        MVII    #isr,   R0        ; to do some minimal STIC initialization
        MVO     R0,     $100
        SWAP    R0
        MVO     R0,     $101

        EIS                       ; enable interrupts

        MVII    #$200,  R3        ; R3 = backtab pointer

        JSR     R4,     count     ; test cases
        STRING  "", 0
        CALL    print
        JSR     R4,     count
        STRING  "a", 0
        CALL    print
        JSR     R4,     count
        STRING  "[*-0]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[0-9][0-9]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[a-z]d[A-z]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[<->]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[!-&]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[d-z]abf[d-z]fg", 0
        CALL    print
        JSR     R4,     count
        STRING  "[[-]]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[a-a][b-b]cde[---]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[--[][--]]", 0
        CALL    print
        JSR     R4,     count
        STRING  "[[-[].[]-]]", 0
        CALL    print

        DECR    R7                ; done: loop forever

        ENDP

        ;; ------------------------------------------------------------- ;;
        ;;  prints the result of a test case                             ;;
        ;; ------------------------------------------------------------- ;;
print   PROC

        PSHR    R5                ; save the return address on the stack

        MOVR    R1,     R0        ; R0 = number to print
        MVII    #4,     R1        ; R1 = number of digits
        MOVR    R3,     R4        ; R4 = backtab pointer
        ADDI    #5,     R3        ; advance by 5 characters for the next one
        PSHR    R3                ; save R3
        CLRR    R3                ; R3 = attributes (black)
        CALL    PNUM              ; invoke the EXEC routine
        PULR    R3                ; restore R3

        PULR    R7                ; return

        ENDP

        ;; ------------------------------------------------------------- ;;
        ;;  ISR                                                          ;;
        ;; ------------------------------------------------------------- ;;
isr     PROC

        MVO     R0,     $0020     ; enable display

        CLRR    R0
        MVO     R0,     $0030     ; no horizontal delay
        MVO     R0,     $0031     ; no vertical delay
        MVO     R0,     $0032     ; no border extension
        MVII    #$D,    R0
        MVO     R0,     $0028     ; light-blue background
        MVO     R0,     $002C     ; light-blue border

        JR      R5                ; return from ISR

        ENDP

        ;; ------------------------------------------------------------- ;;
        ;;  our routine                                                  ;;
        ;; ------------------------------------------------------------- ;;
count   PROC

        MVII    #1,     R1        ; initialize R1 to 1

@@read  MVI@    R4,     R0        ; R0 = current character
        TSTR    R0                ; end of string?
        BEQ     @@rtn             ; if yes, return

        CMPI    #'[',   R0        ; is this a '['?
        BNEQ    @@read            ; if not, just go on with the next character

        MVI@    R4,     R0        ; R0 = ASCII code of the starting character
        INCR    R4                ; skip the '-'
        SUB@    R4,     R0        ; subtract the ASCII code of the ending character
        NEGR    R0                ; negate
        INCR    R0                ; increment
        CALL    MULT              ; compute R2 = R0 * R1
        MOVR    R2,     R1        ; and save the result in R1

        B       @@read            ; go on with the next character

@@rtn   JR      R4                ; return

        ENDP

Output

output

screenshot from jzIntv


1. A CP-1610 opcode is encoded with a 10-bit value (0x000 to 0x3FF), known as a 'DECLE'.

| improve this answer | |
\$\endgroup\$
8
\$\begingroup\$

Haskell, 50 48 bytes

f[]=1
f('[':a:b:c:s)=length[a..c]*f s
f(a:s)=f s

Try it online!

| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

JavaScript (Node.js),  66 65  60 bytes

s=>(s.replace(/\[.../g,s=>r*=([,b]=Buffer(s))[3]-b+1,r=1),r)

Try it online!

Commented

s => (                      // s = input string
  s.replace(                // find in s all occurrences of
    /\[.../g,               // '[' followed by 3 characters
    s =>                    // given the matched string s:
      r *=                  //   multiply r by:
        ([, b] = Buffer(s)) //     the difference between
        [3]                 //     the ASCII code of the 4th character
        - b                 //     and the ASCII code of the 2nd one
        + 1,                //     + 1
      r = 1                 //   start with r = 1
  ),                        // end of replace()
  r                         // return r
)                           //

JavaScript (Node.js),  65  64 bytes

A recursive solution.

f=s=>s?-~([g,b,,c]=Buffer(s),!(g^=91)*(c-b))*f(s.slice(g?1:5)):1

Try it online!

Commented

f = s =>             // f is recursive function taking a string s
  s ?                // if s is not empty:
    -~(              //   add 1 to the result of the multiplication below
      [g, b,, c] =   //     g, b, c = ASCII codes of 1st, 2nd and 4th characters
        Buffer(s),   //
      !(g ^= 91) *   //     true if g is a '[', or false otherwise
      (c - b)        //     multiply it by the width of the ASCII range
    ) *              //   multiply by ...
    f(               //   ... the result of a recursive call
      s.slice(g ? 1  //     discard 1 character if it was not a group
                : 5) //     or 5 if it was
    )                //   end of recursive call
  :                  // else:
    1                //   stop recursion
| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

MATL, 22 21 bytes

1 byte saved thanks to @DeathIncarnate

'\[.-.'XX"@gHKh)dQ]vp

Try it online! Or verify all test cases.

How it works

'\[.-.'    % Push this string, to be used as regexp
XX         % Implicit input. Cell array of substrings that match the regexp
"          % For each
  @g       %   Push current substring
  HKh      %   Push 2, then 4, concatente horizontally: gives [2 4]
  )        %   Index: gives a string of two chars
  d        %   Consecutive difference (of code points)
  Q        %   Add 1
]          % End
v          % Concatenate all stack contents vertically (result may be empty)
p          % Product. Implicit display
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Quick 1 byte saving by removing the final ] which is technically unneeded it seems: Try it online! \$\endgroup\$ – DeathIncarnate Feb 28 at 14:41
5
\$\begingroup\$

C (gcc), 58 56 54 52 50 bytes

f(char*s){s=*s?*s++-91?f(s):(s[2]-*s+1)*f(s+4):1;}

Try it online!

Thanks to @S.S. Anne for 2 bytes, and to @Arnauld for 2 more bytes!

This is a recursive solution in C.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ 54 bytes \$\endgroup\$ – S.S. Anne Feb 28 at 21:06
  • \$\begingroup\$ Thanks, @S.S.Anne -- I've removed those unnecessary parentheses. \$\endgroup\$ – Mitchell Spector Feb 28 at 22:49
  • 1
    \$\begingroup\$ 52 bytes \$\endgroup\$ – Arnauld Mar 1 at 10:14
  • \$\begingroup\$ Thanks, @Arnauld -- nice reworking! \$\endgroup\$ – Mitchell Spector Mar 1 at 13:39
4
\$\begingroup\$

05AB1E, 31 21 20 19 bytes

ü5ε2ι`Çs…[-]Q*ÆÄ>}P

-10 bytes thanks to an alternative approach suggested by @ExpiredData.
-2 bytes and a bugfix for [[-[].[]-]] thanks to @Grimmy.

Try it online or verify all test cases.

Explanation:

ü5          # Push all substrings of length 5 of the (implicit) input-string
  ε         # Map each substring abcde to:
   2ι       #  Uninterleave it into 2 blocks: [ace, bd]
     `      #  Push both strings separated to the stack
      Ç     #  Convert the top (bd) to a list of ASCII codepoint integers [B,D]
   s        #  Swap to get the other string (ace) at the top again
    …[-]Q   #  Check if it's equal to "[-]" (1 if truthy; 0 if falsey)
         *  #  Multiply the codepoints by that ([B,D] if truthy; [0,0] if falsey)
   ÆÄ       #  Take the absolute difference between those two (D-B if truthy; 0 if falsey)
     >      #  And increase this by 1
  }P        # After the map: take the product (which will of course be 1 for empty lists)
            # (after which this is output implicitly as result)
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Don't we want to Œ5ù find the substrings of length 5, then filter them to be [...] (maybe something shorter but ʒ40SRè„[]SQ} then take odd indices and delta push 1 then product? Seems like that might end up shorter but I keep writing really long bits to it at the moment \$\endgroup\$ – Expired Data Feb 28 at 12:08
  • 1
    \$\begingroup\$ Œ5ù => ü5 for -1. \$\endgroup\$ – Grimmy Feb 28 at 13:07
  • \$\begingroup\$ @Grimmy Ah yeah, the undocumented feature. Forgot about that one, thanks! :) \$\endgroup\$ – Kevin Cruijssen Feb 28 at 13:11
  • 1
    \$\begingroup\$ Here's a 19 that fixes the [].[] issue. \$\endgroup\$ – Grimmy Feb 28 at 13:17
  • 3
    \$\begingroup\$ 17 (: \$\endgroup\$ – Grimmy Feb 28 at 16:16
4
\$\begingroup\$

C (gcc), 77 \$\cdots\$ 59 58 bytes

Saved 2 bytes thanks to Kevin Cruijssen!!!
Saved 11 13 bytes thanks to Arnauld!!!

r;f(char*s){for(r=1;*s;)r*=*s++-91?1:1-*s+(s+=3)[-1];s=r;}

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ 73 bytes \$\endgroup\$ – Kevin Cruijssen Feb 28 at 10:25
  • \$\begingroup\$ @KevinCruijssen Wow! Was just trying to tuck that i+=3 away and you've tuck that and the if statement away too! Thanks! :-) \$\endgroup\$ – Noodle9 Feb 28 at 10:32
  • 3
    \$\begingroup\$ 61 bytes \$\endgroup\$ – Arnauld Feb 28 at 10:39
  • \$\begingroup\$ @Arnauld Very effective use of dereferences, pointer arithmetic and truth values. You're the master - thanks! :-) \$\endgroup\$ – Noodle9 Feb 28 at 10:48
  • 1
    \$\begingroup\$ This can actually be optimized some more: 59 bytes \$\endgroup\$ – Arnauld Feb 28 at 13:23
4
\$\begingroup\$

Python 3, 77 75 73 bytes

f=lambda s:s==''or'['!=s[0]and f(s[1:])or(ord(s[3])-ord(s[1])+1)*f(s[5:])

Try it online!

-2 bytes thanks to @Arnauld
-2 bytes thanks to @KevinCruijssen

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Raku, 37 bytes

{[*] map {137+[R-] .ords},m:g/\[.../}

Try it online!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

R, 73 bytes

function(s,i=el(gregexpr("\\[.-",s)),u=utf8ToInt(s))prod(u[i+3]-u[i+1]+1)

Try it online!

Today I learned that to include the character [ in a regexp, you need to escape it twice: \\[.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ If it is similar to Python, you do \\[ to escape the backslash, so that it then reaches the regex engine as \[. That is why in Python we often see regex strings prefixed with r. \$\endgroup\$ – RGS Feb 28 at 16:44
3
\$\begingroup\$

GolfScript, 40 38 36 29 27 bytes

1{\(91={(\(;(@-)}1if@*1$}do

Try it online!

With a bit of teamwork, Grimmy and I have this baby down fairly low. it's a shame my goofy integer trick is no longer here :( Check edits for a neat little GS trick.

1{\(91={(\(;(@-)}1if@*1$}do # Regex Counter
1                           # Our stack is now [str 1]
 {                      }do # Pop the top value after a run. If it's true, loop.
 {\                     }do # Swap the top two element of the stack. [1 str]
 { (91={        }1if    }do # Pop the first char and see if it's "[".
 {     {        }       }do # If so, do the following.
 {     {(\(;(@  }       }do # Get rid of the garbage in our block, leaving just the params
 {     {      - }       }do # Find the difference
 {     {      -)}       }do # Increment
 {               1      }do # If the if statement fails, instead push a 1.
                             # At this point, our stack is [1 str dif] (dif may be 1)
 {                  @   }do # Bring our 1 up. [str dif 1]
 {                   *  }do # Multiply our 1 by dif. [str dif*1]
 {                    1$}do # Duplicate our string. [str dif*1 str]
                             # At this point, if our string is empty, our stack is
                             # ["" dif*1 ""], and we see the output. If it ISN'T
                             # empty, then dif*1 is our new 1, and the next loop
                             # works with this loop's dif instead of with a 1.
                             # This functionally multiplies all the values together.
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Got another two by removing the commas! "" is false in GS, so "" times a certain value would still be "". \$\endgroup\$ – Mathgeek Feb 28 at 15:36
  • \$\begingroup\$ Gah, beat me to it by three minutes! \$\endgroup\$ – Mathgeek Feb 28 at 15:44
  • 1
    \$\begingroup\$ 27 by using stack manipulation instead of assigning to 1 (too bad, I liked that trick). \$\endgroup\$ – Grimmy Feb 28 at 15:47
  • \$\begingroup\$ aw shucks, what a shame :( \$\endgroup\$ – Mathgeek Feb 28 at 15:53
3
\$\begingroup\$

Pyth, 21 bytes

*Fmhs.+CMtd:Q"\[.-."1

Try it online!

Standard regex match with :Q"\[.-."1. Then, we remove the leading [ with td and convert to characters with CM.

Next, the clever part: .+ gives deltas between the code points, and s adds up the deltas. This gives just the difference between the first and last characters, ignoring the -.

Finally, h adds one, and *F multiplies everything together.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

C++ (gcc), 70 bytes

int f(char*s){int r=1;for(;*s;)r*=*s++-91?1:1-*s+(s+=3)[-1];return r;}

Try it online!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

BBC BASIC V, 92 bytes

DEFFNf(X$):O=1:FORI=1TOLEN(X$):IFMID$(X$,I,1)="["THENO=O*(1+ASC(MID$(X$,I+3,1))-ASC(MID$(X$,I+1,1))):I=I+5
NEXT:=O

Defines a function that takes a single string argument and returns an integer. Note BBC BASIC V (as implemented on the Acorn Archimedes and RISC PC) was a tokenised language, so commands like MID$ are a single byte. Unfortunately I can't find an online implementation of this, but RPCEmu can be used to test this.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Husk, 22 bytes

ΠmöLu…Ċ2mtf·=Ċ"[-]"2X5

Try it online!

How?

ΠmöLu…Ċ2mtf·=Ċ"[-]"2X5 - string S
                    X5 - sublists of length five
          f            - filter by predicate:
           ·           -   compose two functions:
             Ċ     2   -     2-gaps (every 2nd element) (e.g. "[a-e]" -> "[-]")
            = "[-]"    -     equal to "[-]"?
        m              - map with:
         t             -   tail (e.g. "[a-e]" -> "a-e]")
 m                     - map with:
  ö                    -   compose four functions:
      Ċ2               -     2-gaps (every 2nd element) (e.g. "a-e]" -> "ae")
     …                 -     fill (e.g. "ae" -> "abcde" -- Note: "xx" -> "xx")
    u                  -     remove duplicates (e.g. "xx" -> "x")
   L                   -     length
Π                      - product
| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

brainfuck, 134 125 119 bytes

-[+[+<]>>+]<+++<+>>>,>+<[<<[->+>-<<]>>[[+]<<<[->+<]>>>>-]>[>,<,,>[-<->]<+<<<<[->>>>[-<+<<+>>>]<[->+<]<<<]>>>>>]+<,]<<<.

A commented version can be found below. Saved 9 bytes thanks to @S.S.Anne.

You can try it online, where you can check the "memory dump" to see that the final output is the correct result. In practice only works for tests where final result is <= 255.

You are welcome to golf my code, just keep it commented please. Then use this Python script on TIO to do the byte count and remove comments.

Init a cell with 91
-[+[+<]>>+]<+++
<+>>>,>+<
Mem: accumulator = 1 | left bracket = 91 | 0 | ^input char | 1 | 0
[ If something was read
Subtract the 91 from this char
<<[->+>-<<]
>>
Mem: accumulator | 0 | 91 | ^input minus 91 | 1 | 0
Use non destructive flow control to check if the input char was the beginning of a range
[ If the ascii code point was not 91 then this is a safe character
Zero out the input char
[+]
Move the acc to the right
<<<[->+<]>>>
Remove the else flag
>-] (end if)
>
[ Else the character starts a range and layout is
Mem: acc | 0 | 91 | 0 | ^1 | 0
>,<,,
Mem: acc | 0 | 91 | 0 | ^right char | left char
Subtract the two and add one
>[-<->]<+
Mem: acc | 0 | 91 | 0 | ^diff plus one | 0
                    A   B                C
Multiply the accumulator by the diff plus one
The diff plus one will be juggled around A and B
<<<<[ While the acc is still nonzero
->>>>
[-<+<<+>>>]
<[->+<]
<<<
] (end while)
Mem: ^0 | acc | 91 | 0 | diff plus one | 0
>>>>>
] (end else)
Mem: 0 | acc | 91 | 0 | ? | ^0 | 0
Reset workplace
+<
, Try reading again
Mem: acc | 91 | 0 | ^input char | 1 | 0
]
<<<.
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Replace ++++++++++[->+++++++++<]+>+ with -[+[+<]>>+]<+++ and you get a solid 122. Can't figure out the dump memory so no The Brainfuck link. Also, you can put your comments in a loop if they're after another loop or if it's the beginning of the program, just make sure to keep your brackets balanced. \$\endgroup\$ – S.S. Anne Feb 29 at 2:37
3
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 138 133 bytes

	I =INPUT
	P =1
	A =&ALPHABET
	L =LEN(1)
N	I '[' L . X L L . Y REM . I	:F(O)
	A X @S
	A Y @E
	P =P * (E - S + 1)	:(N)
O	OUTPUT =P
END

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @RGS the manual and tutorial found by following the SNOBOL link in the header! There was an answer chaining question a few years back (One OEIS after another) where I learned just enough to submit an answer, and I just kinda kept using it cuz it's so weird. String matching is SNOBOL's main focus, but it is not exactly easy to golf in. \$\endgroup\$ – Giuseppe Mar 1 at 12:52
3
+100
\$\begingroup\$

Shakespeare Programming Language, 493 398 bytes

-2 bytes thanks to Jonathan Allan

-87 bytes (!) thanks to Jo King

,.Ajax,.Ford,.Act I:.Scene I:.[Enter Ajax and Ford]Ajax:You cat.Scene V:.Ajax:Is I as big as the sum ofThe cube ofa big big cat the cube ofThe sum ofA big cat a cat?If notLet usScene X.Remember you.Open mind.Ford:Open mind.Open mind.You is the sum ofA cat the difference betweenYou I.Ajax:Recall.You is the product ofyou I.Scene X:.Ford:Open mind.Ajax:Is I worse zero?If notLet usScene V.Open heart

Try it online!

Ford is initialized as 1. Ajax reads through the input. When he encounters a [, Ford reads the next and Ajax the third next character, and Ford is multiplied by the difference + 1. When Ajax reaches the end of the input, Ford opens his heart, printing his value.

The shortest representation I found of 91 (the ASCII code of [) is \$91=(2\times2)^3+(2+1)^3\$ but there might be something better.

With spaces and comments:

,.Ajax,.Ford,.                                         A = F = 0
Act I:.Scene I:.
[Enter Ajax and Ford]
Ajax: You is a cat.                                    F = 1
Scene V:.
Ajax: Is I as big as the sum of                        if not(A == 91) (with 91=64+27)
The cube of a big big cat                              (2*2)^3 (=64)
the cube of The sum of A big cat a cat?                (2+1)^3 (=27)
If not Let us Scene X.                                 go to Scene X
Remember you.                                          F[2] = F
Open mind.                                             F = stdin
Ford: Open mind. Open mind.                            A = stdin
You is the sum of A cat the difference between You I.  A = 1 + A -F
Ajax: Recall.                                          F = F[2]
You is the product of you I.                           F = F * A
Scene X:.
Ford: Open mind.                                       A = stdin
Ajax: Is I worse zero? If not Let us Scene V.          if not(A<0) go to Scene V
Open heart                                             print(F)
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ "The cube ofTwice a big cat" -> "The cube ofa big old cat" saves two \$\endgroup\$ – Jonathan Allan Mar 2 at 13:30
  • \$\begingroup\$ @JonathanAllan Thanks! \$\endgroup\$ – Robin Ryder Mar 2 at 15:08
  • \$\begingroup\$ 441 bytes with a little rearranging. I think it would also be a lot shorter to use Ford's memory instead of a third character \$\endgroup\$ – Jo King Mar 2 at 23:42
  • \$\begingroup\$ Implementing my suggestion takes it down to 404 bytes \$\endgroup\$ – Jo King Mar 3 at 1:10
  • 1
    \$\begingroup\$ Congratulations on winning the style points for this challenge of the RGS! \$\endgroup\$ – RGS Mar 7 at 8:45
2
\$\begingroup\$

C# (Visual C# Interactive Compiler), 80 76 bytes

r=>{int c=1,i=r.Length;for(;i-->1;)c*=r[i]==93?r[--i]-r[i-=2]+1:1;return c;}

Try it online!

Port of @KevinCruijssen's Java answer

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Java 8, 80 76 bytes

r->{int c=1,i=r.length;for(;i-->1;)c*=r[i]==93?r[--i]-r[i-=2]+1:1;return c;}

-4 bytes thanks to @ExpiredData.

Try it online.

Explanation:

r->{               // Method with character-array parameter and integer return-type
  int c=1,         //  Count-integer, starting at 1
      i=r.length;  //  Index integer, starting at the length of the input
  for(;i-->1;)     //  Loop as long as the index is larger than 1,
                   //  and decrease the index every iteration by 1 right after this check
    c*=            //   Multiply the count by:
       r[i]==93?   //    If the `i`'th character of the input is a ']':
        r[--i]     //     Take the `i-1`'th character, by decreasing `i` with 1 first
        -r[i-=2]   //     And decrease it by the `i-3`'th character,
                   //     due to the earlier `--i` and by first decreasing `i` with 2 first
        +1         //     And add 1 to that difference
                   //     (NOTE: We've only decreased `i` by 3 instead of 4 here, but this
                   //      doesn't matter, since it will always be the '[' character of the
                   //      previous block in the next iteration, and thus multiplying by 1
                   //      in the else block)
       :           //    Else (single character match):
        1;         //     Keep the count the same by multiplying with 1
  return c;}       //  And then return this count as result
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ @RGS It's inspired by both Arnauld's JS and your Haskell answers tbh. My initial approach was generating all n-length permutations of the printable ASCII range and check if it matches the regex, but that approach was ~350 bytes (also because [--]] and [--[] aren't valid regexes in Java), so when I saw Arnauld post his 66 byte solution I quickly dropped it and started over, haha. \$\endgroup\$ – Kevin Cruijssen Feb 28 at 9:46
  • 1
    \$\begingroup\$ 76 bytes. it doesn't matter if we skip past characters since it will just multiply by 1 \$\endgroup\$ – Expired Data Feb 28 at 10:06
  • 1
    \$\begingroup\$ @ExpiredData Ah smart! It will always match the [ of the previous block in that case, so it will guaranteed go to the else and simply keep the count the same by multiplying with 1. \$\endgroup\$ – Kevin Cruijssen Feb 28 at 10:14
2
\$\begingroup\$

Whitespace, 149 bytes

[S S S T    N
_Push_1][N
S S N
_Create_Label_LOOP][S N
S _Duplicate][S N
S _Duplicate][T N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve_input][S N
S _Dupe][S S S T    S T S N
_Push_10][T S S T   _Subtract][N
T   S S S N
_If_0_Jump_to_Label_DONE][S S S T   S T T   S T T   N
_Push_91][T S S T   _Subtract][N
T   S S N
_If_0_Jump_to_Label_BLOCK_FOUND][N
S N
N
_Jump_to_Label_LOOP][N
S S S N
_Create_Label_BLOCK_FOUND][S N
S _Duplicate][S N
S _Duplicate][T N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve][S N
S _Duplicate][S N
S _Duplicate][S N
S _Duplicate][T N
T   S _Read_STDIN_as_character][T   N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve][S N
T   _Swap_top_two][T    S S T   _Subtract][S S S T  N
_Push_1][T  S S S _Add][T   S S N
_Multiply][S N
S _Duplicate][T N
T   S _Read_STDIN_as_character][N
S N
N
_Jump_to_Label_LOOP][N
S S S S N
_Create_Label_DONE][S N
N
_Discard][T N
S T _Print_as_integer]

Letters S (space), T (tab), and N (new-line) added as highlighting only.
[..._some_action] added as explanation only.

Since Whitespace inputs one character at a time, the input should contain a trailing newline (\n) so it knows when to stop reading characters and the input is done.

Try it online (with raw spaces, tabs and new-lines only).

Explanation in pseudo-code:

Integer count = 1
Start LOOP:
  Integer c = read STDIN as character
  If(c == '\n'):
    Jump to Label DONE
  If(c == '['):
    Jump to Label BLOCK_FOUND
  Go to next iteration of LOOP

Label BLOCK_FOUND:
  Integer a = read STDIN as character
  Read STDIN as character (without saving it)
  Integer b = read STDIN as character
  Integer diff = b - a
  diff = diff + 1
  count = count * diff
  Read STDIN as character (without saving it)
  Go to next iteration of LOOP

Label DONE:
  Print count as integer to STDOUT
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @RGS No, I actually program in Whitespace for all my answer. Unless it's a kolmogorov-complexity challenge, in which case I have a partial Java generator I once wrote utilizing this tip of mine. Not directly in TIO though. I use the vii5ard compiler which also has a builtin debugger which works quite well. I can see the values on the stack/heap in the memory tab, and even set breakpoints. But I do actually program like in the top part of my program with the [S S S N\n_Push_0] synthax I came up with myself. \$\endgroup\$ – Kevin Cruijssen Feb 28 at 14:22
  • \$\begingroup\$ cool, then :) and then you convert your syntax to code? \$\endgroup\$ – RGS Feb 28 at 19:31
  • 1
    \$\begingroup\$ @RGS Well, converting my synthax to code is easy. I just remove all non-whitespaces with replace("[^ \t\r\n]", "") and that's the code I put in the TIO link. :D \$\endgroup\$ – Kevin Cruijssen Feb 29 at 11:27
  • 1
    \$\begingroup\$ Huh, your replace doesn't support \S? \$\endgroup\$ – Neil Mar 2 at 11:13
  • \$\begingroup\$ @Neil It most likely does. xD I could say all other whitespace-types should be removed as well, but I won't use those anyway when writing my answers, so you're right, replace("\S","") should work fine as well. Ah well ¯\_(ツ)_/¯ \$\endgroup\$ – Kevin Cruijssen Mar 2 at 12:07
2
\$\begingroup\$

Befunge-98 (PyFunge), 30 bytes

1v;>.@;  <
*>#^~'[-#^_~~$~\1--

Try it online!

Explanation

1v
 >

Push 1 to the stack and move east in the second line

 >.@
#^~

Input character (~), if no input is left print the TOS (.) and quit the execution (@).

'[-#^_

Subtract [ from the input, if the input is [ continue east, otherwise go north.

1v;>.@;  <
 >

Case input ≠ [: Go back to the start of the second line.

*>        ~~$~\1--

Case input = '[': Take the next three characters of input, discard the -, and compute the difference between the two remaining chars, multiply this to the current result.

Animation of the code for input a[0-9]: Animation of the code

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Haskell, 66 64 bytes

Non-regex solution.

f[]=1
f('[':a:b:c:d:s)=(1+(g c)-(g a))*f s
f(a:s)=f s
g=fromEnum

You can try it online! Uses the algorithm in my Python reference implementation.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Burlesque, 29 bytes

"\[.-."~?{)**{3 1}si^p.-+.}mp

Try it online!

"\[.-."~?  # List of all RegEx matches
{
 )**         # Ord()
 {3 1}si     # Select values at indices 3 & 1 (start,end)
 ^p          # Unbox
 .-          # Difference
 +.          # Increment
}mp          # Map product (returns 1 for empty)

Burlesque (Non-competing), 24 bytes

s1r1{@\x01\x7fr\jCB}\m{g1~=}fl

Try it online!

Solution that generates all possible strings and counts the number of matches.

WARNING: May take infinite time and memory.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ "WARNING: May take infinite time and memory." is the best kind of code golf warning. \$\endgroup\$ – Mathgeek Feb 28 at 20:23
  • \$\begingroup\$ @Mathgeek It's technically shorter... \$\endgroup\$ – DeathIncarnate Feb 28 at 20:52
  • \$\begingroup\$ @DeathIncarnate Does the second program terminate? If it doesn't, it's disqualified by codegolf.meta.stackexchange.com/questions/4782/… \$\endgroup\$ – Embodiment of Ignorance Feb 29 at 4:27
  • \$\begingroup\$ @EmbodimentofIgnorance Ah darn, not provably. Still fun though. \$\endgroup\$ – DeathIncarnate Feb 29 at 9:07
  • \$\begingroup\$ Invalid answers need to be deleted, not marked "non-competing" \$\endgroup\$ – pppery Mar 29 at 21:28
2
\$\begingroup\$

Python 3.8 (pre-release), 87 bytes

-5 byte thanks to @SurculoseSputum

lambda s:math.prod(ord(m[3])-ord(m[1])+1for m in re.findall(r'\[.-.',s))
import re,math

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

x86-16 machine code, 25 bytes

B3 01       MOV  BL, 1          ; init multiplier
        C_LOOP: 
AC          LODSB               ; AL = [SI], SI++
3C 20       CMP  AL, 32         ; is char less than 32
7C 10       JL   DONE           ; if so, exit
3C 5B       CMP  AL, '['        ; is char '['?
75 F7       JNZ  C_LOOP         ; if not, keep looping
AD          LODSW               ; AL = CHR_L
92          XCHG AX, DX         ; DL = CHR_L
AC          LODSB               ; AL = CHR_R
2A C2       SUB  AL, DL         ; AL = CHR_R - CHR_L
98          CBW                 ; AH = 0
40          INC  AX             ; AL = AL + 1
93          XCHG AX, BX         ; AX = multiplier
F7 E3       MUL  BX             ; multiplier *= CHR_R - CHR_L + 1 
93          XCHG AX, BX         ; BX = multiplier 
EB EA       JMP  C_LOOP         ; keep looping 
        DONE: 
C3          RET                 ; return to caller

As a callable function, input string in [SI]. Output in BX.

Example test program I/O:

enter image description here

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

CJam, 23 bytes

1q{('[={(\(;(@-)@*\}&}h

Try it online!

First time programming in CJam.

1q{('[={(\(;(@-)@*\}&}h
1q                             Push 1, then push the input, stack = [ 1, str ]
  {('[={(\(;(@-)@*\}&}h        Execute this  while the top of the stack is truthy
   ('[=                        Pop the first char and test for equality
                    &          If it is truthy...
       {(\(;(@-)@*\}           Execute this:
        (\(;(@                   Get the two values of the character class to the top of the stack
                                 E.g "0-9]..." -> "9", "0", ...                       
              -)                 Subtract 2nd element char code by first and increment, stack = [1, str, diff]
                @                Get the 1 to the top of the stack, stack = [ str, 1, diff]
                 *               Multiply top 2 elements, stack = [ str, diff ]
                  \              Swap the top 2, so the string is back on top
  {                  }h        If the string is not empty, run this again. Else print the output
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Labyrinth,  53  50 bytes

1 @!{""
}    ;
,:_91-,,;,-
"    ;    `
""";;)~}*{)

Try it online!

How?

Sets the top of the auxiliary stack to 1 and consumes characters from STDIN, if these are [ the next three characters are consumed and the top of the auxiliary stack is multiplied by one more than the difference in ordinals of the relevant two characters. Once the EOF is reached this value is printed.

  1 pop main (0); * 10; + 1 (=1) -> main
  } pop main -> auxiliary  (i.e. set initial cumulative product to 1)
A , read a character, C, ord(C) -> main
    3-neighbours, top of stack is non-zero so turn
  : copy top of main -> main
  _ zero -> main
  9 pop main; * 10; + 9 (=90) -> main
  1 pop main; * 10; + 1 (=91) -> main
  - pop main (a=91); pop main (b=ord(C)); b-a -> main
B   4-neighbours
    if top of main is zero (i.e. we read a '[') then go straight:
  ,   read a character, L, ord(L) -> main  (i.e. L of [L-R])
  ,   read a character, x='-', ord(x) -> main
  ;   pop main (i.e. discard the '-' of [L-R])
  ,   read a character, R, ord(R) -> main  (i.e. R of [L-R])
  -   pop main (a=ord(R)); pop main (b=ord(L)); b-a -> main
  `   pop main; negate -> main
  )   pop main; increment -> main  (i.e. ord(R)-ord(L)+1)
  {   pop auxiliary -> main  (i.e. get current cumulative product)
  *   pop main (a); pop main (b); b*a -> main
  }   pop main -> auxiliary  (i.e. set new cumulative product)
  ~   pop main (0); bitwise NOT (~0=-1) -> main
  )   pop main; increment -> main
      3-neighbours, top of stack is zero so go straight
  ;   pop main (i.e. discard the zero, leaving infinite zeros on main)
  ;   pop main (i.e. discard another zero, sill leaving infinite zeros on main)
  """" no-ops taking us back to the first , instruction at "A"
B   elif top of main is negative (i.e. we read something <'[') then turn left:
  ;   pop main (i.e. discard the result)
  "   no-op
C     3-neighbours
      if top of main (the duplicate of ord(C)) is negative (i.e. EOF) then turn left:
  {     pop auxiliary -> main  (i.e. get cumulative product)
  !     pop main; print as decimal
  @     exit program
C     elif top of main is positive then turn right:
  "     no-op
        we hit a wall so turn around
  "     no-op
        3-neighbours, top of stack is non-zero so turn
  ;     pop main (i.e. discard this leaving infinite zeros on main)
  -     pop main (a=0); pop main (b=0); b-a=0 -> main
        4-neighbours (same location as B but facing down), top of main is zero so go straight
  ;     pop main (i.e. discard one of the infinite zeros off of main)
  )     pop main; increment (=1) -> main
        3-neighbours, top of stack is positive so turn right
  ;     pop main (i.e. discard this 1)
  ;     pop main (i.e. discard one of the infinite zeros off of main)
  """"  no-ops taking us back to the first , instruction at "A"
C     (N.B. elif top of main is zero cannot happen)
B   elif top of main is positive (i.e. we read something >'[') then turn right:
  ;   pop main (i.e. discard the result)
  )   pop main (duplicate of ord(C)); increment -> main
      3-neighbours top of main is positive so turn right:
  ;   pop main (i.e. discard that)
  ;   pop main (i.e. discard one of the infinite zeros off of main)
  """"  no-ops taking us back to the first , instruction at "A"

The complicated 4-neighbour -, along with the dead-end ", is a 3 byte save over the easier to follow:

1
}
,:_91-,,;,-
;    ;    `
""""")~}*{)
     {
    @!
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I was very close to awarding the style points to this answer because I always liked labyrinths and I had never seen this language... So good work! \$\endgroup\$ – RGS Mar 7 at 8:46
2
\$\begingroup\$

Julia 1.0, 62 60 bytes

s->prod(map(x->x[2][1]-x[1][1]+1,eachmatch(r"\[(.)-(.)",s)))

-2 bytes thanks to Robin Ryder

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ The \] doesn't seem necessary: 60 bytes. \$\endgroup\$ – Robin Ryder Feb 29 at 7:48
1
\$\begingroup\$

Charcoal, 31 bytes

≔⪪⮌S¹θ≔¹ηWθF⁼⊟θ[≧×L…·⊟θ∧⊟θ⊟θηIη

Try it online! Link is to verbose version of code. Explanation:

≔⪪⮌S¹θ

Input the pattern string, reverse it, and split it into individual characters. This allows characters to be consumed within an expression by using Pop(q).

≔¹η

Start off with 1 matching string.

Wθ

Repeat until all of the input characters have been processed.

F⁼⊟θ[

Is this a character range?

≧×L…·⊟θ∧⊟θ⊟θη

If so then multiply the result by the length of the inclusive range between the next character and the next but three (this saves a byte over converting to ordinals manually). The characters are consumed so that a range that starts or ends at [ does not get misinterpreted as a second range.

Iη

Output the result.

| improve this answer | |
\$\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.