Highlight the Bounding Box, Part II: Hexagonal Grid

24

1

You're given a hexagonal grid of the characters . and #, like this:

 . . . . . . . .
. . . . # . . . 
 . # . . . # . .
. . . # . . . . 
 . . . . . # . .
. . . . . . . . 

Your task is to fill the entire axis-aligned bounding box of the # with further #:

 . . . . . . . .
. . # # # # . . 
 . # # # # # . .
. . # # # # # . 
 . . # # # # . .
. . . . . . . . 

The axis-aligned bounding box is the smallest convex hexagonal shape which contains all the #. Note that in the case of the hexagonal grid, there are three axes to consider (W/E, SW/NE, NW/SE):

enter image description here

Here is another example to show that in some cases, one or more sides will contain only one #:

. . . . . . . .         . . . . . . . . 
 . # . . . . . .         . # # # # . . .
. . . . . # . .         . . # # # # . . 
 . . # . . . . .         . . # # # . . .
. . . . . . . .         . . . . . . . . 

You can either view these as hexagons with degenerate sides, or you can draw the bounding box around them, like I have done above, in which case they are still hexagons:

enter image description here

Too hard? Try Part I!

Rules

You may use any two distinct non-space printable ASCII characters (0x21 to 0x7E, inclusive), in place of # and .. I'll continue referring to them as # and . for the remainder of the specification though.

Input and output may either be a single linefeed-separated string or a list of strings (one for each line), but the format has to be consistent.

You may assume that the input contains at least one # and all lines are the same length. Note that there are two different "kinds" of lines (starting with a space or a non-space) - you may not assume that the input always starts with the same type. You may assume that the bounding box always fits inside the grid you are given.

You may write a program or a function and use any of the our standard methods of receiving input and providing output.

You may use any programming language, but note that these loopholes are forbidden by default.

This is , so the shortest valid answer – measured in bytes – wins.

Test Cases

Each test case has input and output next to each other.

#    #

 . .      . . 
# . #    # # #
 . .      . . 

 . #      . # 
. . .    . # .
 # .      # . 

 # .      # . 
. . .    . # .
 . #      . # 

 # .      # . 
# . .    # # .
 . #      # # 

 . #      # # 
# . .    # # #
 . #      # # 

. . #    . # #
 . .      # # 
# . .    # # .

# . .    # # .
 . .      # # 
. . #    . # #

. . . . . . . .         . . . . . . . . 
 . . # . # . . .         . . # # # . . .
. . . . . . . .         . . . # # . . . 
 . . . # . . . .         . . . # . . . .

. . . . . . . .         . . . . . . . . 
 . . # . . . # .         . . # # # # # .
. . . . . . . .         . . . # # # # . 
 . . . # . . . .         . . . # # # . .

. . . . . . . .         . . . . . . . . 
 . # . . . . . .         . # # # # . . .
. . . . . # . .         . . # # # # . . 
 . . . . . . . .         . . . . . . . .

. . . . . . . .         . . . . . . . . 
 . # . . . . . .         . # # # # . . .
. . . . . # . .         . . # # # # . . 
 . . # . . . . .         . . # # # . . .

. . . . # . . .         . . # # # # . . 
 . # . . . # . .         . # # # # # . .
. . . # . . . .         . . # # # # # . 
 . . . . . # . .         . . # # # # . .

Martin Ender

Posted 2016-08-29T11:07:19.077

Reputation: 184 808

1My head is spinning trying to find any obvious pattern. You said 'hexagonal' but there are only two inputs form into hexagons in the test cases. I'm lost. – Anastasiya-Romanova 秀 – 2016-08-29T12:04:54.843

1@Anastasiya-Romanova秀 If you picture the shape as going through the centres of the outer characters, then yes some hexagons will have degenerate sides (like in the rectangular grid, where you can get cases where the rectangle reduces to a line). However, if you draw the rectangle around the characters (as I have done in the diagram), all the examples are hexagons (some of which have very short sides). – Martin Ender – 2016-08-29T12:06:55.110

