19
\$\begingroup\$

Befunge is a 2-dimensional programming language, with an instruction pointer (IP). In Befunge-98, the ; character tells the IP to skip characters up until the next ; (Let us call it skipping mode when the IP is skipping characters). Here is an example:

"This part is read into the stack" ; this part is not ; @

I would like to generate a w wide, h high comment outline for a Befunge-98 program. This means that an IP in normal mode (not in string mode nor in skipping mode) should enter the comment, skip over the comment and then exit in normal mode, no matter which row or column it arrives from. Additionally, the outline must be at most one character thick. That is, the bounding box of the entire comment (including outline) must be no more than w+2 wide and no more than h+2 high.

Example

If w = 5, h = 3 then a valid comment outline would be:

;;;;;;
;     ;
;     ;
;     ;
 ;;;;;;

Note that this would not be a valid comment outline:

;;;;;;;
;     ;
;     ;
;     ;
;;;;;;;

This is because in the first column, the IP would enter in normal mode, but exit in skipping mode, potentially skipping crucial code. (The same thing would happen in the 7th column, 1st row and 5th row)

This is not valid either:

       
       
       
       
       

This would result in the comment being interpreted as code.

Challenge

Write a program or function that, given a width and height as input, outputs any valid Befunge-98 comment outline for that size. The width and height are guaranteed to be at least 1.

  • You must output in spaces, semicolons and line breaks, unless your chosen programming language is unable to
  • You may have trailing whitespace, however they can only be spaces and line breaks
  • Each line may have trailing spaces
  • You may alternatively take input as w+2 and h+2 instead of w and h
    • You may also mix between the two e.g. you can input w+2 and h
  • As stated above, the width of the outline must be at most 1
  • There must be a w by h area inside the outline made of only spaces

More examples

w = 2, h = 2

;;;;
;  ;
;  ;
;;;;

w = 3, h = 2

 ;;;;
;   ;
;   ;
 ;;;;

w = 2, h = 3

 ;;
;  ;
;  ;
;  ;
;;;;

w = 5, h = 1

;;;;;;
;     ;
 ;;;;;;
\$\endgroup\$
3
  • 4
    \$\begingroup\$ Suggested test case: 2, 3. \$\endgroup\$ Oct 22, 2023 at 13:35
  • 2
    \$\begingroup\$ Yes please provide at least one testcase for every combination of even and odd w and h. \$\endgroup\$
    – corvus_192
    Oct 22, 2023 at 13:51
  • \$\begingroup\$ @CommandMaster I have added the test case \$\endgroup\$ Oct 22, 2023 at 23:26

9 Answers 9

6
\$\begingroup\$

Python, 93 89 85 79 74 73 bytes

lambda w,h:';'*(w|1)+(';\n;'+' '*w)*h+';\n'+h%2*' '+';'*(w+~h%2+~(w^h)%2)

Attempt This Online!

-7 bytes thanks to Arnauld and bsoelch.

The last row is built from four parts:

  1. a space if the height is odd
  2. w semicolons
  3. one additional semicolon if h is even
  4. one additional semicolon if w and h have the same evenness.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can use w+2&~1 instead of (w|1)+1. \$\endgroup\$
    – Arnauld
    Oct 22, 2023 at 17:00
  • \$\begingroup\$ 73 bytes \$\endgroup\$
    – bsoelch
    Oct 23, 2023 at 16:00
5
\$\begingroup\$

Jelly,  23  19 bytes

aþ¬So1;Ʋ€ZṚƊ4¡ị⁾; Y

A dyadic Link that accepts \$w\$ on the left and \$h\$ on the right and yields a list of characters (or a full program that prints the result).

Try it online! Or see the test-suite.

How?

aþ¬So1;Ʋ€ZṚƊ4¡ị⁾; Y - Link: integer, W; integer, H
 þ                  - [1..W] table [1..H] with:
a                   -   logical AND
  ¬                 - logical NOT
                       -> W×H zeros
             ¡      - repeat...
            4       - ...times: four
           Ɗ        - ...action: last three links as a monad:
        €           -              for each Row:
       Ʋ            -                last four links as a monad:
   S                -                sum {Row}
     1              -                one
    o               -                {sum} logical OR {one}
      ;             -                {that} concatenate {Row}
         Z          -              transpose }
          Ṛ         -              reverse   } - rotate a quarter
              ị⁾;   - index into "; " (1-based and modular)
                  Y - join with newline characters
