Всем привет!
Помогите разобраться, пожалуйста. В целом понимаю, как устроено, но не понимаю, можно ли как-то сделать так, чтобы x и y совпадали, а если нет, то почему.
Есть три вопроса
Небольшая вводная
В статье Раздел "Игры" на JavaRush: Полезная теория прочитала такое:
При обращении к матрице сначала вы указываете y, а потом x, в то время как в математике принято сначала указывать x (x, y).
Здесь мне все полностью понятно, в программировании мы с помощью array.length получим количество строк (то есть y), а с помощью array[number].length получим количество столбцов (т.е. x). Что в математике есть свои стандарты, это тоже понятно, к точке на плоскости мы обращаемся в формате (x, y).
Читала очень много комментариев здесь, что все зависит от того, как представить в своей голове матрицу. И запуталась
Сами вопросы:
1) Верно ли тут, что матрицу мы представляем в коде только так, т.к. это стандарт в программировании, а все вопросы нужно направить к методам в движке (например, setCellValue(int x, int y, String value) итд)? Так как это именно методы принимают аргументы по правилам математики, а не программирования.
2) Это стандартная практика, что методы в игровых движках пишутся по правилам математики, или это все зависит от команды разработчиков? Влияет ли выбор реализации на пользователя игры, или опять же, это дело только между разработчиками и кодом?
3) Есть ли разница между двумя матрицами, которые изображены на рисунке? Имею в виду, влияет ли на наш код то, как мы будем представлять массив, с которым работаем, если выбирать из этих двух вариантов?
![]()
Ada
1 уровень
Игра Сапер, Матрица
Решен
Комментарии (10)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Павел Безумный учёный Expert
8 июня 2022, 13:20
Строго говоря, двухмерный массив в Java - это не привычная нам прямоугольная матрица, имеющая длину и ширину (как на рисунке). Правильнее будет сказать, что двухмерный массив - это несколько одномерных массивов, идущих подряд друг за другом:
Здесь мы видим набор данных, условно разбитых на три блока. Каждый из этих блоков имеет свой индекс и по сути является одномерным массивом. При этом блоки никак не зависят друг от друга, они вообще могут быть разного размера, что противоречит привычному "табличному" представлению. Поэтому сами понятия "ширина" и "высота", применяемые к двухмерному массиву, являются чистой условностью для облегчения восприятия человеком. Собственно говоря, сама "матрица" получается путём умозрительного расположения блоков (одномерных массивов) друг под другом, чтобы получить необходимый "табличный" вид:
Но разумеется, в памяти виртуальной машины массив не становится никакой "матрицей", он является просто последовательностью нескольких одномерных массивов, как было показано в примере выше.
Чтобы обратиться к какому-то значению в двухмерном массиве, нужно сначала обратиться к блоку, содержащему это значение. А поскольку блоки ( т. е. одномерные массивы) - это строки в "табличном" преставлении, то естественным образом появляется необходимость обратного порядка следования координат: сначала указывается индекс одномерного массива (номер "блока", номер "строки в матрице", вертикальная координата), а затем - индекс ячейки в одномерном массиве (горизонтальная координата).
+2
Павел Безумный учёный Expert
8 июня 2022, 13:20
Чтобы избавить себя от необходимости постоянно следить за правильностью порядка координат при передаче в метод или обращению к ячейке двухмерного массива, можно создать вспомогательный класс, описывающий объект "Двухмерная матрица". Например, этот класс может быть таким:
Класс Matrix помимо собственно двухмерного массива содержит также два метода, позволяющие считать/записать значение ячейки по её координатам. Использование методов getValue() и setValue() для доступа к элементам матрицы избавляет от необходимости "перекручивать" координаты x и y, это происходит скрыто от пользователя класса внутри этих методов.
Остаётся только воспользоваться объектом Matrix вместо поля gameField в классе игры, чтобы воспользоваться этим преимуществом работы с матрицей. Впрочем, такое решение едва ли пройдёт валидацию на сервере: если мне не изменяет память, проверяется также наличие поля GameObject[][] gameField в основном классе игры.
+2
Ada
8 июня 2022, 14:29
Павел, спасибо большое!
И все же остались вопросы:
1) Совсем некорректно рассматривать двумерный массив как матрицу? Хотя бы как таблицу (так все же проще его понять)
2) Можно ли просто использовать методы, которые будут работать не с х и у, а с у и х, или так не принято?
3) Создание класса матрицы это пример хорошей композиции или все же перегружает код?
0
Денис Enterprise Java Developer
8 июня 2022, 14:42полезный
1. Двумерный массив вовсе не обязательно состоит из массивов одинаковой длины. Так например
Тоже двумерный массив.
С помощью двумерного массива действительно можно представить координатную плоскость, с той поправкой что отрицательных координат там не будет. Но это не единственное его применение, как мне кажется.
К вашему вопросу по рисунку. Если вы перевернете игральный кубик с одной грани на другую, станет он от этого другим кубиком? И там и там координатное пространство, в обоих пространствах берется только первая четверть (x > 0, y > 0)
2. Можно ли работать - это вам решать, вы автор и имеете право на точку зрения.
3. Любой класс в коде создается с какой либо целью. Если этот класс помогает вам решить вашу задачу можно ли назвать его лишним?
В программировании безусловно есть хорошие практики и плохие, но единственный реальный критерий хорошего кода - он работает правильно, надежно и использует вменяемое количество ресурсов (время, память и пр).
Паттерны проектирования придуманы что бы упростить некоторые задачи, например модифицируемость кодовой базы в будущем. Хорошо ли использовать паттерны? безусловно. Обязательно ли? вовсе нет. Всегда отталкивайтесь от поставленной задачи.
Тут на Javarush есть задача где надо было составить цепочку слов типа игры в города. Я ее решал посредством введения дополнительного класса Word и оперировал им. У класса были нужные мне методы сравнения первой и последней буквы и задача стала выглядеть лаконично и просто. Можно ли назвать это перегруженностью кода? Конечно можно. Доволен ли я своим решением? очень :)
+1
Павел Безумный учёный Expert
8 июня 2022, 16:17решение
Скажем так: любую двухмерную матрицу можно рассматривать как двухмерный массив, но не каждый двухмерный массив может быть матрицей (как показал Денис в своём примере, одномерные массивы в составе двухмерного могут иметь разные длины, поэтому такой двухмерный массив не может рассматриваться как матрица). Другими словами, матрица - это частный случай двухмерного массива, и если длины одномерных массивов равны, то двухмерный массив корректно рассматривать как матрицу. Однако при этом всегда следует рассматривать представление двухмерного массива сообразно рисунку 2, то есть с осью ординат, направленной вниз (в этом направлении возрастают индексы "строк" матрицы). Собственно говоря, именно это и делается при написании игры - двухмерный массив рассматривается как "таблица".
Если всё же очень хочется привести порядок следования координат при вызовах методов и обращениях к элементам матрицы к "общему знаменателю", можно выполнить переопределение используемых методов класса Game, которые принимают x и y:
+2
Павел Безумный учёный Expert
8 июня 2022, 16:17решение
Это пример переопределения метода setCellValue() родительского класса Game. Переопределённый метод содержит в себе вызов родительского метода setCellValue(), то есть фактически поведение переопределённого и родительского методов одинаково. Разница лишь в том, что при вызове переопределённого метода порядок следования координат должен быть обратным (y, x), чем и обеспечивается однообразие с обращением к ячейке матрицы. Но опять же, хоть такое решение будет вполне рабочим, нет гарантии, что оно успешно пройдёт валидацию (при тестах на сервере метод может вызываться отдельно от остального контекста класса). Вполне возможно, что такая разница в порядке следования координат допущена авторами задачи намеренно, чтобы заставить учащихся хорошенько пораскинуть мозгами над этой темой 😄
На мой взгляд, главное предназначение самой концепции ООП - это возможность описания в коде самых разных объектов реального мира, а также их взаимодействия. Создав однажды класс и продумав и описав его внутреннее устройство, нам больше нет нужды возвращаться каждый раз к его "внутренностям" для взаимодействия с объектом этого класса. Мы просто "дёргаем" методы, доступные для вызова извне объекта, и получаем какой-то результат этих вызовов. А о том, как оно там "шуршит" внутри больше нет необходимости задумываться - мы уже продумали это при описании логики класса.
Класс Matrix - простейший пример такой абстракции. Его использование помогает нам отвлечься от нюансов и тонкостей работы с двухмерным массивом, упрощая его восприятие в воображении разработчика. Если это удобно и позволяет упростить общее понимание алгоритма, то такой дополнительный класс, на мой взгляд, никогда не будет лишним.
+2
Ada
8 июня 2022, 17:37
Денис, насчет К вашему вопросу по рисунку. Если вы перевернете игральный кубик с одной грани на другую, станет он от этого другим кубиком? И там и там координатное пространство, в обоих пространствах берется только первая четверть (x > 0, y > 0)
В комментариях к задачам видела, как многие просили именно нарисовать массив и поиграться с рисунком, чтобы понять, что к чему. Я так и сделала, вот и возник вопрос, а тут ничего ли я не упустила)
Спасибо также, что поделились опытом, на вашем примере стало понятнее)
0
Ada
8 июня 2022, 17:43
Павел, а вот это что-то вроде аксиомы?
Однако при этом всегда следует рассматривать представление двухмерного массива сообразно рисунку 2, то есть с осью ординат, направленной вниз (в этом направлении возрастают индексы "строк" матрицы). Собственно говоря, именно это и делается при написании игры - двухмерный массив рассматривается как "таблица".
Про зубчатые массивы знаю, но пока к ним не лезу, так сказать) У меня и сейчас есть некоторые сложности с представлением и пониманием двумерных массивов, потому что везде пишут по-разному, даже на джавараше (вот статья, как пример, там со слов "Расположение элементов в массивах"). Поэтому хотелось бы зафиксировать в голове)
Про ООП очень наглядно донесли мысль, благодарю!
0
Павел Безумный учёный Expert
8 июня 2022, 20:26решение
Нет, это не аксиома, а просто более распространённая модель, учитывая её "естественность". Так же, как мы читаем текст слева направо и сверху вниз, мы последовательно движемся по ячейкам матрицы. Такая модель, в частности, используется для "нумерации" пикселей матрицы монитора. Разумеется, окончательный выбор остаётся за разработчиком - он выбирает ту модель, которая, по его мнению, наилучшим образом соответствует его задачам. Например, если представить, что двухмерный массив - это набор вертикальных столбцов-массивов, то вполне можно опираться на модель координатной плоскости с традиционным обозначением координат (x, y). Преимущество модели, представленной на рисунке 2 из заголовка вопроса в том, что она совпадает с синтаксисом объявления двухмерного массива:
Тот же массив при необходимости разработчик может представить иначе, например:
При этом во втором случае мы получаем модель координатной плоскости с традиционным порядком следования координат при обращении к ячейке.
Сам массив в обоих случаях остаётся тем же. Тут всё дело в воображении разработчика, его видении. Мы просто умозрительно складываем "блоки" (одномерные массивы) разными способами, и получаем, опять же умозрительно, нужную нам модель.
+2
Ada
9 июня 2022, 04:13
благодарю! все прояснилось!)
0