Challenge
Given an ASCII art shape, you must find out whether the shape is a regular hexagon or not.
Hexagons
A regular hexagon is defined using two rules:
- It has six sides
- Each side has equal numbers of characters
For example, the following shape is regular but it doesn't have six sides and so is not a regular hexagon:
B a a h
s a i d
y o u r
g a o t
Similarly, the following shape has six sides but has sides of different lengths and so is not a regular hexagon:
* *
* * *
* * * *
* * *
* *
However, the following shape has six sides and all of the sides have the same number of characters, so it is a regular hexagon:
T h e
h e x a
g o n s a
r e c o
m i n
Rules
Output should be a truthy or a falsey value (truthy if the shape is a regular hexagon, falsey if not).
The shapes will only ever contain printable ASCII characters.
The border of the shape will never contain spaces. If it does, you can return falsey.
There can be arbitrary amounts of whitespace before and/or after the shape.
All angles in the shape may not be equal for example, the following shape is valid input:
. . .
. . .
. . . . .
. . . .
. . .
It will return a falsey value.
All shape inputs will be on a space separated grid. Hexagonal input will be on a staggered grid (each line is offset from the next).
Examples
Truthy
The following shapes should return truthy values:
# _
+ + +
9 :
5 6 7
8 9 0 1
2 3 4 5 6
7 8 9 0
1 2 3
t h i s
i s
a h
e x
a g
o n
! ! ! !
5 6 7
8 9 0 1
2 3 4 5 6
7 8 9 0
1 2 3
Falsey
The following should return falsey values
r e c t a
n g l e s
h e l l o
w o r l d s
t h i s i s b
e t a d e c
a y n o w
*
* *
* * *
.....
.......
.........
.......
.....
This shape is not on a space separated grid and is not staggered.
* * * *
---------
* * * * * *
-------------
* * * * * *
---------
* * * *
5 6 7
8 9 0 1
2 3 4 5 6
7 8 9 0
1 2 3
For single character inputs, your program may output either truthy or falsey:
&
Winning
The shortest program in bytes wins.
4 Answers 4
R, 184 bytes
Golfed, could probably be golfed by a few bytes
function(m){e=min;f=max;l=length;v=which(m!=" ",T);a=v[,1];n=l(v[a==1,2]);u=(v[a==e(a),2]);all(u==v[a==f(a),2])&all(c(e(d<-v[a==ceiling(f(v[,1])/2),2]),f(d))==c(u[1]-n+1,u[l(u)]+n-1))}
Ungolfed, very messy, more like half way golfed
f=function(m) {
v = which(m!=" ",T)
a = v[,1]
n = length(v[a==1,2])
u=(v[a==min(a),2])
c1 = all(u==v[a==max(a),2])
d = v[a==ceiling(max(v[,1])/2),2]
c2 = all(c(min(d), max(d))==c(u[1]-n+1,u[length(u)]+n-1))
c1 & c2
}
Since the input format is unspecified, Input needs to be specified in an R array format, looking something like this.
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] " " " " "5" " " "6" " " "7" " " " "
[2,] " " "8" " " "9" " " "0" " " "1" " "
[3,] "2" " " "3" " " "4" " " "5" " " "6"
[4,] " " "7" " " "8" " " "9" " " "0" " "
[5,] " " " " "1" " " "2" " " "3" " " " "
Here is a generator function that generates the input. The generator doesn't generate an object that is fed into hexagon check function, but rather the code specifying the array (effectively the same thing). So this should not count as parsing the text. Remember that I'm not inputting text, but rather an array structure.
generate = function(x) {
s = strsplit(strsplit(x, "\n")[[1]], "")
m = max(sapply(s, length))
dput(do.call(rbind, lapply(s, function(x) c(x, rep(" ", m-length(x))))))
}
For example, the generated code would be: structure(c(" ", " ", "2", " ", " ", " ", "8", " ", "7", " ", "5", " ", "3", " ", "1", " ", "9", " ", "8", " ", "6", " ", "4", " ", "2", " ", "0", " ", "9", " ", "7", " ", "5", " ", "3", " ",
"1", " ", "0", " ", " ", " ", "6", " ", " "), .Dim = c(5L, 9L
)) which is identical to array(c(" ", " ", "2", " ", " ", " ", "8", " ", "7", " ", "5", " ", "3", " ", "1", " ", "9", " ", "8", " ", "6", " ", "4", " ", "2", " ", "0", " ", "9", " ", "7", " ", "5", " ", "3", " ", "1", " ", "0", " ", " ", " ", "6", " ", " "), dim = c(5, 9))
Hopefully this input method is in compliance with the rules.
Here are the test cases
x1 =
" 5 6 7
8 9 0 1
2 3 4 5 6
7 8 9 0
1 2 3"
x2 =
" # _
+ + +
9 :"
x3 =
" t h i s
i s
a h
e x
a g
o n
! ! ! !"
x4 =" 5 6 7
8 9 0 1
2 3 4 5 6
7 8 9 0
1 2 3"
x5 = "r e c t a
n g l e s"
x6 = " h e l l o
w o r l d s
t h i s i s b
e t a d e c
a y n o w"
x7 =" *
* *
* * *"
x8 =" .....
.......
.........
.......
....."
Generate input arrays
sapply(mget(paste("x", 1:8, sep = "")), generate)
Test for hexagon
sapply(.Last.value , f)
x1 x2 x3 x4 x5 x6 x7 x8
TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
-
\$\begingroup\$ @DLosc You didn't have the generate function defined. Try this link: tutorialspoint.com/… You can also check with a manual input like
f(array(c(" ", " ", "2", " ", " ", " ", "8", " ", "7", " ", "5", " ", "3", " ", "1", " ", "9", " ", "8", " ", "6", " ", "4", " ", "2", " ", "0", " ", "9", " ", "7", " ", "5", " ", "3", " ", "1", " ", "0", " ", " ", " ", "6", " ", " "), dim = c(5, 9)))\$\endgroup\$Vlo– Vlo2016年09月10日 06:19:31 +00:00Commented Sep 10, 2016 at 6:19 -
\$\begingroup\$ Ah, I missed that part. Thanks. \$\endgroup\$DLosc– DLosc2016年09月10日 19:22:06 +00:00Commented Sep 10, 2016 at 19:22
JavaScript (ES6), 214 bytes
(s,a=s.split`\n`,n=a[l=a.length>>1].match(r=/(?=\S).*\S/),i=n.index)=>!/\S( )*\S/.test(s)&&!a.some((s,j)=>(m=r.exec(s))&&(k=m.index)<i+(j<l?j=l-j:j-=l)|k+(m=m[0].length)+j>i+n[0].length|k+i+j&1|j%l<1&m+j+j!=l*4+1)
Where \n represents a literal newline character. Ungolfed:
function validhex(s) {
if (/S( )*/S/.test(s)) return false;
var a = s.split("\n");
var l = Math.floor(a.length / 2);
var n = a[l].match(/(?=\S).*\S/);
for (var j = -l; j <= l; j++) {
var m = a[j+l].match(/(?=\S).*\S/);
if (!m) continue;
if (m.index < n.index + Math.abs(j)) return false;
if (m.index + m[0].length + Math.abs(j) > n.index + n[0].length) return false;
if ((m.index + n.index + j) % 2) return false;
if (j % l) continue;
if (m[0].length != l * 4 + 1 - 2 * Math.abs(j)) return false;
}
return true;
}
-
\$\begingroup\$ I found a bug: input
" x\n g g\ng g g\n g g"should give false, but gives true. \$\endgroup\$DLosc– DLosc2016年09月10日 02:31:07 +00:00Commented Sep 10, 2016 at 2:31 -
\$\begingroup\$ @DLosc I take it that's two spaces before the
x? \$\endgroup\$Neil– Neil2016年09月10日 10:26:34 +00:00Commented Sep 10, 2016 at 10:26 -
\$\begingroup\$ @DLosc I think I have it fixed now, cost me 30 bytes though... \$\endgroup\$Neil– Neil2016年09月10日 11:58:51 +00:00Commented Sep 10, 2016 at 11:58
SnakeEx, 200 bytes
The right language for the job... sort of.
m:{v<>}{r<RF>2P}{r<R>2P}{h<RF>1P}{w<>}{l<RF>2P}{l<R>2P}{h<.>1}
w:{u<>P}{v<>}
v:{e<L>}{u<R>1}
u:.*{e<>}
e:.$
r:[^ ]+
h:([^ ] )+
l:({c<.>}[^ ])+{c<.>}
c:{b<B>}(. )+{x<>LP}{s<>}
b:.{s<>}
s:[^\!-\~]*$
x:.
SnakeEx is a language from the 2-D Pattern Matching challenge. It ought to be really good at this task, but unfortunately all the corner cases really bloated the code. I also turned up a couple of interpreter bugs. Still, it was a fun challenge.
m is the main snake that calls all the others to do the actual work. It matches starting at the top right corner of the hexagon and going clockwise. Numbered groups are used to verify that the diagonal side lengths are all equal and that the horizontal side length matches the height of the whole figure. I could write a more detailed explanation, but I've spent the last two days dealing with corner cases, so just try it out for yourself here. :^)
Perl, (削除) 127 (削除ここまで) (削除) 125 (削除ここまで) (削除) 124 (削除ここまで) 121 bytes
Includes +4 for -0p
Give input on STDIN
#!/usr/bin/perl -0p
/ *(.*\S)/;$a=join'\S *
1円',map$"x(abs).'\S '.(/$n/?'\S ':'. ')x(2*$n-1-abs),-($n=1ドル=~y/ //)..$n;$_=/^$`( *)$a\S\s*$/
5 6 7\n8 9 0 1\n2 3 4 5 6\n7 8 9 0\n1 2 3and one with an additional space leading for one of the rows:ss5 6 7\nss8 9 0 1\n2 3 4 5 6\ns7 8 9 0\nss1 2 3(leading spaces are replaced withsto make it a bit more clear in this unformatted form). All 10 of your test cases are validating correctly with my code currently, but these two cases would fail with the approach I used. \$\endgroup\$