17
\$\begingroup\$

In a now deleted stackoverflow question, someone posted the following:

Write a program or function to print alternating patterns in * and # based on a given integer n. Some examples:

Input: n=1
Output:

*

Input n=5
Output:

*####
###**
***##
###**
*####

Input: n=8
Output:

*#######
######**
***#####
####****
****####
#####***
**######
#######*

Since it looked like a pretty cool code-golfing challenge, here it is.

How are these patterns build?

The first line starts with a single *, followed by n-1 amount of trailing #.
The second line then contains two *, with n-2 amount of leading #.
The third line starts with three *, followed by n-3 amount of trailing #.
etc.

Once we've reached the middle (n/2), we count back again with the amount of *, which can be seen in the examples above.

NOTE that for odd input numbers the inversed pair of lines (so first and last; second and next to last; etc.) are exactly the same. In the n=5 example the first and last lines are *####; the second and next to last lines are ###**.
For even input numbers however the inversed pair of lines are reversed. In the n=8 example the first and last lines are *####### and #######*; the second and next to last lines are ######** and **######; etc.

Challenge rules:

  • You can use any two distinct printable characters instead of * and #. You can use A and B; 3 and 7; < and >; etc. Please state in your answers what you've used.
  • You can assume n will be a positive integer (>= 1)
  • You are allowed to output a list/array of strings for each line or a 2D matrix of characters, instead of printing them to STDOUT.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, adding an explanation for your answer is highly recommended.

Test cases (first n=1 through n=10)

*

*#
#*

*##
#**
*##

*###
##**
**##
###*

*####
###**
***##
###**
*####

*#####
####**
***###
###***
**####
#####*

*######
#####**
***####
###****
***####
#####**
*######

*#######
######**
***#####
####****
****####
#####***
**######
#######*

*########
#######**
***######
#####****
*****####
#####****
***######
#######**
*########

*#########
########**
***#######
######****
*****#####
#####*****
****######
#######***
**########
#########*
\$\endgroup\$
2
  • \$\begingroup\$ "You can use any two distinct characters instead of * and #." - Do they have to be printable? Can we use NUL and SOH (ASCII codes 0 and 1)? \$\endgroup\$
    – ngn
    Jul 27, 2018 at 9:13
  • \$\begingroup\$ @ngn Sorry, printable characters only. Will clarify in the challenge description. \$\endgroup\$ Jul 27, 2018 at 9:42

18 Answers 18

17
\$\begingroup\$

Python 2, 62 bytes

lambda n:["%*s"%(i%2*2*n-n,"x"*min(i+1,n-i))for i in range(n)]

Try it online!

Uses x and space.

The rows are computed like this:

"%-5s" % "x"      == "x    "
"%5s"  % "xx"     == "   xx"
"%-5s" % "xxx"    == "xxx  "
"%5s"  % "xx"     == "   xx"
"%-5s" % "x"      == "x    "

Using the %*s specifier to choose between n and -n.

\$\endgroup\$
14
\$\begingroup\$

Jelly, 9 bytes

>þµoṚUÐeY

Try it online!

Explanation

>þ           Create a table of (x>y) over [1…n]×[1…n]:
               [0 1 1 1 1]
               [0 0 1 1 1]
               [0 0 0 1 1]
               [0 0 0 0 1]
               [0 0 0 0 0]
  µ          Take this array, and...
   oṚ        OR it with its reverse:
               [0 1 1 1 1]
               [0 0 1 1 1]
               [0 0 0 1 1]
               [0 0 1 1 1]
               [0 1 1 1 1]
    UÐe      Apply U (reverse) to even-indexed rows.
       Y     Join by newlines.
\$\endgroup\$
0
7
\$\begingroup\$

APL (Dyalog Classic), 18 bytes

⎕a[↑⊢∘⌽\(⊂>⊢⌊⌽)⍳⎕]

Try it online!

outputs AB instead of *#

evaluated input n

⍳⎕ the vector 0 1 ... n-1

⊢⌊⌽ min () between themselves () and their reverse () - see trains

⊂>⊢⌊⌽ where is the vector as a whole () less than each of its ⊢⌊⌽ - return a vector of boolean (0/1) vectors

⊢∘⌽\ reverse every other vector

mix into a matrix

⎕a the uppercase English alphabet, 'AB...Z'

⎕a[ ] replace 0 1 with 'A' 'B'