1@Anastasiya-Romanova秀 Does the new diagram help? – Martin Ender – 2016-08-29T12:13:07.170

3I! looks like II if I have the wrong glasses on.. – Neil – 2016-08-29T12:17:52.430

1@Neil Or, you know, too much alcohol ;) – ThreeFx – 2016-08-29T12:35:27.920

I don't understand these boxes fine. Do I have to process multiple boxes with my program, line by line, column by column? Yea, I'm beginner and english isn't my first language :p – Hydroper – 2016-08-29T13:05:06.573

1@nicematt No, you take a single grid (e.g. the very first code block in the challenge) and return a single grid (e.g. the second code block in the challenge). The final code block is just compressed a bit to save space for the large number of test cases. Your program should be able to receive any of the grids on the left and produce the corresponding grid on the right. – Martin Ender – 2016-08-29T13:08:34.217

1Sorry @MartinEnder, I still don't get it. You don't have to explain anything anymore, let's see how one approaches this challenge, maybe I can get some ideas. Thanks. – Anastasiya-Romanova 秀 – 2016-08-29T13:21:28.670

@MartinEnder Can I right-pad? – Leaky Nun – 2016-08-29T13:56:48.580

@LeakyNun Yes: "You may assume that [...] all lines are the same length." – Martin Ender – 2016-08-29T13:58:04.860

Can I also take input without the spaces? – ThreeFx – 2016-08-29T16:31:43.033

@ThreeFx No, because then there's no way to tell whether the first row was indented or not. – Martin Ender – 2016-08-29T16:34:13.527

Technically I could, since they would have different length, but I get what you mean (it's not a costly workaround relatively speaking). – ThreeFx – 2016-08-29T17:26:27.697

@ThreeFx They wouldn't always have different lengths (see for instance the 8x4-sized test cases at the end). – Martin Ender – 2016-08-29T17:37:23.387

1I know it's highly unlikely but I want to see a Hexagony solution – CAD97 – 2016-08-29T23:56:30.340

Actually a quincunx lattice and not a hexagonal one, the angles are slightly off to be hexagonal. But +1 for fun problem. – mathreadler – 2016-08-30T06:22:47.867

1@mathreadler I never said they were regular hexagons. ;) – Martin Ender – 2016-08-30T06:25:25.603

What if the total field would need to grow to contain the hexagon ? Think of an input consisting of a narrow high vertical line – Ton Hospel – 2016-09-01T11:09:17.030

@TonHospel Ohhh, very good catch. I didn't consider that at all (and apparently no one else either so far). As I doubt any of the existing answers will handle that correctly, I'll say you can assume that won't happen. – Martin Ender – 2016-09-01T11:26:45.910

Answers

7

Pyth, 82 71 bytes

L,hbebMqH@S+GH1KhMyJs.e,Lkfq\#@bTUb.zA,ySm-FdJySsMJj.es.eXW&&gKkgG-kYgH+kYZ\.\#b.z
MqH@S[hGHeG)1j.es.eXW&&ghMJs.e,Lkfq\#@bTUb.zkgSm-FdJ-kYgSsMJ+kYZ\.\#b.z

Try it online!

Explanation

  • Let A be the point with the lowest y-coordinate and B the point with the highest y-coordinate.

  • Let C be the point with the lowest (x-value minus y-value) and D the point with the highest.

  • Let E be the point with the lowest (x-value plus y-value) and F the point with the highest.

Then it is equivalent to finding the coordinates which the y-coordinate is between A and B, the x-value minus y-value is between C and D, and the x-value plus y-value is between E and F.

Leaky Nun

Posted 2016-08-29T11:07:19.077

Reputation: 45 011

the first time when I could post a solution earlier, if only the SE android app could correctly handle tab characters (for some reason they disappeared when pasted) :/ – Display Name – 2016-08-29T15:35:43.850

@SargeBorsch I'm sorry :( – Leaky Nun – 2016-08-29T15:41:57.720