\$\endgroup\$
4
\$\begingroup\$

Charcoal, 22 21 bytes

F⁴«§; ⁺ι⁺ⅈⅉ×;I§⟦θη⟧ι↷

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

F⁴«

Loop over the four sides of the rectangle.

§; ⁺ι⁺ⅈⅉ

Output a space if the sum of the previous dimensions is odd but a semicolon if it is even.

×;I§⟦θη⟧ι

Output the appropriate number of semicolons.

Pivot 90° so that the next iteration draws the next side of the rectangle.

(Would have saved 4 bytes to input the width and height as a tuple instead of separate values.)

\$\endgroup\$
4
\$\begingroup\$

Rust, 109 100 129 120 113 112 108 bytes

-4 bytes thanks to @corvus_192

Is this what people mean when they say Rust's syntax is unreadable?

|w,h|{let r=str::repeat;r(";",w|1)+&r(&(r(";\n;",1)+&r(" ",w)),h)+";\n"+&r(" ",h%2)+&r(";",w+!h%2+!(w^h)%2)}

Attempt This Online!

At the end of the program, I have to calculate the number of semicolons to output for the last line. This forms a decision tree that can be visualized in the following table:

w h result
odd odd w + 1
odd even w + 1
even odd w
even even w + 2

First, I used an actual array and indexing with n%2 to get the result, but this takes too many characters.

I have now converged to w+(w&1)+2*(!(w|h)&1) (first taking w, adding 1 if w is odd and then adding 2 if both w and h are even), but this can't be optimal.

I have now converged to w+(!h&1)+(!(w^h)&1) (first taking w, adding 1 if h is even and then again adding 1 the parity of w and h is equal, but that also can't be optimal. Just look at the amount of parens!

w+!h%2+!(w^h)%2 seems to be the best option. Completely forgot about precedence whoops

\$\endgroup\$
6
  • \$\begingroup\$ How is the output in the ATO invalid? From every direction there is an even number of boxes, and the box is of the specified size. \$\endgroup\$
    – leo848
    Oct 22, 2023 at 13:29
  • \$\begingroup\$ Thanks, fixed . \$\endgroup\$
    – leo848
    Oct 22, 2023 at 14:08
  • 1
    \$\begingroup\$ -4 bytes: w+!h%2+!(w^h)%2 (not from me, but I used it in my answer) \$\endgroup\$
    – corvus_192
    Oct 22, 2023 at 20:26
  • \$\begingroup\$ I think let r=str::repeat;move|w,h|... is a valid answer according to the rules, as it can be assigned to a function. \$\endgroup\$
    – corvus_192
    Oct 22, 2023 at 20:37
  • \$\begingroup\$ @corvus_192 but that would be 2 bytes longer?! \$\endgroup\$
    – leo848
    Oct 22, 2023 at 20:58
3
\$\begingroup\$

J, 53 53 41 36 35 31 30 26 24 bytes

'; '{~1=3|+/&(3,$&5,2&|)

Attempt This Online!

Finally found a decent approach based on an addition table of the appropriate lists. Say our m rows x n cols input is 1 x 3, which represents the dimensions of the inner box.

We construct lists for each dimension of an addition table as follows:

going down:

Initial number 
is always 3, followed
by m 5s, followed by....
v
3 
5 
1     <-- Final number is 1
          since m = 1 is odd.
          Otherwise would be 0.
              

going across:

3 followed by n=3 fives
v
3 5 5 5 1 <-- Final number is
              is 1 again, since n=3 
              is odd

Let's see what happens when we make a addition table:

  | 3  5  5  5  1
--+--------------
3 | 6  8  8  8  4
5 | 8 10 10 10  6
1 | 4  6  6  6  2

Next we mod by 3, and check if the result is 1, which it will be only for cells that should be a space:

0 0 0 0 1
0 1 1 1 0
1 0 0 0 0

And finally convert to spaces/semicolons:

;;;;
;   ;
 ;;;;

This procedure gives the correct result for all 4 possible even/odd combos.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Much more clear now, thanks! \$\endgroup\$
    – noodle man
    Oct 24, 2023 at 17:29
  • \$\begingroup\$ Since you mod everything by 3, why not just use 0, 2 and 1 respectively? \$\endgroup\$
    – Neil
    Oct 31, 2023 at 16:25
  • \$\begingroup\$ @Neil You're right '; '{~1=3|+/&(0,$&2,2&|) works too, but doesn't save any bytes since you still need to mod by 3. But you're right it's simpler. \$\endgroup\$
    – Jonah
    Oct 31, 2023 at 17:25
1
\$\begingroup\$

05AB1E, 29 bytes

«';Ž9¦S.ΛIÉ©нi¨}®θið®OÉǝ}®Oi¦

Can definitely be golfed by using a different approach..

Input as pair \$[w+2,h+2]\$.

Try it online or verify all test cases.

Explanation:

Step 1: Create a \$w+2\$ by \$h+2\$ box of ;, filled with spaces:

«         # Merge the (implicit) input-pair to itself: [w+2,h+2,w+2,h+2]
 ';      '# Push character ";"
   Ž9¦    # Push compressed integer 2460
      S   # Convert it to a list of digits [2,4,6,0]
       .Λ # Use the (modifiable) Canvas builtin with these three arguments

Try just step 1 online.

Step 2: Do the following actions based on whether the \$w\$ and \$h\$ are odd:

\$h\$=even,\$w\$=even \$h\$=even,\$w\$=odd \$h\$=odd,\$w\$=even \$h\$=odd,\$w\$=odd
Do nothing Insert a space at index 1;
Remove the first character
Remove the first character
Remove the last character
Insert a space at index 0;
Remove the last character

: Removing the first character of the multiline string basically empties the top-right corner.

Combining those actions, we have the following three things to do:

Remove the first character Remove the last character Insert a space at index \$((w+h)=odd)\$
If \$w+h\$=odd If \$w\$=odd If \$h\$=odd

Which translates to the following code:

I         # Push the input-pair again
 É        # Check for both whether they're odd (1 if odd; 0 if even)
  ©       # Store this pair in variable `®` (without popping)
   н      # Pop and push the first item
    i }   # If w is odd:
     ¨    #  Remove the last character of the box
®         # Push pair `®` again
 θ        # Pop and push its last item
  i     } # If h is odd:
   ð      #  Push a space character " "
    ®O    #  Push the sum of pair `®`
      É   #  Check if this sum is odd
       ǝ  #  Insert the space at that (0-based) index