\$\endgroup\$
2
  • \$\begingroup\$ Out of curiosity. How many bytes would it be to simply output the matrix of 0s and 1s without spaces? I'm assuming ⎕a[...} converting them to A and B without spaces is shorter than keeping them as 0 and 1 without spaces considering you've used that, but just curious if there is much difference in bytes if you keep them as 0 and 1. \$\endgroup\$ Jul 25, 2018 at 17:50
  • 1
    \$\begingroup\$ @KevinCruijssen As far as I can golf, it would be the same length - either ⎕d[...] or ⊃¨⍕¨... In the latter expression ⍕¨ is "format each" - it turns each number into a nested char vector, so we need "first each" (⊃¨) to get only char scalars (and therefore no whitespace when printing). \$\endgroup\$
    – ngn
    Jul 25, 2018 at 18:36
6
\$\begingroup\$

Perl 6, 57 bytes

{map ^$^a: {fmt -$a*(-1)**$_=>\*x($_+1 min$a-$_): "%*s"}}

Try it online!

Uses the same method as Lynn's Python answer. Outputs using * and space.

\$\endgroup\$
6
\$\begingroup\$

MATL, 34 31 18 bytes

:t!>tPY|!"@X@oQ&P!

Try it on MATL Online

Uses 0 for * and 1 for #. Based on Lynn's Jelly answer.


Older answer, 31 bytes:

2/tk:wXk:Ph"X@ot~XHh@Gy-hHQ&PY"

Try it on MATL Online

Uses 1 for * and 0 for #.

         % implicit input, say 5
2/       % divide input number by 2 [2.5]
tk       % make a copy and floor that [2.5, 2]
:        % create range 1 to the floored value [2.5, [1, 2]]
wXk      % bring out the division result and this time ceil it
         %  [[1, 2], 3]
:        % create range 1 to that [[1, 2], [1, 2, 3]]
Ph       % flip the last array and concatenate horizontally 
         %  [[1, 2, 3, 2, 1]]