haha why, it's SE Android app that made me fail :D – Display Name – 2016-08-29T15:52:22.747

6

Haskell, 256 254 243 bytes

import Data.List
f=z(\l->(,).(,))[0..]l)[0..]
q l=m(m(\e->min(snd e).(".#"!!).fromEnum.and.z($)(m(\x y->y>=minimum x&&y<=maximum x).transpose.m b.filter((==)'#'.snd).concat$l)$b e))l
b=(m uncurry[const,(-),(+)]<*>).pure.fst
z=zipWith
m=map
q.f

Thanks @Damien for golfing f!

Input is taken as list of list of chars, output is provided the same way.

Soo this was a beast to write. It's based on LeakyNun's idea using a maximum and minimum based filtering on the coordinates of the items.

I'm really surprised by the fact that m=map actually saves bytes since it seems so costly.


Explanation:

Here's a slightly less butchered version (emphasis on slightly):

import Data.List
f=zipWith(\y l->zipWith(\x e->((y,x),e))[0..]l)[0..]
p=map(\x y->y>=minimum x&&y<=maximum x).transpose.map b.filter((==)'#'.snd).concat
q l=map(map(\e->min(snd e).(".#"!!).fromEnum.and.zipWith($)(p$l)$b e))l
b=(map uncurry[const,(-),(+)]<*>).pure.fst
  • f is a function which assigns each char an index (y-index, x-index) while preserving the original structure of the list.

  • b: Given an item of the indexed list, b computes [y-index, y - x, y + x].

  • p: Given the indexed field, return 3 functions Int -> Bool, the first of which is the check of the y-index, the second of the difference and the third of the sum. min(snd e) takes care of the spaces (a space is smaller than both). This function is inlined in the golfed code.

  • q given the indexed field, change all necessary . to # by checking if that specific field return True to every test function.

The final solution is then the composition of q and f.

ThreeFx

Posted 2016-08-29T11:07:19.077

Reputation: 1 435

1f=z(\y->z((,).(,)y)[0..])[0..] – Damien – 2016-09-01T07:06:34.627

or h x=z x[0..] f=h$h.curry(,) – Damien – 2016-09-01T07:22:41.647

5

Python 3, 380 378 348 346 bytes

Note that the indentation is with tabs, not spaces.

Golfed version:

def s(i):
    L=i.splitlines();E=enumerate;A=lambda x,y:(y,x+y,x-y);N=(2**64,)*3;X=(-2**64,)*3
    for y,l in E(L):
        for x,c in E(l):
            if c=='#':p=A(x,y);X=tuple(map(max,X,p));N=tuple(map(min,N,p))
    R=''
    for y,l in E(L):
        for x,c in E(l):
            if c!='.':R+=c
            else:p=A(x,y);f=all(N[j]<=p[j]<=X[j]for j in range(0,3));R+='.#'[f]
        R+='\n'
    return R

Test it on Ideone

Explanation (for ungolfed version below):

All processing is done without any conversion, space characters are simply skipped.
Function axes_pos calculates 3-tuple of imaginary "3D" coordinates, they are accumulated into (element wise) minimum and maximum 3-tuples (bmin, bmax) for all # characters.

Coordinates are calculated in def axes_pos(x, y): return y, x + y, lc - y + x;
where X counts from 0 to right, and Y counts from 0 to bottom (from first line to last).
First imaginary coordinate is basically Y, because it's obvious why. Its axe is orthogonal to green bounds (in the OP's pictures)
Second is orthogonal to red bounds, and third is orthogonal to blue bounds.

In the second pass, replacement is done for all . characters which "3D" coordinates fall into bmin..bmax range, element wise — this is checked in this expression all(bmin[j] <= p[j] <= bmax[j] for j in range(0, 3)).

Ungolfed version with tests, also on Ideone:

