F.P
F.P

Reputation: 17831

Dynamically create arrays under certain rules

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.

Upvotes: 2

Views: 99

Answers (3)

F.P
F.P

Reputation: 17831

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>

Upvotes: 1

BitTickler
BitTickler

Reputation: 11897

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

Upvotes: 1

Ami Tavory
Ami Tavory

Reputation: 76336

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.

Upvotes: 1

Related Questions