Hexagolf: Validagons

13

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.

Beta Decay

Posted 2016-09-09T09:27:21.137

Reputation: 21 478

4Mathematica one liner incoming. – ThreeFx – 2016-09-09T09:48:02.513

1I think you might want to add two test cases: One without leading spaces, for example: 5 6 7\n8 9 0 1\n2 3 4 5 6\n7 8 9 0\n1 2 3 and 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 with s to 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. – Kevin Cruijssen – 2016-09-09T10:02:06.017

Is the example with the periods necessarily falsey ? The missing period is a space which is one of the valid characters that can make up the hexagon, – Ton Hospel – 2016-09-09T11:33:18.240

1@TonHospel I think the idea is that the outline is an unbroken regular hexagon. – Martin Ender – 2016-09-09T11:34:51.967

All angles in the shape may not be equal for example, the following shape is valid input: This phrasing seems misleading. Surely we are detecting regular hexagons? Do you mean to write that the symbols don’t necessarily have angular symmetry? – Lynn – 2016-09-09T11:38:30.307

@Lynn It's more that all input will not necessarily be a regular shape – Beta Decay – 2016-09-09T11:41:05.050

Ah. That seems like a strange thing to specify. Anyway, I agree with Ton Hospel’s complaint. You need to specify that we’re interested in non-space printable ASCII characters – Lynn – 2016-09-09T11:43:34.063

@Lynn That isn't the case, though as you have spaces in the ring (the third truthy example) – Beta Decay – 2016-09-09T11:45:06.660

Okay, then you need to specify that we’re interested in hexagons with a space-free border, like Martin says. – Lynn – 2016-09-09T11:49:20.210

What about input with a single non-space but also a non-zero number of spaces (and/or newlines) ? (so not *JUST* a single character) – Ton Hospel – 2016-09-09T12:04:58.680

@TonHospel Well those are leading/trailing spaces, so it's stilk effectively a single character – Beta Decay – 2016-09-09T12:16:04.583

the 3rd truthy example shows just the outline of the hexagon, which depending on your interpretation does not comply with the rule "The shapes will only ever contain printable ASCII characters." What should we do with a shape that has a hexagonal outline and is partially filled in, for example it also has a diagonal? Or a hexagon that is solidly filled on one side and just an outline on the other? – Level River St – 2016-09-09T18:02:25.100

@LevelRiverSt You can expect a hexagon like http://pastebin.com/kcFRBbgi

– Beta Decay – 2016-09-09T18:19:23.230

"All shape inputs will be on a space separated grid" conflicts with test case labeled "This shape is not on a space separated grid." – DLosc – 2016-09-09T22:20:36.237

Some more falsey test cases: http://pastebin.com/fHnfHPiJ

– DLosc – 2016-09-10T02:20:26.153

Answers

2

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 

Vlo

Posted 2016-09-09T09:27:21.137

Reputation: 806

@DLosc You didn't have the generate function defined. Try this link: http://goo.gl/9MtCLg 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)))

– Vlo – 2016-09-10T06:19:31.720

Ah, I missed that part. Thanks. – DLosc – 2016-09-10T19:22:06.067

1

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;
}

Neil

Posted 2016-09-09T09:27:21.137

Reputation: 95 035

I found a bug: input " x\n g g\ng g g\n g g" should give false, but gives true. – DLosc – 2016-09-10T02:31:07.083

@DLosc I take it that's two spaces before the x? – Neil – 2016-09-10T10:26:34.120

@DLosc I think I have it fixed now, cost me 30 bytes though... – Neil – 2016-09-10T11:58:51.803

1

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. :^)

DLosc

Posted 2016-09-09T09:27:21.137

Reputation: 21 213

1

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*$/

Ton Hospel

Posted 2016-09-09T09:27:21.137

Reputation: 14 114