def solve(i):
    ls = i.splitlines()
    lc = len(ls)

    def axes_pos(x, y):
        return y, x + y, lc - y + x

    I = 2 ** 64
    bmin = (I, I, I)
    bmax = (0, 0, 0)

    for y, line in enumerate(ls):
        for x, char in enumerate(line):
            if char != '#': continue
            p = axes_pos(x, y)
            bmax = tuple(map(max, bmax, p))
            bmin = tuple(map(min, bmin, p))

    result = ''
    for y, line in enumerate(ls):
        for x, char in enumerate(line):
            if char != '.':
                result += char
            else:
                p = axes_pos(x, y)
                f = all(bmin[j] <= p[j] <= bmax[j] for j in range(0, 3))
                result += '#' if f else char
        result += '\n'

    return result


def run_test(a, b):
    result = solve(a)
    if result != b:
        raise AssertionError('\n' + result + '\n\nshould be equal to\n\n' + b)


def run_tests():
    run_test(
        "#\n",

        "#\n")

    run_test(
        " . . \n"
        "# . #\n"
        " . . \n",

        " . . \n"
        "# # #\n"
        " . . \n")

    run_test(
        " . # \n"
        ". . .\n"
        " # . \n",

        " . # \n"
        ". # .\n"
        " # . \n")

    run_test(
        " # . \n"
        ". . .\n"
        " . # \n",

        " # . \n"
        ". # .\n"
        " . # \n")

    run_test(
        " # . \n"
        "# . .\n"
        " . # \n",

        " # . \n"
        "# # .\n"
        " # # \n")

    run_test(
        " . # \n"
        "# . .\n"
        " . # \n",

        " # # \n"
        "# # #\n"
        " # # \n")

    run_test(
        ". . . . . . . . \n"
        " . . # . # . . .\n"
        ". . . . . . . . \n"
        " . . . # . . . .\n",

        ". . . . . . . . \n"
        " . . # # # . . .\n"
        ". . . # # . . . \n"
        " . . . # . . . .\n")

    run_test(
        ". . . . . . . . \n"
        " . . # . . . # .\n"
        ". . . . . . . . \n"
        " . . . # . . . .\n",

        ". . . . . . . . \n"
        " . . # # # # # .\n"
        ". . . # # # # . \n"
        " . . . # # # . .\n")

    run_test(
        ". . . . . . . . \n"
        " . # . . . . . .\n"
        ". . . . . # . . \n"
        " . . . . . . . .\n",

        ". . . . . . . . \n"
        " . # # # # . . .\n"
        ". . # # # # . . \n"
        " . . . . . . . .\n")

    run_test(
        ". . . . . . . . \n"
        " . # . . . . . .\n"
        ". . . . . # . . \n"
        " . . # . . . . .\n",

        ". . . . . . . . \n"
        " . # # # # . . .\n"
        ". . # # # # . . \n"
        " . . # # # . . .\n")

    run_test(
        ". . . . # . . . \n"
        " . # . . . # . .\n"
        ". . . # . . . . \n"
        " . . . . . # . .\n",

        ". . # # # # . . \n"
        " . # # # # # . .\n"
        ". . # # # # # . \n"
        " . . # # # # . .\n")


if __name__ == '__main__':
    run_tests()
Update 1:

Removed unnecessary -1 for third imaginary coordinate, because it doesn't change anything

Update 2,3:

Partially implemented improvements suggested by Leaky Nun + my own too.

Display Name

Posted 2016-08-29T11:07:19.077

Reputation: 654

Do we basically use the same algorithm? Could you append an explanation? – Leaky Nun – 2016-08-29T15:42:57.177

1def A(x,y):return y,x+y,len(L)-1-y+x -> A=lambda x,y:(y,x+y,len(L)-1-y+x) – Leaky Nun – 2016-08-29T15:49:05.547

Also, list comprehensions could help you golf some bytes off.

– Leaky Nun – 2016-08-29T15:49:43.653

