24
\$\begingroup\$

Given an input integer n > 1, output an ASCII-art octagon with side lengths composed of n characters. See examples below:

n=2
 ##
# #
# #
 ##
n=3
 ###
 # #
# #
# #
# #
 # #
 ###
n=4
 ####
 # #
 # #
# #
# #
# #
# #
 # #
 # #
 ####
n=5
 #####
 # #
 # #
 # #
# #
# #
# #
# #
# #
 # #
 # #
 # #
 #####
and so on.

You can print it to STDOUT or return it as a function result.

Any amount of extraneous whitespace is acceptable, so long as the characters line up appropriately.

Rules and I/O

  • Input and output can be given by any convenient method.
  • You can use any printable ASCII character instead of the # (except space), but the "background" character must be space (ASCII 32).
  • Either a full program or a function are acceptable.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.
asked Nov 6, 2018 at 17:50
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Can we use different output characters, or does it need to be consistent? \$\endgroup\$ Commented Nov 6, 2018 at 18:13
  • \$\begingroup\$ @Emigna Different characters are fine. \$\endgroup\$ Commented Nov 6, 2018 at 18:26
  • 1
    \$\begingroup\$ Quite related. \$\endgroup\$ Commented Nov 7, 2018 at 11:06

24 Answers 24

23
\$\begingroup\$

05AB1E, 3 bytes

7ÝΛ

Try it online!

Explanation

 # implicit input as length
 # implicit input as string to print
7Ý # range [0...7] as directions
 Λ # canvas print

See this answer to understand the 05AB1E canvas.

answered Nov 6, 2018 at 18:12
\$\endgroup\$
4
  • \$\begingroup\$ Surely this should be 5 bytes? Or do code golf challenges see bytes and characters as interchangeable \$\endgroup\$ Commented Nov 7, 2018 at 17:10
  • 3
    \$\begingroup\$ @Doug: It is 3 bytes in 05ab1e's code page \$\endgroup\$ Commented Nov 7, 2018 at 17:11
  • \$\begingroup\$ Oh, cool! Thanks for the docs link! \$\endgroup\$ Commented Nov 7, 2018 at 17:58
  • \$\begingroup\$ >:( damnit, adnan \$\endgroup\$ Commented Nov 11, 2018 at 5:14
11
\$\begingroup\$

JavaScript (ES6), (削除) 114 (削除ここまで) (削除) 106 (削除ここまで) (削除) 105 (削除ここまで) (削除) 104 (削除ここまで) 103 bytes

n=>(g=x=>v=x*2>w?w-x:x,F=x=>~y?`# 
`[~x?(h=g(x--))*g(y)>0&h+v!=n|n>h+v:(y--,x=w,2)]+F(x):'')(y=w=--n*3)

Try it online!

How?

This builds the output character by character.

Given the input \$n\$, we compute:

$$n'=n-1\\w=3n'$$

For each character at \$(x,y)\$, we compute \$(h,v)\$:

$$h=w/2-\left|x-w/2\right|\\v=w/2-\left|y-w/2\right|$$

The cells belonging to the octagon satisfy one of the following conditions:

  • (\$h=0\$ OR \$v=0\$) AND \$h+v\ge n'\$ (in red below)
  • \$h+v=n'\$ (in orange below)

For example, with \$n=4\$ (and \$n'=3\$):

$$\begin{matrix}(0,0)&(1,0)&(2,0)&\color{red}{(3,0)}&\color{red}{(4,0)}&\color{red}{(4,0)}&\color{red}{(3,0)}&(2,0)&(1,0)&(0,0)\\ (0,1)&(1,1)&\color{orange}{(2,1)}&(3,1)&(4,1)&(4,1)&(3,1)&\color{orange}{(2,1)}&(1,1)&(0,1)\\ (0,2)&\color{orange}{(1,2)}&(2,2)&(3,2)&(4,2)&(4,2)&(3,2)&(2,2)&\color{orange}{(1,2)}&(0,2)\\ \color{red}{(0,3)}&(1,3)&(2,3)&(3,3)&(4,3)&(4,3)&(3,3)&(2,3)&(1,3)&\color{red}{(0,3)}\\ \color{red}{(0,4)}&(1,4)&(2,4)&(3,4)&(4,4)&(4,4)&(3,4)&(2,4)&(1,4)&\color{red}{(0,4)}\\ \color{red}{(0,4)}&(1,4)&(2,4)&(3,4)&(4,4)&(4,4)&(3,4)&(2,4)&(1,4)&\color{red}{(0,4)}\\ \color{red}{(0,3)}&(1,3)&(2,3)&(3,3)&(4,3)&(4,3)&(3,3)&(2,3)&(1,3)&\color{red}{(0,3)}\\ (0,2)&\color{orange}{(1,2)}&(2,2)&(3,2)&(4,2)&(4,2)&(3,2)&(2,2)&\color{orange}{(1,2)}&(0,2)\\ (0,1)&(1,1)&\color{orange}{(2,1)}&(3,1)&(4,1)&(4,1)&(3,1)&\color{orange}{(2,1)}&(1,1)&(0,1)\\ (0,0)&(1,0)&(2,0)&\color{red}{(3,0)}&\color{red}{(4,0)}&\color{red}{(4,0)}&\color{red}{(3,0)}&(2,0)&(1,0)&(0,0)\end{matrix} $$

answered Nov 6, 2018 at 20:09
\$\endgroup\$
4
  • \$\begingroup\$ Wow, this is awesome! I think \$h + v \geq n'\$ can be simplified to \$h+v>n'\,ドル although I'm not sure if that helps the golfing logic at all. \$\endgroup\$ Commented Nov 6, 2018 at 22:20
  • \$\begingroup\$ @Giuseppe It could indeed be simplified that way if both conditions were tested. But in the code, the cases \$hv=0\$ and \$hv\neq0\$ are separated. However, I'm actually testing the opposite condition (\$n'>h+v\$), which already is 1 byte shorter. \$\endgroup\$ Commented Nov 6, 2018 at 22:29
  • \$\begingroup\$ @Giuseppe Your comment prompted me to have a closer look at the formula and I finally saved a byte by writing it a bit differently. :) \$\endgroup\$ Commented Nov 6, 2018 at 22:41
  • 1
    \$\begingroup\$ heh, well your comment about \$hv=0\$ prompted me to go look at my port of your logic and save another couple of bytes! \$\endgroup\$ Commented Nov 6, 2018 at 22:44
