Динамически создавать массивы по определенным правилам
Мне нужно создать массивы с определенными значениями / свойствами, которые следуют этим шаблонам.
К сожалению, мои знания по математике не позволяют мне найти образец.
Вот пример массива, который должен быть выведен в (снизу вверх) 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 ответа
Каждый из ваших шестиугольников состоит из трех частей (сверху вниз):
верхняя половина оканчивается зеленой линией, покрывающей всю ширину
одна красная клетчатая линия
нижняя половина начинается с зеленой линии, покрывающей всю ширину
Верхняя и нижняя половины являются зеркальными отражениями самих себя, отраженными по линии в 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 + "'> </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>