@LeakyNun hmm I guess the algorithm is similar. (Can't really read Pyth, but sounds similar to your explanation) I'll add the explanation soon. – Display Name – 2016-08-29T15:51:56.917

@LeakyNun added explanation – Display Name – 2016-08-29T16:01:23.470

Can you explain how the imaginary 3D coordinates are generated? – Leaky Nun – 2016-08-29T16:02:28.887

@LeakyNun yes, added this. Not sure if I explained it good though. – Display Name – 2016-08-29T16:13:14.340

Would you mind if I port my Pyth answer to Python? – Leaky Nun – 2016-08-29T16:17:38.240

@LeakyNun No problem. I know it'd probably be shorter than this. – Display Name – 2016-08-29T16:32:40.137

1I think you can turn len(L)-y+x into x-y – Leaky Nun – 2016-08-29T16:44:46.647

@LeakyNun oh yeah. however, then sometimes it'll be negative, and I think I can construct a test when it'll fail (but the tests from the question do work). So the correct minimum should be something like -inf. But it's shorter overall. – Display Name – 2016-08-29T16:51:07.027

1You can take in list of lines – Leaky Nun – 2016-08-29T17:14:59.347

5

Jelly, 45 3513 42 41 bytes

Ṁ€»\
ṚÇṚ«Çṁ"
ŒDṙZL$ÇṙL’$ŒḌ«Ç
ṚÇṚ«Ç
n⁶aÇo⁶

This is a list of links; the last one has to be called on the input to produce the output.

I/O is in form of string arrays, where . indicates empty and @ indicates filled.

Try it online! or verify all test cases.

Background

Let's consider the following example.

. . . . . . . . 
 . @ . . . . . .
. . . . . @ . . 
 . . @ . . . . .

By drawing a pair or parallel lines – the closest pair that encloses all filled positions – in each of the three directions, we can determine the hexagonal bounding box.

In the implementation, we replace all characters between those two lines with @, and everything outside these lines with ., with the possible exception of diagonals that only contains spaces).

For the horizontal axis, this gives

................
@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@

for the falling diagonal axis, it gives

..@@@@@@@......
...@@@@@@@......
....@@@@@@@.....
 ....@@@@@@@....

and for the raising diagonal axis, it gives

....@@@@@@@@@...
...@@@@@@@@@....
..@@@@@@@@@....
.@@@@@@@@@.... .

By taking the character-wise minimum of all three, since . < @, we get

...............
...@@@@@@@......
....@@@@@@@....
 ....@@@@@.... .

All that's left to do is restoring the spaces.

How it works

n⁶aÇo⁶           Main link. Argument: A (array of strings)

n⁶               Not-equal space; yield 0 for spaces, 1 otherwise.
  aÇ             Take the logical AND with the result the 4th helper link.
                 This will replace 1's (corresponding to non-space characters) with
                 the corresponding character that result from calling the link.
    o⁶           Logical OR with space; replaces the 0's with spaces.
ṚÇṚ«Ç            4th helper link. Argument: A

Ṛ                Reverse the order of the strings in A.
 Ç               Call the 3rd helper link.
  Ṛ              Reverse the order of the strings in the resulting array.
    Ç            Call the 3rd helper link with argument A (unmodified).
   «             Take the character-wise minimum of both results.
ŒDṙZL$ÇṙL’$ŒḌ«Ç  3rd helper link. Argument: L (array of strings)

ŒD               Yield all falling diagonals of L. This is a reversible operation,
                 so it begins with the main diagonal.
   ZL$           Yield the length of the transpose (number of columns).
  ṙ              Shift the array of diagonals that many units to the left.
                 This puts the diagonals in their natural order.
      Ç          Call the helper link on the result.
        L’$      Yield the decremented length (number of columns) of L.
       ṙ         Shift the result that many units to the left.
                 This puts the changed diagonals in their original order.
           ŒḌ    Undiagonal; reconstruct the string array.
              Ç  Call the 2nd helper link with argument L (unmodified).
             «   Take the character-wise minimum of both results.
ṚÇṚ«Çṁ"          2nd helper link. Argument: M (array)