7
\$\begingroup\$

Charcoal, 5 bytes

GH*N#

My first answer with Charcoal!

Explanation:

GH*N# //Full program
GH //Draw a hollow polygon
 * //with 8 sides
 N //of side length from input
 # //using '#' character

Try it online!

answered Nov 6, 2018 at 18:25
\$\endgroup\$
1
  • 3
    \$\begingroup\$ For those who prefer verbose Charcoal, that's PolygonHollow(:*, InputNumber(), "#");. \$\endgroup\$ Commented Nov 6, 2018 at 18:51
5
\$\begingroup\$

Canvas, (削除) 15 (削除ここまで) (削除) 14 (削除ここまで) 12 bytes

×ばつ+:⤢n╬┼

Try it here!

Explanation:

/ a diagonal of length n
 8 the input,
 ⇵ ceiling divided by 2, (storing the remainder)
 ╷ minus one
 ×ばつ repeat "#" that many times
 + append that to the diagonal
 :⤢n overlap that with its transpose
 ╬┼ quad-palindromize with the overlap being the remainder stored earlier

Alternative 12-byter.

answered Nov 6, 2018 at 17:56
\$\endgroup\$
4
\$\begingroup\$

R, (削除) 122 (削除ここまで) (削除) 117 (削除ここまで) 115 bytes

function(n){n=n-1
m=matrix(0,y<-3*n+1,y)
v=t(h<-(w=3*n/2)-abs(row(m)-1-w))
m[h*v&h+v-n|h+v<n]=' '
write(m,1,y,,"")}

Try it online!