"        % loop through the array
  X@o    % Is the current loop index odd? 1 for odd, 0 for even
  t~     % duplicate and logical negate that
  XH     % copy that value to clipboard H
  h      % and concatenate the values ([1 0] on odd iterations, [0 1] on even) 
  @      % push current value from array (say 2, then stack is [[0 1], 2)
  G      % push input again
  y-     % subtract current array value from input [[0 1], 2, 3]
  h      % concatenate those two [[0 1], [2, 3]]
  H      % get the stored value from clipboard H (1 for even iterations, 0 for odd) 
  Q      % increment that
  &P     % flip the array in that dimension: in even iterations, this flips
         %   across columns and hence inverts the two values. [[0 1], [3, 2]]
         %   in odd iterations, it's a no-op
  Y"     % run-length decoding - repeat the element from first array the number of times
         %  specified in the second array
         % implicit loop end, implicit output
\$\endgroup\$
5
\$\begingroup\$

Charcoal, 21 bytes

≔⮌…⁰NθEθ⭆θ›§⟦μλ⟧κ⌊⟦κι

Try it online! Uses 0 and 1. Link is to verbose version of code and includes §*# which translates the output to the * and # in the question. Explanation:

    N                   Input number
  …⁰                    Range from 0
 ⮌                      Reversed
≔    θ                  Assign to `q`
      Eθ                Map over reversed range
        ⭆θ              Map over reversed range and join
           §⟦μλ⟧κ       Alternate between range and reversed range column
                 ⌊⟦κι   Minimum of range and reversed range row
          ›             Greater
                        Implicitly print each row on its own line
\$\endgroup\$
5
\$\begingroup\$

Jelly,  12  15 bytes

+3 fixing n=1 edge-case bug :(

R«Ṛ$‘r⁸ṬUÐe0YE?

A full program accepting an integer which prints the output as defined in the OP using 0 and 1 for * and # respectively.

Try it online!

How?

R«Ṛ$‘r⁸ṬUÐe0YE? - Main Link: integer, n
R               - range -> [1,2,3,4,...,n]
   $            - last two links as a monad:
  Ṛ             -   reverse -> [n,...,4,3,2,1]
 «              -   minimum (vectorises) -> [1,2,3,4,...,4,3,2,1]
    ‘           - increment (vectorises) -> [2,3,4,5,...,5,4,3,2]
      ⁸         - chain's left argument, n
     r          - inclusive range (vectorises) -> [[2,3,...,n],[3,4,...n],[4,5,...n],[5,...n],...,[5,...n],[4,5,...n],[3,4,...n],[2,3,...,n]]
       Ṭ        - untruth (vectorises) -> [[0,1,1,...,1],[0,0,1,1,...,1],[0,0,0,1,...,1],[0,0,0,0,1,...,1],...,[0,0,0,0,1,...,1],[0,0,0,1,...,1],[0,0,1,1,...,1],[0,1,1,...,1]]
         Ðe     - apply to entries with even indices:
        U       -   upend              -> [[0,1,1,...,1],[1,1,...,1],[0,0,0,1,...,1],[1,...,1,0,0,0,0],...]
              ? - if...
             E  - ...condition: all equal? (only true when n=1, where we have [1,1])
           0    - ...then: zero
            Y   - ...else: join with newline characters
                - implicit print
\$\endgroup\$
2
  • \$\begingroup\$ It looks like this is exactly my algorithm, but a different implementation which outputs 0s instead of 1s and vice versa. \$\endgroup\$ Jul 26, 2018 at 9:42
  • \$\begingroup\$ Yes effectively the same thing ...and I hadn't updated my post to show the fix I made. \$\endgroup\$ Jul 26, 2018 at 11:29
4
\$\begingroup\$

Jelly, 15 bytes

r1«RR;ṬṖɗ€‘UÐeY

Try it online!

Full program.

* = 1
# = 0

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

Java 10, 145 bytes

n->{var r=new char[n][n];for(int j=0,k;j<n;++j)for(k=0;k<n;)r[j][k]=k++<(j<n/2?j%2<1?j+1:n+~j:j%2>0?j:n-j)?j%2<1?'*':'#':j%2>0?'*':'#';return r;}

All the ternary makes it a bit messy, but it works fine. I tried flattening the nested loop, and various other things, but they only increased the byte count. Try it online here.

Ungolfed:

n -> { // lambda taking an integer as output and returning a char[][]
    var r = new char[n][n]; // the output array; we make use of Java 10's var here (replace with char[][] for another 4 bytes to make this work in Java 8)
    for(int j = 0, k; j < n; ++j) // iterate over the lines
        for(k = 0; k < n; )       // iterate over the j'th line
            r[j][k] = // set the current character
                      k++ < // determine if we're in the first or second portion of the line:
                            (j < n/2 ? // for the first half of the output:
                                 j%2 < 1  // on even lines ...
                                 ? j + 1  // ... print the first symbol j+1 times ...
                                 : n + ~j // ... on odd lines, print it n-j-1 times.
                             : j%2 > 0 ?  // for the second half of the output, on odd lines ...
                                 j :      // ... print the first symbol j times ...
                                 n - j)   // ... on even lines, print it n-j times.
                      ? j%2 < 1 ? '*' : '#'  // for the first part of the line, use '*' on even lines, '#' otherwise
                      : j%2 > 0 ? '*' : '#'; // for the second part of the line, use '*' on odd lines, '#' otherwise
    return r; // return the completed array
}

Java 8 11, 179 127 bytes

n->{String r="",a,b;for(int j=0;j<n;b="#".repeat(j<n/2?n+~j:j),r+=(j++%2<1?a+b:b+a)+"\n")a="*".repeat(j<n/2?j+1:n-j);return r;}

Try it online here (TIO does not have Java 11 yet, so this uses a custom method that results in the same byte count as String#repeat()).

Thanks to Kevin Cruijssen for golfing a whopping 52 bytes!

Ungolfed:

n -> { // lambda taking an int argument and returning a String
    String r = "", // the output String
           a,      // temporary String containing the '*'s
           b;      // temporary String containing the '#'s
    for(int j = 0; j < n; // loop over the lines
        b = "#".repeat( // repeat the '#' character ...
            j < n/2 ? n + ~j // ... n-j-1 times in the first half of the output ...
            : j), // ... j times in the second half
        r += (j++ % 2 < 1 ? a + b : b + a) + "\n") // assemble the j'th line and append it to the output: on even lines, the '*'s go first; on odd lines, the '#'s go first
        a = "*".repeat( // repeat the '*' character ...
              j < n/2 ? j + 1 // ... j+1 times in the first half of the output ...
              : n - j); // n-j times in the second half
    return r; // return the completed output
}
\$\endgroup\$
2
4
\$\begingroup\$

Lua,  148  133 Bytes

function(n)t,a,b={},".","#"for i=1,n do r=i<n/2+1 and i or-~n-i s=a:rep(r)..b:rep(n-r)t[i]=i%2<1 and s:reverse()or s end return t end

Try it online!

-15 bytes thanks to @KevinCruijssen and @JoKing.

function(n)
   t = {}; a = "."; b = "#"          -- initialize variables, output is in table
                                     -- strings are needed in variables for
                                     --   the str:rep and str:reverse syntax

   for i = 1, n do                          -- build the rows of the table
      r = i<=(n+1)/2 and i or n-i+1         -- logic used to count up then down
      str = a:rep(r)..b:rep(n-r)            -- append correct number of '.'s, fill
                                            --   in the rest with '#'s
      t[i]=i%2==0 and str:reverse() or str  -- logic used to control reversing
   end
   return t                                 -- return table
end
\$\endgroup\$
5
  • 2
    \$\begingroup\$ I don't know Lua too well, but it seems you can save five bytes: (n+1)/2 to -~n/2; or n-i+1 to or-~n-i; i%2==0 to i%2<1; and reverse() or to reverse()or. Also, your TIO version and byte-count both contain a trailing semi-colon which doesn't seems to be necessary. Nice first answer, though. +1 from me. And welcome to PPCG! :) \$\endgroup\$ Jul 26, 2018 at 21:17
  • 2
    \$\begingroup\$ You actually don't need any of the semi-colons. 133 bytes including Kevin's suggestions. \$\endgroup\$
    – Jo King
    Jul 26, 2018 at 23:17
  • \$\begingroup\$ @KevinCruijssen Thanks! Could I ask what the -~n is doing in your suggestions? It definitely works, but I don't understand why. \$\endgroup\$ Jul 27, 2018 at 16:57
  • 1
    \$\begingroup\$ @AzureHeights Sure. ~ is a unary bitwise negation operator. What's important for codegolfing however, is that ~i holds the same value as -i-1. We can therefore use -~i instead of i+1 and ~-i instead of i-1. This is useful in two cases, which I could both utilize in your answer: getting rid of parenthesis, because - and ~ have operator precedence over other mathematical operations, so (n+1)/2 can therefore be -~n/2. And the other useful part is to get rid of spaces in some cases, as I did with or-~n-i. \$\endgroup\$ Jul 27, 2018 at 17:48
  • 1
    \$\begingroup\$ Here are the two relevant tips if you want to read a bit more about it: Use unary ~ for x+1 and x-1 and Use unary ~ for a-b-1 and a+b+1. All general tips, as well as language specific tips (Tips for golfing in Lua in this case), might be interesting to read through. :) \$\endgroup\$ Jul 27, 2018 at 17:50
3
\$\begingroup\$

Kotlin, 86 bytes

{n:Int->for(i in 0..n)println("%${i%2*2*n-n}s".format("x".repeat(Math.min(i+1,n-i))))}

Try it online!

Uses x and space as output symbols. Derivates from Lynn Answer

\$\endgroup\$
3
\$\begingroup\$

Perl 5 + -pa -MPOSIX -M5.010, 58 bytes

say+sort{$|--}1x abs,2x("@F"-abs)for(1..ceil$_/=2),-$_..-1

Try it online!

\$\endgroup\$
3
\$\begingroup\$

C (gcc), 104 99 bytes

h,j,k;f(i){char s[h=i++];for(j=0;k=++j>i/2?i-j:j,j<i;memset(memset(s,42,h)+j%2*k,35,h-k),puts(s));}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

C (gcc), 118 108 bytes

This one isn't going to win, but it's a different approach (or at least, I think so!) Instead of doing string manipulations, I make use of the fact that \$10^x-1\$ over \$[1..n] = \{9, 99, 999, ...\}\$, which then can be multiplied to get the appropriate pattern; printf() then does the zero-padding for right-justification.

Sadly, int only has sufficient range to do up to 9 digits (on 32-bit platforms), so you need to go to long for larger patterns; a language that natively does MP arithmetic might be able to use this for something.

Thanks to ceilingcat for the suggestion.

h,j,k;p(h){h=h?10*p(--h):1;}f(i){for(j=0,h=i++;k=++j>i/2?i-j:j,j<i;printf("%0*d\n",h,~-p(k)*p(j%2*(h-k))));}

Try it online!


Proof of concept that this works with MP arithmetic:

C# (Mono C# compiler), 187 165 bytes

(143 bytes + 22 bytes for the using System.Numerics; in the header)

q=>{var r="";for(int j=0,h=q+1,k;j<q;r+=((BigInteger.Pow(10,k)-1)*BigInteger.Pow(10,j%2*(q-k))).ToString("D"+q)+"\n")k=++j>h/2?h-j:j;return r;}

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Proof of concept with numbers outside of the maximum native integer ranges (using C# and BigIntegers): Try it online! \$\endgroup\$
    – ErikF
    Jul 26, 2018 at 9:08
3
\$\begingroup\$

Vim, 99 keystrokes

It's always interesting to try to do vim with input arguments. It's very unnatural, so it's not going to be amazingly short. There probably are other good approaches to this.

Input is assumed to be by itself in a buffer. Registers are assumed to be empty. Editor is assumed to be tall enough to contain the result without scrolling (this could technically be avoided at the cost of some keystrokes).

"nD@ni<cr><esc>MmaGddM
<c-v>'aI*<esc>qwgvjokoI*<esc>@wq@w<esc>
:set ve=all<cr>@nlh<c-v>@nkr#
:%s/ /#/g<cr>o<esc>
2Gqqdt#$p2j0@qq@q

Explanation

 | Buffer state (odd and even case):
 | 5                    6

"nD              read input into register n
@ni<cr><esc>     add n newlines
MmaGddM<c-v>'a   visual block select center row(s)
I*<esc>          prepend a column of *
qw               record macro w
  gvjoko         expand selection up and down
  I*<esc>
  @w             recurse
q
@w<esc>          run macro w and exit visual block select

 | Buffer state:
 | *                    *
 | **                   **
 | ***                  ***
 | **                   ***
 | *                    **
 |                      *

:set ve=all<cr>  move anywhere!
@nlh<c-v>@nkr#   add last column of #s

 | Buffer state:
 | *   #                *    #
 | **  #                **   #
 | *** #                ***  #
 | **  #                ***  #
 | *   #                **   #
 |                      *    #

:%s/ /#/g<cr>      replace spaces with #

 | Buffer state:
 | *####                *#####
 | **###                **####
 | ***##                ***###
 | **###                ***###
 | *####                **####
 |                      *#####

o<esc>2G           prep and jump to line 2
qqdt#$p2j0@qq@q    (effectively) flip every other onward

 | Buffer state:
 | *####                *#####
 | ###**                ####**
 | ***##                ***###
 | ###**                ###***
 | *####                **####
 |                      #####*

And in base64, with actual characters (put input in input and keystrokes in keys and run using vim -u NONE -s keys input)

Im5EQG5pDRtNbWFHZGRNFidhSSobcXdndmpva29JKhtAd3FAdxs6c2V0IHZlPWFsbA1AbmxoFkBua3IjOiVzLyAvIy9nDW8bMkdxcWR0IyRwMmowQHFxQHE=
\$\endgroup\$
2
\$\begingroup\$

R, 75 bytes

function(n)outer(1:n,1:n,function(x,y,a=x<y|x>n-y+1)+ifelse(x%%2,a,rev(a)))

Try it online!

  • Inspired by @Lynn answer
  • function getting n as parameter and returning a matrix of 0/1 where 0 corresponds to '*' and 1 corresponds to '#'
\$\endgroup\$
2
\$\begingroup\$

K (ngn/k), 22 bytes

{"*#"i|:/'i>/:i&|i:!x}

Try it online!

{ } function with argument x

!x the list (0;1;...;x-1)

i: assign to i

i&|i minima (&) of i and its reverse (|)

i>/: compare with greater than (>) i against each element from the list on the right (/:) - return a boolean matrix (list of lists)

i|:/' for each (') j in i, reverse (|: - we need the : to force | to be unary) the corresponding element j times (n f/ x applies f n times on x). Effectively, reverse every other row.

"*#" use matrix elements as indices in the string "*#"

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

Python 3, 251 bytes

n = int(input())

for i in range(1,n+1):
  if i%2 != 0:
    for j in range(1,n-i+2):
      print("*",end=" ")
  
  for j in range(1,i+1):
    print("#",end=" ")
    
  if i%2 == 0:
    for j in range(1,n-i+2):
      print("*",end=" ")
      
  print()

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! Be sure to check out our Tips for golfing in Python page for ways you can golf your program. I've edited your answer slightly to include a link to an online testing environment and to improve the formatting. It looks like you can remove a lot of whitespace to save bytes: Try it online! \$\endgroup\$ Nov 25, 2021 at 13:31

Your Answer

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

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