Ṛ                Reverse the rows of M.
 Ç               Call the 1st helper link on the result.
  Ṛ              Reverse the rows of the result.
    Ç            Call the 1nd helper link with argument M (unmodified).
   «             Take the minimum of both results.
     ṁ"          Mold zipwith; repeat each character in the result to the left
                 as many times as needed to fill the corresponding row of M.
Ṁ€»\             1st helper link. Argument: N (array)

Ṁ€               Take the maximum of each row of N.
  »\             Take the cumulative maxima of the resulting characters.

Dennis

Posted 2016-08-29T11:07:19.077

Reputation: 196 637

2

Python, 237 230 bytes

7 bytes thanks to Dennis.

def f(a):i=range(len(a[0]));j=range(len(a));b,c,d=map(sorted,zip(*[[x,x+y,x-y]for y in i for x in j if"?"<a[x][y]]));return[[[a[x][y],"#"][(a[x][y]>" ")*(b[0]<=x<=b[-1])*(c[0]<=x+y<=c[-1])*(d[0]<=x-y<=d[-1])]for y in i]for x in j]

Port of my answer in Pyth.

Takes array of lines as input, outputs 2D array of characters.

Leaky Nun

Posted 2016-08-29T11:07:19.077

Reputation: 45 011

2

Perl, 128 126 bytes

Includes +6 for -0F\n

Run with input on STDIN. Use 1 for filled, 0 for empty. Lines do not have to be padded with spaces at the end:

perl -M5.010 hexafill.pl
 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 
 0 1 1 1 1 1 0 0
0 0 1 1 1 1 1 0 
 0 0 1 1 1 1 0 0
0 0 0 0 0 0 0 0 
^D

hexafill.pl

#!/usr/bin/perl -0F\n
$-=map{s%$=%$=^!map{/$/;grep{pos=$`;$=?$_|="!"x$`.1:!/\b.*\G./}${--$@}}@F-$-+pos,$-+pos,$-%eeg;--$-;$=||say}@F while$=--

Uses cube coordinates. Determine maximum and minimum during the $= == 1 loop and fills coordinates between these bounds during the $= == 0 loop. The first 58 loops are pointless and are only there to fill $- with the number of lines

Ton Hospel

Posted 2016-08-29T11:07:19.077

Reputation: 14 114

1

TSQL, 768 bytes

I wrote a query to solve this - which I found quite difficult. It is not able to compete with all the excellent shorter answer. But wanted to post it anyway for those interested. Sorry about the length of the answer - hoping codegolf is also about different approachs.

Golfed:

DECLARE @ varchar(max)=
'
. . . . # . . . 
 . # . . . # . .
. . . # . . . . 
 . . . . . # . .
. . . . . . . . 
'

;WITH c as(SELECT cast(0as varchar(max))a,x=0,y=1,z=0UNION ALL SELECT SUBSTRING(@,z,1),IIF(SUBSTRING(@,z,1)=CHAR(10),1,x+1),IIF(SUBSTRING(@,z,1)=CHAR(10),y+1,y),z+1FROM c WHERE LEN(@)>z)SELECT @=stuff(@,z-1,1,'#')FROM c b WHERE((exists(SELECT*FROM c WHERE b.y=y and'#'=a)or exists(SELECT*FROM c WHERE b.y<y and'#'=a)and exists(SELECT*FROM c WHERE b.y>y and'#'=a))and a='.')and(exists(SELECT*FROM c WHERE b.x<=x-ABS(y-b.y)and'#'=a)or exists(SELECT*FROM c WHERE b.x<=x+y-b.y and a='#'and b.y<y)and exists(SELECT*FROM c WHERE b.x<=x+b.y-y and a='#'and b.y>y))and(exists(SELECT*FROM c WHERE b.x>=x+ABS(y-b.y)and'#'=a)or exists(SELECT*FROM c WHERE b.x>=x-y+b.y and b.y<y and'#'=a)and exists(SELECT*FROM c WHERE b.x>=x-b.y+y and a='#'and b.y>y))OPTION(MAXRECURSION 0)PRINT @

Ungolfed:

DECLARE @ varchar(max)=
'
. . . . # . . . 
 . # . . . # . .