Ports the logic from Arnauld's answer, specifically this revision in case there are further improvements. Another 2 bytes saved thanks to Arnauld's suggestion of inverting the logic!

answered Nov 6, 2018 at 18:33
\$\endgroup\$
1
  • \$\begingroup\$ -2 bytes by doing it the other way around (I can't do h*v&h+v-n in JS because & is a bitwise operator; but it's a logical one in R, so that works). \$\endgroup\$ Commented Nov 7, 2018 at 15:05
3
\$\begingroup\$

Python 2, 96 bytes

a=b=n=input()
while a>2-n-n:a-=1;b-=a/~-n+1;s=(-~b*' '+'#').ljust(n);print s+s[-1]*(n-2)+s[::-1]

Try it online!

answered Nov 6, 2018 at 22:03
\$\endgroup\$
3
\$\begingroup\$

Python 2, 81 bytes

a=d=n=input()-1
while a<=n:print' '*a+'#'+' #'[a==n]*(3*n-a+~a)+'#';d-=1;a-=d/n+1

Try it online!


Python 2, 75 bytes

a=d=n=input()-1
while a<=n:print' '*a+`' `'[a==n]*(3*n-a+~a)`;d-=1;a-=d/n+1

Try it online!

If mixing output characters is OK.

answered Nov 6, 2018 at 23:49
\$\endgroup\$
3
\$\begingroup\$

Powershell, 91 bytes

param($n)($s=' '*--$n+'#'*$n+'#')
--$n..0+,0*$n+0..$n|%{' '*$_+"#$(' '*(3*$n-2*$_+2))#"}
$s
answered Nov 7, 2018 at 7:37
\$\endgroup\$
2
\$\begingroup\$

PowerShell, (削除) 107 (削除ここまで) 97 bytes

param($n)($z=$n-1)..1+,0*$n+1..$z|%{" "*$_+"#"+($x=" "*($z-$_))+(" ","#")[!($_-$z)]*($n-2)+"$x#"}

Try it online!

If there was a cheap way to reverse the first half, this answer would feel a lot better. It builds the left half, then the core (which is either x #'s or spaces), then mirrors the left's logic to make the right. Fun fact, you don't need to copy over trailing white-space.

Unrolled and explained:

param($n)
($z=$n-1)..1 + ,0*$n + 1..$z |%{ #Range that repeats 0 n times in the middle
" "*$_ + "#" +($x=" "*($z-$_)) + #Left side
(" ","#")[!($_-$z)]*($n-2) + #Core that swaps when it's the first or last row
"$x#"} #Right side which is left but backwards
answered Nov 7, 2018 at 0:38
\$\endgroup\$
0
2
\$\begingroup\$

APL (Dyalog Unicode), 46 bytes SBCS

(' '@~5 6∊⍨1⊥⊢∘,)⌺3 3⊢<(⍉⌽⌊⊢)⍣2∘(∘.+⍨∘⍳ ×ばつ⊢)

This solution was provided by Adám - thanks!

Try it online!

My (almost) original solution:

APL (Dyalog Unicode), 61 bytes SBCS

(((⊃∘' #' ̈1+5∘=+6∘=)⊢)1⊥⊢∘,)⌺3 3⊢<(((⊖⌊⊢)⌽⌊⊢)(∘.+⍨(⍳ ×ばつ⊢)))

Try it online!

Thanks to Adám for his help!

The idea is to find the "diamond" that lies partly in the square and apply an edge-detect filter to "outline" the octagone.

answered Nov 7, 2018 at 13:48
\$\endgroup\$
6
  • 1
    \$\begingroup\$ 46: (' '@~5 6∊⍨1⊥⊢∘,)⌺3 3⊢<(⍉⌽⌊⊢)⍣2∘(∘.+⍨∘⍳¯2+3×⊢) \$\endgroup\$ Commented Nov 7, 2018 at 13:51
  • 1
    \$\begingroup\$ You can't actually use Classic here because of . Rather count 1 byte/char by referring to SBCS as per Meta. \$\endgroup\$ Commented Nov 7, 2018 at 13:52
  • \$\begingroup\$ @Adám Thanks! I don't know how to edit the header, can you do it for me? \$\endgroup\$ Commented Nov 7, 2018 at 14:01
  • \$\begingroup\$ What do you mean by editing the header? \$\endgroup\$ Commented Nov 7, 2018 at 14:22
  • 1
    \$\begingroup\$ Edit and copy from here. \$\endgroup\$ Commented Nov 7, 2018 at 14:40
2
\$\begingroup\$

C (clang), -DP=printf( -DF=for(i (削除) + 179 = 199 (削除ここまで) 180 bytes

i;*m="%*s%*s\n";g(n){P"%*s",n,H;F;--i;)P H;P"\n");}f(n){g(n);F;--i;)P m,i,(H,3*n-i+~i,H;F-2;i--;)P"#%*s\n",3*n-3,H;F;--i;)P m,n-i,(H,n+i+i-1,H;g(n);}

