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 code-golf so all usual golfing rules apply, and the shortest code (in bytes) wins.
-
1\$\begingroup\$ Can we use different output characters, or does it need to be consistent? \$\endgroup\$Emigna– Emigna2018年11月06日 18:13:56 +00:00Commented Nov 6, 2018 at 18:13
-
\$\begingroup\$ @Emigna Different characters are fine. \$\endgroup\$AdmBorkBork– AdmBorkBork2018年11月06日 18:26:21 +00:00Commented Nov 6, 2018 at 18:26
-
1\$\begingroup\$ Quite related. \$\endgroup\$Charlie– Charlie2018年11月07日 11:06:55 +00:00Commented Nov 7, 2018 at 11:06
24 Answers 24
05AB1E, 3 bytes
7ÝΛ
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.
-
\$\begingroup\$ Surely this should be 5 bytes? Or do code golf challenges see bytes and characters as interchangeable \$\endgroup\$Doug– Doug2018年11月07日 17:10:05 +00:00Commented Nov 7, 2018 at 17:10
-
3\$\begingroup\$ @Doug: It is 3 bytes in 05ab1e's code page \$\endgroup\$Emigna– Emigna2018年11月07日 17:11:53 +00:00Commented Nov 7, 2018 at 17:11
-
\$\begingroup\$ Oh, cool! Thanks for the docs link! \$\endgroup\$Doug– Doug2018年11月07日 17:58:40 +00:00Commented Nov 7, 2018 at 17:58
-
\$\begingroup\$ >:( damnit, adnan \$\endgroup\$ASCII-only– ASCII-only2018年11月11日 05:14:10 +00:00Commented Nov 11, 2018 at 5:14
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)
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} $$
-
\$\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\$Giuseppe– Giuseppe2018年11月06日 22:20:37 +00:00Commented 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\$Arnauld– Arnauld2018年11月06日 22:29:00 +00:00Commented 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\$Arnauld– Arnauld2018年11月06日 22:41:22 +00:00Commented 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\$Giuseppe– Giuseppe2018年11月06日 22:44:24 +00:00Commented Nov 6, 2018 at 22:44
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
-
3\$\begingroup\$ For those who prefer verbose Charcoal, that's
PolygonHollow(:*, InputNumber(), "#");. \$\endgroup\$Neil– Neil2018年11月06日 18:51:53 +00:00Commented Nov 6, 2018 at 18:51
Canvas, (削除) 15 (削除ここまで) (削除) 14 (削除ここまで) 12 bytes
×ばつ+:⤢n╬┼
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
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,,"")}
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!
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
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
If mixing output characters is OK.
Powershell, 91 bytes
param($n)($s=' '*--$n+'#'*$n+'#')
--$n..0+,0*$n+0..$n|%{' '*$_+"#$(' '*(3*$n-2*$_+2))#"}
$s
PowerShell, (削除) 107 (削除ここまで) 97 bytes
param($n)($z=$n-1)..1+,0*$n+1..$z|%{" "*$_+"#"+($x=" "*($z-$_))+(" ","#")[!($_-$z)]*($n-2)+"$x#"}
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
APL (Dyalog Unicode), 46 bytes SBCS
(' '@~5 6∊⍨1⊥⊢∘,)⌺3 3⊢<(⍉⌽⌊⊢)⍣2∘(∘.+⍨∘⍳ ×ばつ⊢)
This solution was provided by Adám - thanks!
My (almost) original solution:
APL (Dyalog Unicode), 61 bytes SBCS
(((⊃∘' #' ̈1+5∘=+6∘=)⊢)1⊥⊢∘,)⌺3 3⊢<(((⊖⌊⊢)⌽⌊⊢)(∘.+⍨(⍳ ×ばつ⊢)))
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.
-
1\$\begingroup\$ 46:
(' '@~5 6∊⍨1⊥⊢∘,)⌺3 3⊢<(⍉⌽⌊⊢)⍣2∘(∘.+⍨∘⍳¯2+3×⊢)\$\endgroup\$Adám– Adám2018年11月07日 13:51:23 +00:00Commented Nov 7, 2018 at 13:51 -
1
-
\$\begingroup\$ @Adám Thanks! I don't know how to edit the header, can you do it for me? \$\endgroup\$Galen Ivanov– Galen Ivanov2018年11月07日 14:01:38 +00:00Commented Nov 7, 2018 at 14:01
-
\$\begingroup\$ What do you mean by editing the header? \$\endgroup\$Adám– Adám2018年11月07日 14:22:39 +00:00Commented Nov 7, 2018 at 14:22
-
1
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);}
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
-
\$\begingroup\$ 173 bytes \$\endgroup\$ceilingcat– ceilingcat2022年04月25日 06:43:59 +00:00Commented Apr 25, 2022 at 6:43
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
On mobile, so not incredibly golfed.
-
\$\begingroup\$ You can remove the space after
(n+2*i). \$\endgroup\$Adalynn– Adalynn2018年11月08日 13:26:53 +00:00Commented Nov 8, 2018 at 13:26
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).
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]
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
]
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
Reads the size of the octagon from first line of STDIN.
-
\$\begingroup\$ Welcome to PPCG! You can probably shave off a few bytes here and there by using tricks found in this post. \$\endgroup\$user45941– user459412018年11月08日 05:14:11 +00:00Commented Nov 8, 2018 at 5:14
-
\$\begingroup\$ @Mego Yep. I was able to save 4 bytes by using
$"instead of" ". \$\endgroup\$Nathan Mills– Nathan Mills2018年11月08日 17:14:09 +00:00Commented Nov 8, 2018 at 17:14
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
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));}
-
\$\begingroup\$ @ceilingcat Thank you. \$\endgroup\$Jonathan Frech– Jonathan Frech2019年01月21日 07:53:38 +00:00Commented Jan 21, 2019 at 7:53
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)
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.]
-
\$\begingroup\$ saved 20 bytes reordering some instructions TIO, why
\sand not just a space in last regex \$\endgroup\$Nahuel Fouilleul– Nahuel Fouilleul2019年01月22日 10:56:04 +00:00Commented Jan 22, 2019 at 10:56
J, (削除) 59 (削除ここまで) (削除) 45 (削除ここまで) 41 bytes
h=.|.,],~,:@{.#~_2+#
' #'{~h@|.@|:@h@=@i.
Will add explanation tonight.
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/ /