Скажу сразу, что ниже описана не полная версия алгоритма, о чем допишу в следующей части.
?Постановка задачи
Задача читать из файла расположение элементов электрической цепи, считать сопротивление всей цепи и для каждого участка цепи установить силу тока, протекающего через него. Для упрощения примем, что элементы помещаются на плату 5х3 в свободные ячейки.
На первый раз ограничимся 4 элементами: резистором, батарейкой, лампочкой и пустышкой, которая соединяет участок цепи (без внутреннего сопротивления). Теперь, когда задача более/менее поставлена, можно приступать к реализации.
? Внутренние обозначения
Для определенности обозначим 0 за пустышку, 1 за резистор в 200 ом, 2 за 500 ом и 3 за 1к ом. Минус означает пробел. Батарейку и лампочку поставим заранее в точках 1,2 и 5,2 соответственно:
?Чтение файла
Так как имя файла не константа, а алгоритм нужно сделать универсальным, то имя файла будет передаваемым параметром.
Вид уровня, хранящего с файле:
0 0 2 0 0
0 — - — 0
0 0 0 0 0
Считываем построчно (значит через массив строк) и разбираем потом отдельно каждую строку. Результат для каждого пустого места в плате вписываем в PlayerPrefs, чтобы можно было работать с элементами вне зависимости от исходной программы чтения из файла.
private string [] s;
private string str;
void Start()
{
s=System.IO.File.ReadAllLines (name);
r=s.Length;
i = 0;
while (i<s.Length) {
str=s[i];
j=0;
while(j<str.Length)
{
if(str[j]=='-') PlayerPrefs.SetInt((i+1).ToString()+«x»+((j-j%2)/2+1).ToString(),-1);
if(str[j]=='0') PlayerPrefs.SetInt((i+1).ToString()+«x»+((j-j%2)/2+1).ToString(),0);
if(str[j]=='1') PlayerPrefs.SetInt((i+1).ToString()+«x»+((j-j%2)/2+1).ToString(),1);
if(str[j]=='2') PlayerPrefs.SetInt((i+1).ToString()+«x»+((j-j%2)/2+1).ToString(),2);
if(str[j]=='3') PlayerPrefs.SetInt((i+1).ToString()+«x»+((j-j%2)/2+1).ToString(),3);
j++;j++;
}
i++;
}
}
?Алгоритм обхода
Вот тут придется сделать оговорку. Так как работа со стеком вызвала некоторые сложности, реализация через очереди и стеки рассмотрю во второй части. Сейчас будем разбирать случай, когда нет никакого разветвления (крайне ограниченно, но для размеров 5х3 самое то).
Зададим начальное место обхода (у нас это от батарейки до другого входа в батарейку). Чтобы из каждой новой точки в плате не идти в обратную сторону, сделаем переменные, в которые будем записывать нашу предыдущую дислокацию. И ещё потребуется переменная, в которую будем запоминать все сопротивления, которые встретились. Для подстраховки сделаем переменную, которая будет отвечать за количество проделанных итераций на случай, если цепь окажется не замкнутой или в ней есть циклы.
Немного забежим вперед и ограничим перемещения по резисторам: если резистор расположен горизонтально (1-3), то тогда можно перемещаться только по вертикали, а если горизонтально (4-6 и об этом в следующей главе), то перемещения доступны только по горизонтали.
xn = 1;yn = 1;
r = 0;
step = 0; tick = 0;
while( ( !((xn==2)&&(yn==1)) )&&(step<500) )
{
step++;
p = PlayerPrefs.GetInt (xn.ToString()+«x»+yn.ToString());
if(p==1) r=r+200;
if(p==2) r=r+500;
if(p==3) r=r+1000;
PlayerPrefs.SetInt(xn.ToString()+«x»+yn.ToString()+«R»,r);
if(( ((xn+1)<=3) && (PlayerPrefs.GetInt ((xn+1).ToString()+«x»+yn.ToString())!=-1) )&&((xn+1)!=xr)&&((p==0)||(p>=4)) )
{
tick++;
xr=xn;
yr=yn;
xn=xn+1;
}
else
if(( ((xn-1)>=1) && (PlayerPrefs.GetInt ((xn-1).ToString()+«x»+yn.ToString())!=-1) )&&((xn-1)!=xr)&&((p==0)||(p>=4)) )
{
tick++;
xr=xn;
yr=yn;
xn=xn-1;
}
else
if(( ((yn+1)<=5) && (PlayerPrefs.GetInt (xn.ToString()+«x»+(yn+1).ToString())!=-1) )&&((yn+1)!=yr)&&(p<=4) )
{
tick++;
yr=yn;
xr=xn;
yn=yn+1;
}
else
if(( ((yn-1)>=1) && (PlayerPrefs.GetInt (xn.ToString()+«x»+(yn-1).ToString())!=-1) )&&((yn-1)!=yr)&&(p<=4))
{
tick++;
yr=yn;
xr=xn;
yn=yn-1;
}
}
Полученное сопротивление обработаем и сохраним в PlayerPrefs. Если сопротивление равно нулю, то заранее установим ток, равным 1 амперу. Если было совершено более 500 шагов, то в схеме есть цикл или же цепь не замкнута.
PlayerPrefs.SetInt («SxemeR», r);
if((step<500)&&(r!=0)) ir=9.0f/r; else
if(step>=500)
{
PlayerPrefs.SetInt («SxemeR», -1);
ir=0.001f;
}
Чтобы получить силу тока, разделим напряжение в батарейке (9В) на сопротивление в цепи. И запишем результат в каждый элемент цепи (для этого пройдем ещё раз по цепи по алгоритму, описанному выше).
?В заключении первой части
— Описанные приемы позволяют создать систему, в которой пользователь сам планирует и размещает элементы цепи;
— Рассмотренный способ представляется интуитивно понятным, но не покрывает все потребности в расчетах;
— В следующей главе будет описано как обойти цепь, используя стек, чтобы не только упростить код, но и разрешить проблему с циклами и разветвлениями (параллельными соединениями в цепи);
P.S. Модели, используемые в проекте можно скачать тут.
Комментарии (22)
daiver19
13.10.2016 16:14+2И какой же стандартный алгоритм вы в итоге реализовали?
Такого ужасного я, кстати, уже давно не видел.Gr13
13.10.2016 16:31Обход вершин в графе (ужасным способом, не скрою).
О том, как это сделать правильно (стек и прочие радости) будет в следующей статье.daiver19
13.10.2016 16:37+1Ну так стандартные алгоритмы — это обход в ширину/глубину. Я уже молчу, что они тривиальны, но у вас их еще и нет в статье про применение стандартных алгоритмов :)
Anton_Menshov
14.10.2016 01:29+1Я практически уверен, что вы изобретаете тот еще велосипед. Перед реализацией такой задачи, очень советую прочитать матчасть: метод узловых потенциалов (уже упомянут в комментариях выше).
Если решать задачу по-настоящему, то стоит использовать модифицированный алгоритм:
Modified Nodal analysis
Основная статья по этому методу: Ho, Ruehli, and Brennan, «The modified nodal approach to network analysis».
bambruysk
14.10.2016 03:20А в целом какая цель? Написать на Unity3D свой собственный симулятор цепей?
Gr13
14.10.2016 03:20Очень верно подмечено
armature_current
14.10.2016 05:03А когда планируете расширить элементную базу? Интересуют модели приводов, солнечных панелей, химических накопитилей, полупроводниковых приборов и ШИМ-контроллеров. Неплохо бы еще и осциллографы, желательно гальванически развязанные и с цифровыми анализаторами.
Gr13
14.10.2016 12:20Боюсь, что из за отказа от переменного тока все эти прекрасные технические вещи не реализовать должным образом.
Потому их добавление зависит от добавления переменного тока в проект
maisvendoo
14.10.2016 07:08Меня смутила (и возмутила!) первая же фраза статьи:
За время обучения не раз задавался вопросом: все эти хорошие и крутые алгоритмы чем могут помочь на практике?
То есть как это? Чем же это может помочь программисту знание алгоритмов? Сложный вопрос, дайте ка подумаю…Gr13
14.10.2016 12:13Не так часто на практике сталкивался с алгоритмами обхода и вот таковой попался в деле
Возможно достаточно броский, потому так и зацепилb_oberon
14.10.2016 13:29Для подстраховки сделаем переменную, которая будет отвечать за количество проделанных итераций на случай, если цепь окажется не замкнутой или в ней есть циклы.
А упомянутые крутые алгоритмы-то где? То, что написано выше, совсем не круто.
QtRoS
14.10.2016 19:32Это все же не уровень хабра. И код, и само отношение к алгоритмам как к чему-то далекому и малоприменимому на практике. Тут большинство все же «нюхали порох», и об алгоритмах знают не по наслышке, да и код пишут продакшн качества, а не, пардон, фарш из статьи :)
Не обижайтесь, это дружеский совет.
Virviil
Я конечно не знаю, что у вас будет в следующей статье, но на самом деле цепи считаются не так.
Рассмотрим простейший вариант — статическая цепь, то есть цепь в которой не надо считать переходные процессы.
Для её расчёта используется метод узловых потенциалов(чаще) или метод контурных токов(реже).
Преимущества: любая конфигурация сети, любые элементы (конденсаторы и индуктивности), переменный ток работает так же как и постоянные без оверхеда. Если интересно — пишите в личку.
Gr13
Пока не задумывался про переходные процессы, так как ориентировался только на вычисление сопротивления цепи.
Дальше собираюсь описать как при помощи стека можно выделить циклы и параллельные соединения (в статических цепях).
Метод узловых потенциалов решит проблему с мостом, но на данный момент не очень понимаю, как такое реализовать, потому и опустил этот метод
nckma
У Вас проблемы начнутся, когда Вы захотите рассчитывать цепь содержащую не только резисторы, но и индуктивности с емкостями. Например, сопротивление индуктивности комплексное: jwL и зависит от частоты. Сопротивление конденсатора 1/jwC так же зависит от частоты. Вот методы узловых потенциалов или контурных токов позволяют посчитать и переходные процессы и частотные характеристики цепей.
Gr13
Осознаю такую сложность, но для этого проекта (в дальнейшем развитии) отказался от переменного тока, равно как и от конденсаторов и катушек индуктивностей.
возможно рассмотрю их, но это будет крайне не скоро
nckma
Я допускаю, что видимо Ваша задача состоит в изучении языка C/C++, а не изучении теории цепей. Читателям статьи это не понятно, отсюда и критика.
Gr13
Цель действительно не в изучении цепей (иначе хаб был не разработка в физика или подобное), а в том, как такое сделать на интуитивно уровне (глава 1) и на уровне программиста (глава 2)