Try it online!

Ungolfed:

f(n){
	int i;
	printf("%*d",n,0);
	for(i=0;i<n-1;i++){
		printf("0");
	}
	printf("\n");
	for(i=1;i<n;i++){
		printf("%*d%*d\n",n-i,0,n+i+i-1,0);
	}
	for(i=0;i<n-2;i++){
		printf("0%*d\n",n+n+n-3,0);
	}
	for(i=n-1;i>0;i--){
		printf("%*d%*d\n",n-i,0,n+i+i-1,0);
	}
	printf("%*d",n,0);
	for(i=0;i<n-1;i++){
		printf("0");
	}
}

-19 bytes thanks to @ceilingcat

answered Nov 7, 2018 at 3:32
\$\endgroup\$
1
  • \$\begingroup\$ 173 bytes \$\endgroup\$ Commented Apr 25, 2022 at 6:43
1
\$\begingroup\$

Python 2, 130 bytes

def f(n):
 a=[' '*~-n+n*'#']
 b=[' '*(n-i-2)+'#'+' '*(n+2*i) +'#'for i in range(n-2)]
 return a+b+['#%*s'%(3*n-3,'#')]*n+b[::-1]+a

Try it online!

On mobile, so not incredibly golfed.

answered Nov 6, 2018 at 19:02
\$\endgroup\$
1
  • \$\begingroup\$ You can remove the space after (n+2*i). \$\endgroup\$ Commented Nov 8, 2018 at 13:26
1
\$\begingroup\$

Batch, 260 bytes

@echo off
set s=
for /l %%i in (1,1,%1)do call set s= %%s%%
echo %s% %s: =#%
call:c %1,-1,3
for /l %%i in (1,1,%1)do echo #%s:~2%%s%%s:~2%#
call:c 3,1,%1
echo %s% %s: =#%
exit/b
:c
for /l %%i in (%*)do call echo %%s:~,%%i%%#%%s:~%%i%%%s%%%s:~%%i%%#