®O        #  Push the sum of pair `®` yet again
  i       # If this sum is 1 (so either w or h is odd, and the other is even):
   ¦      #  Remove the first character of the box†
          # (after which the result is output implicitly)

See this 05AB1E tip of mine to understand how the Canvas builtin Λ works.
See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž9¦ is 2460.

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

Ruby, 66 bytes

->w,h{(a="; "*w*h)[w+h]+?;*w+a[h]+"
;#{' '*w};"*h+"
"+a[w]+?;*-~w}

Try it online!

We use "; " repeated (w * h) times to get the character at the corners (by indexing) without using reminder operations.

The character at the top left corner is ; if both or none of w and h are odd so we add them together, that's why we need a loooong "; ; ; ..." string

\$\endgroup\$
0
\$\begingroup\$

JavaScript (Node.js), 96 bytes

f=(x,y,h=y++,w=x++)=>~x?f(x-1,y,h,w)+' ;'[(Y=y>h|!y)^(x>w|!x)|Y&!x*h+!y*w+1]:y?f(w,y-1,h)+`
`:''

Try it online!

\$\endgroup\$
0
\$\begingroup\$

sed -E, 158 bytes

Input is taken as 51 for w=5 and h=1. The first line adds a cheat sheet to teach sed counting down (of course you'd need some extra bytes for comments larger than 9) and produces the solution for w=1/h=1. Then the w loop adds two ; and one while counting down the first field. The h loop duplicates a line with a whitespace while counting down the second field. The next-to-last line adds a semicolon for a odd number of them. Not very slim, but probably the best to achieve with sed.

s/$/987654321\n;;\n; ;\n;;\n/
:w
s/^(.)(..*\1(\S).*;;)(.* )(.*;)/\3\2;\4 \5;/
tw
:h
s/^.(.)(.*\1(\S).*)(\n.* ;)/-\3\2\4\4/
th
s/(\n(;;)+)(;\n)/\1;\3/g
s/.*1//

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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