2

I need to create arrays with certain values/properties that follow these patterns.

Unfortunately, my mathematics knowledge doesn't let me find the pattern.

Here is an example of the array that should be output at (bottom to top) n = 1, 2 and 3 (counting the red boxes along each edge).

enter image description here

All red and green squares should have assigned some value, while all white ones need to be undefined (or empty, null, something).

Creating the array, how do I dynamically assign them their respective red/green/white values?

    for (var x = 0; x < n * 4 - 1; x++)
    {
        for (var y = 0; y < n * 4 - 1; y++)
        {
            board[x][y] = green, red or white?;
        }
    }

PS: If it isn't obvious, The pattern creates hexagons with a "red" edge length of n.

F.P
  • 17,421
  • 34
  • 123
  • 189
  • What variables are known to you at the onset of the function which will create these arrays? You mentioned the edge length, is the position variable or is it always going to be top left aligned on the grid like in your images? – George Kendros Oct 25 '16 at 19:38
  • One more thing, say in the first hexagon, would that be represented by an edge length of 3 or 5 (not sure if the white blocks make up part of the edge length) – George Kendros Oct 25 '16 at 19:41
  • 1
    The only variable as such is `n`. How the red/green/null are done should always follow the pattern from the example. The edge length is counted by the red squares (but that is a convention by me, if counting it otherwise that can be done as well if it makes things easier). The position should always be aligned like this (we are doing arrays, so not much variance there in the indices) – F.P Oct 25 '16 at 19:44
  • I believe that you have a mistake. The patterns you drew of 3 and 2 are OK. The pattern you drew of 1 corresponds to nothing, in my opinion. The pattern you drew of 0 is the one that should correspond to 1. – Ami Tavory Oct 25 '16 at 19:46
  • Hm okay that could be. I was wondering why that one created different values for x and y... I will check if there is an error in my example and update. – F.P Oct 25 '16 at 19:46
  • @FlorianPeschka Much better. – Ami Tavory Oct 25 '16 at 19:51
  • @AmiTavory I checked again with the other algorithms and you were right, I created a diamond shape with the wrong one which should not be allowed. If we want that later, I can create special cases for it. – F.P Oct 25 '16 at 19:52
  • So the question is answered, yes? – user3386109 Oct 25 '16 at 20:08
  • @user3386109 Um, no - I just realized one of the example was false. I still need help with how to figure out for any given `n` 1. array dimensions and 2. what indices should be red, green or white – F.P Oct 25 '16 at 20:09
  • 3
    As for the formula for the arrays size: ``dim n = 4 * n - 1``, which is the simplified versoin of: ``dim n = (n + (n-1)) * 2 + 1`` – BitTickler Oct 25 '16 at 20:11

3 Answers3

1

Each of your hexagons is composed of three parts (from top to bottom):

  1. an upper half terminated by a green line covering the entire width

  2. a single red checkered line

  3. a lower half starting with a green line covering the entire width

The upper and lower halves are mirror images of themselves, reflected over the line in 2.

For a given n, the total number of lines is 2 n - 1 + 2 n. The 2 n - 1 term is due to the red lines: there are 2 n of them, but two of them (the longest ones) are one on top of each other. The 2 n term is due to the green lines (it is the number of red lines + 1).

Here is Python code drawing the top half (item 1 at the beginning):

def print_hex_upper_half(n):
    num_lines = 2 * (n - 1) + 1
    width = (2 * n - 1) + 2 * n
    for i in range(1, num_lines + 1):
        if i % 2 == 1:
            s = n - i / 2 - 1
            print ' ' * s + 'G' * (width - 2 * s) + ' ' * s
        else:
            s = n - i / 2 + 1
            rw = (width - 2 * s + 1) / 2
            print ' ' * s + ' '.join('R' * rw) + ' ' * s

and here it is when run:

>>> print_hex_upper_half(4)
   GGGGGGGGG   
    R R R R    
  GGGGGGGGGGG  
   R R R R R   
 GGGGGGGGGGGGG 
  R R R R R R  
GGGGGGGGGGGGGGG

>>> print_hex_upper_half(3)
  GGGGGGG  
   R R R   
 GGGGGGGGG 
  R R R R  
GGGGGGGGGGG

>>> print_hex_upper_half(2)
 GGGGG 
  R R  
GGGGGGG

>>> print_hex_upper_half(1)
GGG

The middle line is easy, and the bottom half is a reflection, so it is just a matter of manipulating the indices.

Here is a detailed explanation of the code:

  • For the reasons explained above, the number of lines in the top half is 2 (n - 1) + 1, and the width was given above.

  • Odd rows are green, and even rows are red.

  • For the same reasons given above, a green row starts and ends with n - i / 2 - 1 spaces. The rest is green.

  • Again, for the same reasons given above, a red row starts and ends with i / 2 + 1 spaces. The rest is red interspersed with spaces. If we subtract from the width this amount, add 1, and divide by 2, we get the number of red blocks.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • Thanks for the input. I created my own version using your code and text explanations, but you helped a lot! I will post my own version of it too, so we have a good collection of solutions. – F.P Oct 26 '16 at 13:12
  • 1
    @FlorianPeschka Thanks. UVd your version too - good to have a few approaches. – Ami Tavory Oct 26 '16 at 13:33
1

As stated in the question, it is all about finding patterns in the problem which allow for dividing the problem into a set of smaller problems.

Picture size from n