Outputs two leading spaces on each line. Explanation: Batch has no string repetition operator, limited string slicing capability and requires separate statements to perform arithmetic. It was therefore golfiest to make up a string of the input length in spaces (Batch can at least translate these to #s for the top and bottom lines) and then slice from or to a specific position ranging from 3 to the length to generate the diagonals (this is what the last line of the script achieves).

answered Nov 7, 2018 at 9:20
\$\endgroup\$
1
\$\begingroup\$

Ruby, 96 bytes

->n{[*(n-=2).step(z=n*3+2,2),*[z]*n,*z.step(n,-2)].map{|x|([?#]*2*('# '[x<=>n]*x)).center(z+2)}}

Try it online!

Not very golfed yet. Might golf if I find the time.

answered Nov 7, 2018 at 9:40
\$\endgroup\$
1
\$\begingroup\$

Red, 171 bytes

func[n][c:(a: n - 1)* 2 + n
b: collect[loop c[keep pad/left copy"^/"c + 1]]s: 1x1 s/1: n
foreach i[1x0 1 0x1 -1x1 -1x0 -1 0x-1 1x-1][loop a[b/(s/2)/(s/1): #"#"s: s + i]]b]

Try it online!

Explanation:

Red[]
f: func [ n ] [
 a: n - 1 ; size - 1
 c: a * 2 + n ; total size of widht / height 
 b: collect [ ; create a block
 loop c [ ; composed of size - 1 rows
 keep pad/left copy "^/" c + 1 ; of empty lines of size c (and a newline)
 ]
 ]
 s: a * 1x0 + 1 ; starting coordinate
 foreach i [ 1x0 1 0x1 -1x1 -1x0 -1 0x-1 1x-1 ] [ ; for each offset for the 8 directions
 loop a [ ; repeat n - 1 times 
 b/(s/2)/(s/1): #"#" ; set the array at current coordinate to "#"
 s: s + i ; next coordinate
 ] 
 ]
 b ; return the block 
]
answered Nov 7, 2018 at 9:44
\$\endgroup\$
1
\$\begingroup\$

Perl 5, (削除) 201 (削除ここまで) (削除) 197 (削除ここまで) (削除) 188 (削除ここまで) (削除) 187 (削除ここまで) 186 bytes:

$a=<>;$b=3*$a-4;$c='$"x($e-$_)."#".$"x$f."#\n"';$e=($b-$a)/2+1;$d=$"x$e."#"x$a.$/;$f=$a;print$d,(map{(eval$c,$f+=2)[0]}1..$a-2),("#".$"x$b."#\n")x$a,(map{$f-=2;eval$c}reverse 1..$a-2),$d

Try it online!

Reads the size of the octagon from first line of STDIN.

answered Nov 8, 2018 at 4:31
\$\endgroup\$
2
  • \$\begingroup\$ Welcome to PPCG! You can probably shave off a few bytes here and there by using tricks found in this post. \$\endgroup\$ Commented Nov 8, 2018 at 5:14
  • \$\begingroup\$ @Mego Yep. I was able to save 4 bytes by using $" instead of " ". \$\endgroup\$ Commented Nov 8, 2018 at 17:14
1
\$\begingroup\$

Perl 5, 176 bytes

$f=$a=<>;$b=3*$a-4;$c='$"x($e-$_)."#".$"x$f."#\n"';$e=$a-1;$d=$"x$e."#"x$a.$/;print$d,(map{(eval$c,$f+=2)[0]}1..$a-2),("#".$"x$b."#\n")x$a,(map{$f-=2;eval$c}reverse 1..$a-2),$d

Based on Nathan Mills' answer above (which I have insufficient rep to comment on!).

$e can be simplified to $a-1 saving 6 bytes; $f can be chain assigned; saving two bytes; Not sure where the other two come from!

While $e can be replaced with $a-1 in the two places it occurs, the extra brackets needed means this only breaks even.

Ungolfed:

$f = $a = <>;
$b = 3 * $a - 4;
$c = '$"x($e-$_)."#".$"x$f."#\n"';
$e = $a - 1;
$d = $" x $e . "#" x $a . $/;
print $d, ( map { ( eval $c, $f += 2 )[0] } 1 .. $a - 2 ),
 ( "#" . $" x $b . "#\n" ) x $a,
 ( map { $f -= 2; eval $c } reverse 1 .. $a - 2 ), $d
Stephen
14.2k3 gold badges57 silver badges118 bronze badges
answered Nov 14, 2018 at 17:29
\$\endgroup\$
1
\$\begingroup\$

Perl 6, (削除) 76 (削除ここまで) 73 bytes

-3 bytes thanks to Jo King

{(' 'x$_-1~\*x$_,{S/.\S(.)+/* {' 'x0ドル}*/}...*)[^$_,$_ xx$_-2,[R,] ^$_;*]}

Try it online!

Returns a list of lines.

answered Nov 15, 2018 at 19:27
\$\endgroup\$
0
1
\$\begingroup\$

C (gcc), (削除) 158 (削除ここまで) (削除) 153 (削除ここまで) 150 bytes

  • Saved (削除) five (削除ここまで) eight bytes thanks to ceilingcat.
O,c,t,g;o(n){for(O=2*~-n,t=c=O+n;t--;puts(""))for(g=c;g--;)putchar(33-(!t|t>c-2?g<n-1|g>O:t<n-1|t>O?t+O-g&&t-O-g&&~c+g+t+n+n&&c-g-t+n-3+n:g&&g<c-1));}

Try it online!

answered Nov 8, 2018 at 13:34
\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat Thank you. \$\endgroup\$ Commented Jan 21, 2019 at 7:53
1
\$\begingroup\$

Vyxal RM, 4 bytes

S7ø∧

Try it Online!

new canvas builtin go brr

answered Jun 2, 2022 at 22:02
\$\endgroup\$
0
\$\begingroup\$

Python 3, 224 bytes

n=int(input())
z=" "*(n-1)+"#"*n+" "*(n-1)
print(z)
for i in range(n-2):print(" "*(n-i-2)+"#"+" "*(i*2+n)+"#")
print((("#"+" "*(n*3-4)+"#\n")*n)[:-1])
for i in range(n-3,-1,-1):print(" "*(n-i-2)+"#"+" "*(i*2+n)+"#")
print(z)

Try it online!

answered Nov 9, 2018 at 15:13
\$\endgroup\$
0
\$\begingroup\$

Perl 5, (削除) 170 (削除ここまで) (削除) 168 (削除ここまで) 166 bytes

$a=<>-1;$\="#\n";print$x=$_=$"x$a."#"x$a;if(s/^( *) #*/1ドル # 1ドル /){print}while (s/ #/# /){print}$z=$_;for(1..$a){print$_=$z}while(s/# (\s{$a})/ #1ドル/){print}print$x

This works by the magic of regex. The "if" is only needed to deal with the pathological case of n=2, which otherwise outputs something like:

 ##
 ##
# #
 ##

probably this can be coded away.

I think there may be a lot more to gain by creating a string up to the mid-point then reversing it. Of course we then need to insert/delete an extra space if n is odd (or use thin-space :p).

Ungolfed

$a = <> -1; # Subtracting one is very useful! 
$\ = "#\n"; # Every line ends with a '#' let perl provide. 
$x=$_ = " " x $a. "#" x $a; # The horiz line (one short) 
print; # print it plus the extra #
if(s/^( *) #*/1ドル # 1ドル /){print} # create a hole and remove a leading space(if n=2 this fails)
while (s/ #/# /){ # make the hole bigger 
 print; # and print (with a trailing #)
}
$z=$_; # store $_ for later use
for (1 .. $a) { # nice that we don't have to do 2..$a but not golf-nice 
 $_ =$z; # restore $_ (we could use $z but since we have
 print; # to restore somewhere, doing it here saves us bytes)
}
while (s/# (\s{$a})/ #1ドル/){ # now move the # to the right and reduce the trailing spaces 
 print;
}
print $x; # and finish...

I think this can probably be golfed a bit more, quite apart from significant changes like pushing onto $@ and printing that at the end.

[Golfed spaces around .. and moved print before assigns in two cases, saving on semicolons.]

answered Nov 15, 2018 at 13:03
\$\endgroup\$
1
  • \$\begingroup\$ saved 20 bytes reordering some instructions TIO, why \s and not just a space in last regex \$\endgroup\$ Commented Jan 22, 2019 at 10:56
0
\$\begingroup\$

J, (削除) 59 (削除ここまで) (削除) 45 (削除ここまで) 41 bytes

h=.|.,],~,:@{.#~_2+#
' #'{~h@|.@|:@h@=@i.

Try it online!

Will add explanation tonight.

answered Nov 16, 2018 at 8:03
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 98 bytes

$_=2x$_.1x$_.$/;s/2//;s/.$/ #/,y/1/ /while$a.=$_,$b=$_.$b,s/2[#1]/# /;$_=$a.$_ x("@F"-2).$b;y/2/ /

TIO

answered Jan 22, 2019 at 9:34
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.