. . . # . . . . 
 . . . . . # . .
. . . . . . . . 
'
;WITH c as
(
  SELECT 
    cast(0as varchar(max))a,x=0,y=1,z=0
  UNION ALL
  SELECT
    SUBSTRING(@,z,1),IIF(SUBSTRING(@,z,1)=CHAR(10),1,x+1),
    IIF(SUBSTRING(@,z,1)=CHAR(10),y+1,y),
    z+1
  FROM c
  WHERE LEN(@)>z
)
SELECT @=stuff(@,z-1,1,'#')FROM c b
WHERE((exists(SELECT*FROM c WHERE b.y=y and'#'=a)
or exists(SELECT*FROM c WHERE b.y<y and'#'=a)
and exists(SELECT*FROM c WHERE b.y>y and'#'=a)
)and a='.')
and 
(exists(SELECT*FROM c WHERE b.x<=x-ABS(y-b.y)and'#'=a)
or exists(SELECT*FROM c WHERE b.x<=x+y-b.y and a='#'and b.y<y)
and exists(SELECT*FROM c WHERE b.x<=x+b.y-y and a='#'and b.y>y))
and(exists(SELECT*FROM c WHERE b.x>=x+ABS(y-b.y)and'#'=a)
or exists(SELECT*FROM c WHERE b.x>=x-y+b.y and b.y<y and'#'=a)
and exists(SELECT*FROM c WHERE b.x>=x-b.y+y and a='#'and b.y>y))
OPTION(MAXRECURSION 0) 
PRINT @

Fiddle ungolfed

t-clausen.dk

Posted 2016-08-29T11:07:19.077

Reputation: 2 874

1

GNU Octave, 212, 196 bytes

Maybe not really a golfer's favourite choice language, but that's what makes the challenge, isn't it? Assuming m is taken as a char matrix: 178 bytes stand alone and 196 if stuffed into a function.

golfed:

function k=f(m)[a,b]=size(m);[y,x]=ndgrid(1:a,1:b);t={y,y+x,x-y};k=m;s=x>0;for j=1:3l{j}=unique(sort(vec(t{j}.*(m==['#']))))([2,end]);s&=(l{j}(1)<=t{j})&(l{j}(2)>=t{j});endk(s&mod(x+y,2))=['#']end

ungolfed:

function k=f(m)
[a,b]=size(m);[y,x]=ndgrid(1:a,1:b);t={y,y+x,x-y};k=m;s=x>0;
for j=1:3
  l{j}=unique(sort(vec(t{j}.*(m==['#']))))([2,end]);
  s&=(l{j}(1)<=t{j})&(l{j}(2)>=t{j});
end
k(s&mod(x+y,2))=['#']
end

Explanation : we build a coordinate system, 3 axes - orthogonal to the hexagons sides, find max and min of each coordinate, then build a logical mask starting with 1 everywhere and logically and:ing each coordinate max and min constraint, finally re-setting each remaining "true" position to "#" char.

If you want to test it, you can just create m matrix like this:

m = [' . . . . . . . .. . . . # . . .  . # . . . # . .. . . # . . . .  . . . . . # . .. . . . . . . . ']; m = reshape(m,[numel(m)/6,6])';

and then call the f(m) and compare with m by building a matrix with both of them in:

['     before           after      ';m,ones(6,1)*'|',f(m)]

mathreadler

Posted 2016-08-29T11:07:19.077

Reputation: 141

1

(Belated) Welcome to PPCG! Octave answers are more than welcome. :) Two things though: 1) please include the code that you've actually counted(without unnecessary whitespace), so that people can check the score more easily. You can include a readable version separately. 2) It appears that your submission is a snippet which assumes the input to be stored in m and the output to be stored in k. Answers should always be full programs or callable functions.

– Martin Ender – 2016-08-30T14:53:56.047

Thanks! Yes you are right, I have embedded k and m in a function f now and added a snippet constructing a first test m for validation. – mathreadler – 2016-08-30T15:28:18.243