Динамически создавать массивы по определенным правилам

Мне нужно создать массивы с определенными значениями / свойствами, которые следуют этим шаблонам.

К сожалению, мои знания по математике не позволяют мне найти образец.

Вот пример массива, который должен быть выведен в (снизу вверх) n = 1, 2 и 3 (считая красные поля вдоль каждого края).

введите описание изображения здесь

Все красные и зеленые квадраты должны иметь определенное значение, а все белые должны быть неопределенными (или пустыми, нулевыми, что-то).

Создавая массив, как мне динамически назначать им соответствующие красные / зеленые / белые значения?

    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: Если это не очевидно, шаблон создает шестиугольники с "красной" длиной ребра n,

3 ответа

Решение

Каждый из ваших шестиугольников состоит из трех частей (сверху вниз):

  1. верхняя половина оканчивается зеленой линией, покрывающей всю ширину

  2. одна красная клетчатая линия

  3. нижняя половина начинается с зеленой линии, покрывающей всю ширину

Верхняя и нижняя половины являются зеркальными отражениями самих себя, отраженными по линии в 2.

Для данного n общее количество строк составляет 2 n - 1 + 2 n. Член 2 n - 1 обусловлен красными линиями: их 2 n, но два из них (самые длинные) расположены один над другим. Член 2 n связан с зелеными линиями (это количество красных линий + 1).

Вот код Python, рисующий верхнюю половину (элемент 1 в начале):

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

и вот оно когда запускается

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

Средняя линия проста, а нижняя половина является отражением, так что это просто вопрос манипулирования индексами.

Вот подробное объяснение кода:

  • По причинам, изложенным выше, количество строк в верхней половине равно 2 (n - 1) + 1, а ширина была указана выше.

  • Нечетные строки зеленого цвета, а четные строки красного цвета.

  • По тем же причинам, указанным выше, зеленая строка начинается и заканчивается n - i / 2 - 1 пробелами. Остальное зелено.

  • Опять же, по тем же причинам, что и выше, красная строка начинается и заканчивается пробелами i / 2 + 1. Остальное красное вкраплено пробелами. Если мы вычтем из ширины эту сумму, добавим 1 и разделим на 2, мы получим количество красных блоков.

Как указано в вопросе, речь идет о поиске закономерностей в проблеме, которые позволяют разделить проблему на ряд более мелких проблем.

Размер картинки от n

Как только мы увидим, что параметр n связан с длиной стороны шестиугольника, мы можем обнаружить, что наибольшее количество красных квадратов на рисунке будет
nRedsMax n = 2 * n - 1,
Теперь зеленые линии на картинке всегда на 2 пикселя длиннее красной полосы внизу (1 пиксель слева и 1 справа). Это ведет к
nGreensMax n = nRedsMax n + 2
Из примера изображения мы видим, что самая длинная зеленая линия заполняет всю строку изображения. Следовательно,
dimX n = nGreensMax n,
И мы также можем видеть, что картина квадратная. Так
dimY n = dimX n,
Собрав все воедино и упростив термин, мы находим, что размер изображения по n равен:
dim n = 4 * n - 1,

Нахождение значений пикселей x,y для n

По сути, картина представляет собой две картинки, с чередованием по вертикали. Зеленые линии - одна, линии с красным - другая. Таким образом, мы можем заключить, что у нас есть 2 случая, которые мы можем обрабатывать отдельно.

Мы также видим, что верхняя половина рисунка и нижняя половина рисунка симметричны его средней оси.

Итак, для вычисления пикселей в строке у, мы всегда используем
y' = mirrorUp n y,
Это работает для линий обоих типов (красные линии и зеленые линии).

Зеленые линии

Изображение масштабируется в 2 раза в направлении х. Итак, для картины, показывающей шестигранник длины nполоса красных и белых имеет длину 2 * п. И зеленая линия выше начинается на 1 пиксель слева от красной полосы и, таким образом, на 1 пиксель длиннее красной полосы внизу.
nGreen n y = 2 * n + 1 + 2 * div (mirrorUp n y) 2

Красные линии

Красные линии также центрированы на картинке, и для каждой логической красной точки мы используем R - два персонажа. Если
nRed n y = n + div (mirrorUp y) 2
дает количество красных пикселей в строке у, таким образом, строка красных будет, таким образом, 2 * nRed n y долго.

Центрирование зеленой и красной полос в линии

Количество пикселей, не используемых полосой, равно
dim n - length stripИ для центрирования полосы подряд нам понадобится половина этого слева и половина справа.

Это приводит к следующему коду, который написан так, что описанные выше шаги могут быть легко найдены.

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

Используя ввод обоих отличных ответов, вот заключительная версия, которую я реализовал:

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>

Другие вопросы по тегам