Once we see the parameter n is related to the length of a side of a hexagon, we can find that the biggest number of red squares in the picture will be
nRedsMax n = 2 * n - 1.
Now, the green lines in the picture are always 2 pixels longer than the red strip below (1 pixel to the left and 1 to the right). This leads to
nGreensMax n = nRedsMax n + 2
From the sample pixture, we see that the longest green line fills in a whole row of the picture. Hence,
dimX n = nGreensMax n.
And we can also see, that the picture is a square. So
dimY n = dimX n.
Putting it all together and simplifying the term, we find, that the picture size by n is:
dim n = 4 * n - 1.

Finding the pixel values x,y for n

Basically, the picture is two pictures, vertically interleaved. The green lines being one, the lines with red, being the other. So we can conclude we have 2 cases, we can handle separately.

We also see, that the upper half of the picture and the lower half of the picture is symmetric to its middle axis.

So, for the computation of the pixels in a line y, we always use an
y' = mirrorUp n y.
This works for lines of both types (red lines and green lines).

The green lines

The picture is scaled by a factor 2 in x direction. So, for a picture showing the hexagon of length n, the strip of reds and whites has length 2 * n. And the green line above starts 1 pixel to the left of the red strip and is thus 1 pixel longer than the red strip below.
nGreen n y = 2 * n + 1 + 2 * div (mirrorUp n y) 2

The red lines

The red lines are also centered in the picture and for every logical red dot, we use R - two characters. If
nRed n y = n + div (mirrorUp y) 2
gives the number of red pixels in a row y, thus, the string of reds would thus be 2 * nRed n y long.

Centering of the green and red strips in a line

The amount of pixels not used by a strip is
dim n - length strip And for centering the strip in a row, we need half of that on the left and half on the right.

This leads to the following code, which is written such that the steps described above can be easily found.

module Hexagon(picture,color) where 
import Data.List.Split(chunksOf)

-- The 3 possible values of the output matrix.
data Color = WHITE | RED | GREEN deriving(Eq,Show)

-- The size of the output matrix.
-- n -> Array[dim n,dim n]
dim n = 4 * n - 1

-- classify the type of line by index. 
-- There are Green lines (those with greens)
-- and red lines (those with the reds)
rowType :: Int -> Color
rowType y | mod y 2 == 0 = GREEN
rowType y | mod y 2 == 1 = RED

-- y-symmetry of picture - mirror y of lower half
-- to y of upper half
mirrorUp :: Int -> Int -> Int
mirrorUp n y 
    | y < div (dim n) 2 = y
    | otherwise = dim n - y - 1

-- Number of green elements by n and y
nGreen :: Int -> Int -> Int
nGreen n y = n * 2 + 1 + 2 * div (mirrorUp n y) 2

-- Number of red elements by n and y
nRed :: Int -> Int -> Int
nRed n y = n + div (mirrorUp n y) 2

-- Compute the color of an element by n,x,y
color :: Int -> Int -> Int -> Color
color n x y 
    | rowType y == GREEN && (x < div (dim n - nGreen n y) 2)  
        = WHITE
    | rowType y == GREEN && x >= (div (dim n - nGreen n y) 2 + nGreen n y)
        = WHITE
    | rowType y == GREEN = GREEN
    | rowType y == RED =
        if x < border || x > dim n - border then WHITE
        else 
            case mod (x - border) 2 of
                0 -> RED
                1 -> WHITE
        where
            border = div (dim n - redStrip) 2
            redStrip = 2 * nRed n y - 1

-- color 2 output character
col2char :: Color -> Char
col2char WHITE = '_'
col2char RED = 'R'
col2char GREEN = 'G'            

-- create the ASCII picture of the hexagon for parameter n
picture :: Int -> [Char]
picture n =
    (unlines . chunksOf (dim n)) values
    where 
        values = 
            [col2char (color n x y) | y <- [0,1..dim n - 1], x <- [0,1..dim n - 1] ]

-- Usage Example:
-- putStrLn $ picture 3
BitTickler
  • 10,905
  • 5
  • 32
  • 53
  • Thanks for you help. I accepted the other answer because the pseudo code helped me the most. I am sure yours is just as valid, but I cannot quite read it (not even sure what language it is), but your textual explanations still helped. – F.P Oct 26 '16 at 13:11
  • @FlorianPeschka FYI: The "pseudocode" in the other answer is python. The code in my answer is haskell. – BitTickler Oct 26 '16 at 14:03
  • Sorry I didn't mean pseudo code in a bad way, I just meant that it was code not in a language I can immediately use. Thanks for clearing it up. Haskell is very hard to understand from the outside :D – F.P Oct 26 '16 at 16:15
1

Using the input of both other excellent answers, here is the final version that I implemented:

var $log = $("#log");

var size = 3;
var dimension = size * 4 - 1;

for (var x = 0; x < dimension; x++)
{
 var isUpperHalf = x < size * 2;
 var isRedRow = x % 2 === 1;
 var nextRed = true;

 for (var y = 0; y < dimension; y++)
 {
  var color = " ";
  
  if (isUpperHalf)
  {
   padding = size - Math.floor(x / 2) - 1;
  }
  else
  {
   padding = Math.ceil(x / 2) - size;
  }
  
  if (isRedRow && y > padding && y < dimension - padding)
  {
   if (nextRed)
   {
    color = "r";
   }
   nextRed = !nextRed;
  }
  else if (!isRedRow && y >= padding && y < dimension - padding)
  {
   color = "g";
  }

  $log.append("<span class='" + color + "'>&nbsp;</span>");
 }
 
 $log.append("<br/>");
}
#log {
 font-family: courier;
}
span {
 width: 20px;
 display: inline-block;
}
.g {
 background-color: green;
}
.r {
 background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="log">

</div>
F.P
  • 17,421
  • 34
  • 123
  • 189