Уведомления

Группа в Telegram: @pythonsu

#1 Март 11, 2020 06:53:03

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9844
Репутация: +  853  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

Romanteg
Не могу понять принцип как вы пришли к такому решению, что нужно использовать зависимость n от nn и что nn задает границу, а затем n еще и сбрасывается… наверное, это приходит с опытом.
Я увидел, что весь путь состоит из повторяющихся кусков. Один кусок включает в себя действия: закрасить первую клетку; пропустить ряд клеток; остановиться. Дальше я увидел, что “пропустить ряд клеток” вырастает на одну клетку после каждого куска. Дальше я ввёл эту переменную nn, которая и следит за тем, сколько клеток нужно пропустить в куске. А дальше можно было использовать range(), но range() есть не во всех языках, поэтому я решил range() заменить на счётчик пройденных клеток и назвал его n. Таким образом, на каждом куске счётчик пропущенных клеток обнуляется, а количество клеток, которые надо пропустить, наращивается на одну клетку. И когда счётчик на куске достигает количества пропускаемых клеток, кусок завершается остановкой и цикл переходит к следующему куску. В следующем куске устанавливается: сколько клеток надо в нём пропустить; счётчик пройденных клеток куска устанавливается в ноль; первая клетка куска закрашивается. И дальше всё повторяется, как в предыдущем куске.

Идёт обработка каждого куска одним и тем же способом.

Romanteg
наверное, это приходит с опытом.
Да, ты видишь этот путь целиком, а нужно его раскладывать на одинаковые кусочки. Потом для кусочка надо писать программку, а потом эту программку повторять. И чтобы видеть, из каких одинаковых кусочков состоит якобы неразделимая и целостная сущность, нужно тренироваться. Человек состоит из частей тела. Человек состоит из тканей. Человек состоит из клеток. Человек состоит из атомов. Вот это разделение целостной сущности на составляющие части. То есть делить можно по-разному. Когда делаешь программу, делить целостную сущность нужно на максимальные одинаковые куски. Если ты поделишь путь из клеток на клетки, то ты ничего не получишь. Но если ты поделишь путь из клеток на повторяющиеся фрагменты пути, то ты можешь для одного фрагмента пути написать алгоритм, а потом в цикле вызывать его. И путь будет обрабатываться одинаковыми порциями.

Всё это написано в книге “Программирование для математиков”. Фактически, я тебе просто по памяти переписываю сюда эту книгу. Там нужно всё досканально читать и во всё вникать. А если ты всё наискосок прочитал, то ты время на это потратил и не узнал ничего.



Отредактировано py.user.next (Март 11, 2020 06:56:41)

Офлайн

#2 Март 19, 2020 02:41:55

lapimax
От: Moscow
Зарегистрирован: 2020-03-19
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

py.user.next
Почему мы делаем вот так, а не как у тебя, - потому что это декомпозиция.

Какой принцип у декомпозиции:
1)
Нужно выделить максимальные действия, максимальные структуры и всё записать для них;
2)
Когда на них всё работает, мы спускаемся в полученные функции и проводим с ними то же самое действие - ищем всё максимальное уже на новом уровне и записываем всё для максимального;
3)
Когда для этого второго уровня всё работает, мы снова спускаемся в полученные функции (на третий уровень) и проводим там то же самое действие по поиску максимальных действий и структур;
4)
Это продолжается, пока разбивать ничего не останется, - элементы станут простейшими.

Эта декомпозиция приводит к тому, что у тебя всё получается ясно и выстроено.
А если же ты вот это всё не соблюдаешь, то у тебя получается вот такое дробление, где уже ничего поймёшь, что происходит.

Если бы функция fill_up_down() получилась слишком большой и запутанной, то её можно было бы дальше разбивать. Но так как она короткая (до 25 строк) и функционально-прочная по Майерсу (отвечает точно на вопрос “что делает эта функция?”), то мы её оставляем в таком виде. Если бы она была на полстраницы или делала бы десяток несвязанных между собой действий, то мы бы должны были её разбить на несколько разных функций, которые и короткие, и функционально-прочные. Проверяем “Что делает эта функция?”, ответ - она закрашивает клетки сверху и снизу от текущей, если это возможно сделать. Всё, ответ точный, значит функция фунционально-прочная по Майерсу.

Пол дня сидел над задачей №20. Потом случайным образом наткнулся на этот форум и ваши ответы. Моментально пришло осознание, насколько криво я сделал прошлые 20 заданий.

Чтобы вы понимали, вот так у меня была сделана изначально 13 задача:
     while not wall_is_on_the_right():
        if not wall_is_above():
            move_up()
            fill_cell()
            move_down()
        if not wall_is_beneath():
            move_down()
            fill_cell()
            move_up()
        move_right()
    else:
        if not wall_is_above():
            move_up()
            fill_cell()
            move_down()
        if not wall_is_beneath():
            move_down()
            fill_cell()
            move_up()

Только начал изучение Python (по свежему курсу Хирьянова Тимофея на Ютубе) и ваши ценные и дельные ответы очень помогают разобраться. Зарегистрировался просто сказать спасибо за ваш труд.

К слову, 20 задачу решил вот так:
 #!/usr/bin/python3
from pyrob.api import *
def fill_cells():
    for i in range(27):
        move_right()
        fill_cell()
    move_down()
    for i in range(27):
        fill_cell()
        move_left()
    move_down()
@task(delay=0.01)
def task_4_3():
    pass
    for i in range(6):
        fill_cells()
    move_right()
if __name__ == '__main__':
    run_tasks()

Офлайн

#3 Март 19, 2020 03:45:28

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9844
Репутация: +  853  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

lapimax
Чтобы вы понимали, вот так у меня была сделана изначально 13 задача:
Я её сделал с подпрограммой (с функцией), потому что так легко было сделать. Но по курсу Тимофея в 13-ой задаче ещё подпрограммы нельзя использовать. Подпрограммы начинаются в 24-ой задаче. Но всё равно, всё к этому идёт. Без подпрограмм ничего не пишется. Так что у тебя вариант даже правильнее, если его до ума довести (убрать else ветку) и сделать всё без подпрограмм. Но я думаю, что до первого действия - действия подготовки к циклу - ты бы не додумался, потому что это надо знать из теории про предусловие цикла (хотя я там эту часть не описал, а в книжке оно есть). То есть перед выполнением цикла нужно соблюсти предусловие выполнения цикла. И для этого мы делаем подготовительный шаг перед тем, как начать выполнять цикл. Этот шаг можно делать и после цикла, но обычно мы его делаем до цикла. А зачем его делать, этот подготовительный шаг? А затем, что поле может оказаться ширины 1 (это теория, но она реальна) и твой цикл на самом первом шаге может сказать “там справа уже есть стена, и поэтому делать ничего не нужно” и таким образом оставить клетку незакрашенной, которую надо закрасить.

lapimax
К слову, 20 задачу решил вот так:
  
for i in range(27):
Это ошибка. Какой ширины поле? Если не сказано, что поле точно ширины 29, то значит, что оно может быть ширины 1 и может быть ширины 1000. Поэтому и программу нужно писать так, что поле может быть как такой, так и такой ширины и при этом программа сработает правильно.
Да, при запуске в pyrob'е это поле каждый раз размерности 15x29, но в реальных программах и в учебных программах тоже это не так. Поэтому при написании алгоритма ты пишешь для всех размерностей сразу - для минимальной, для максимальной и для любой срединной. И тогда твоя программа будет хорошей, потому что при добавлении поля другого размера твоя программа без каких-либо изменений обработает и его правильно. Это важный момент, который называется “повторное использование кода”, - это когда для новых и неизвестных ранее условий ты можешь взять уже написанный код и сэкономить время (сэкономить неделю, сэкономить месяц, сэкономить год). Таким образом, ты задачу решаешь, а код не пишешь, а просто копируешь его за час. Так можно целые программы писать и делать сложные вещи за один день.

Второй аспект этой строки в том, что ты использовал “магическое число”. Ты про них можешь почитать в Интернете: что это такое и почему их надо избегать и как их избегать. Информация не сложная, она есть везде и за день ты её освоишь.



Отредактировано py.user.next (Март 19, 2020 03:52:13)

Офлайн

#4 Март 19, 2020 11:48:03

Romanteg
Зарегистрирован: 2020-03-09
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

DevilDemonn
 from pyrob.api import *
@task(delay=0.15)
def task_9_3():
    # Check size
    x = 0
    while not wall_is_on_the_right():
        move_right()
        x += 1
    else:
        move_left(x)
    ############
    base = x
    while x > 1:
        for i in range (x):
            move_right()
            if not i == x-1:
                fill_cell()
        for i in range (x):
            move_down()
            if not i == x-1:
                fill_cell()
        for i in range (x):
            move_left()
            if not i == x-1:
                fill_cell()
        for i in range (x):
            move_up()
            if not i == x-1:
                fill_cell()
        move_down()
        move_right()
        x -= 2
    else:
        move_down(int(base/2))
        move_left(int(base/2))
if __name__ == '__main__':
    run_tasks()[/quote]

Классное решение! Я до такой логики сравнения не додумался, к сожалению.
И немного изменил ваш вариант.

     
    a = 0
    while not wall_is_on_the_right():
        move_right()
        a += 1
    else: move_left(a)
    while a > 1:
        for c in range(a):
            move_right()
            if c != a - 1: fill_cell()
        for c in range(a):
            move_down()
            if c != a - 1: fill_cell()
        for c in range(a):
            move_left()
            if c != a - 1: fill_cell()
        for c in range(a):
            move_up()
            if c != a - 1: fill_cell()
        move_right()
        move_down()
        a -= 2
    while not wall_is_on_the_left(): move_left()
    while not wall_is_beneath(): move_down()

Отредактировано Romanteg (Март 19, 2020 11:53:06)

Офлайн

#5 Март 19, 2020 15:27:34

lapimax
От: Moscow
Зарегистрирован: 2020-03-19
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

py.user.next
Подпрограммы начинаются в 24-ой задаче.
Можете тогда объяснить, как тогда решить 20 задачу не прибегая к подпрограмме(как сделал я)?
Судя по названию раздела в заданиях, её нужно решить вложенным циклом без применения подпрограммы (вообще, подразумевается, что все задания из первой лабораторной можно решить изучив первую лекцию. По крайней мере, такой вывод складывается из страницы практики: http://cs.mipt.ru/python).

Проще говоря, новички могут немного теряться, т.к. без просмотра 2 лекции, сделать 1 лабораторную невозможно(хотя бы потому, что там ничего нет про циклы while и for, да и судя по информации от вас, в 24 задаче уже необходимы подпрограммы).

py.user.next
Это ошибка. Какой ширины поле? Если не сказано, что поле точно ширины 29, то значит, что оно может быть ширины 1 и может быть ширины 1000. Поэтому и программу нужно писать так, что поле может быть как такой, так и такой ширины и при этом программа сработает правильно.
Я понимаю, о чем вы говорите. Пытался найти другой способ, который подразумевал бы эту гибкость, но мне не удалось. При решении прошлых задач, достигнуть такой гибкости можно было благодаря циклу while и командам стены и/или закрашенной клетки.
В 20 задании выделенные клетки ни к чему не привязаны, а отдельного параметра, отличающего их от других незакрашенных клеток в роботе нет.

Прикреплённый файлы:
attachment Снимок экрана 2020-03-19 в 00.00.21.png (37,6 KБ)

Офлайн

#6 Март 19, 2020 23:38:32

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9844
Репутация: +  853  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

lapimax
Можете тогда объяснить, как тогда решить 20 задачу не прибегая к подпрограмме(как сделал я)?
Судя по названию раздела в заданиях, её нужно решить вложенным циклом без применения подпрограммы

Задача
шагнуть вправо
цикл выполнять
шагнуть вниз
если снизу_нет_стены то
шагнуть вверх
иначе
шагнуть вверх
выход из цикла
конец если
цикл пока справа_нет_стены выполнять
закрасить ячейку
шагнуть вправо
конец цикла
цикл пока слева_нет_стены выполнять
шагнуть влево
конец цикла
шагнуть вправо
шагнуть вниз
конец цикла

[guest@localhost pyrob]$ python3 task_20.py 
INFO:pyrob:Starting task task_4_3
INFO:pyrob:Task task_4_3 finished: +
INFO:pyrob:Total: 1/1
[guest@localhost pyrob]$


lapimax
В 20 задании выделенные клетки ни к чему не привязаны
Есть поле вокруг и его границы. Эти границы можно использовать как логические знаки. Но до границы часто нужно сходить и вернуться обратно, чтобы сделать логический вывод по ней.



Отредактировано py.user.next (Март 19, 2020 23:44:36)

Офлайн

#7 Март 26, 2020 16:57:26

F.Dorohov
Зарегистрирован: 2020-03-26
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

Здравствуйте, подскажите
Задача №29: task_7_7

Решаю ее подсчтётом закрашенных клеток, клетки считаются, но счетчик не обнуляется, где ошибка?

def task_7_7():
filled = 0
while not wall_is_on_the_right():
if cell_is_filled():
filled += 1
if filled == 3:
break
else:
filled == 0
else:
filled == 0
move_right()

Отредактировано F.Dorohov (Март 26, 2020 17:00:02)

Офлайн

#8 Март 26, 2020 22:56:09

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9844
Репутация: +  853  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

F.Dorohov
Здравствуйте, подскажите
Задача №29: task_7_7

Задача

количество_заполненных = 0
цикл пока справа_нет_стены выполнять
если клетка_заполнена то
количество_заполненных.увеличить на 1
иначе
количество_заполненных = 0
конец если
если количество_заполненных = 3 то
выход из цикла
конец если
шагнуть вправо
конец цикла
[guest@localhost pyrob]$ python3 task_29.py 
INFO:pyrob:Starting task task_7_7
INFO:pyrob:Task task_7_7 finished: +
INFO:pyrob:Total: 1/1
[guest@localhost pyrob]$



Отредактировано py.user.next (Март 26, 2020 22:57:04)

Офлайн

#9 Апрель 2, 2020 20:17:21

Romanteg
Зарегистрирован: 2020-03-09
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

py.user.next
 def walk_upstairs():
    n = 0
    while not wall_is_above():
        move_up()
        if cell_is_filled():
            n += 1
        else:
            fill_cell()
    while not wall_is_beneath():
        move_down()
    return n
  
@task
def task_8_18():
    n = 0
    while not wall_is_on_the_right():
        if cell_is_filled():
            n += 1
        if wall_is_above():
            if not cell_is_filled():
                fill_cell()
        else:
            n += walk_upstairs()
        move_right()
    mov('ax', n)
 
Тут применён возврат значения из функции. В этом курсе такие возможности не описываются, но в реале всё делается именно так. Если же по курсу брать, то регистр доступен во всех процедурах и из него можно брать значение (брать, наращивать и класть обратно). Но тут в курсе не указано, как брать значение регистра, хотя pyrob может его брать (если внутри пакета покопаться) через get_register_value(r). Короче, это всё частности; главное алгоритм составить, применив декомпозицию на подпрограммы, потому что регистр потом не пригодится, а вот навык декомпозиции (раскладывания на составные части) алгоритма потом всегда будет нужен.

Добрый вечер. Не могли бы уточнить, допустимо ли такое решение?
Т.е. сперва считаю клеточки, которые необходимо закрасить по Х, затем по Y.
Но почему-то в 99% случаев, когда вставляю сумму закрашенных клеток в переменную mov (“ax”, total) ничего не происходит. В ручную все клеточки, необходимые для закрашивания пересчитывал. Совпадает с total. Может только через функцию работает? 1% (успех) был когда число 28 попало и еще какое-то.
Спасибо.

task_32.py

 @task(delay=0.01)
def task_8_18():
    y = 0
    x = 0
    for c in range(50):
        if wall_is_on_the_right() and not wall_is_beneath() and not wall_is_above() and not wall_is_on_the_left(): break
        elif wall_is_above() and not wall_is_on_the_right():
            fill_cell()
            x += 1
            move_right()
        elif not wall_is_above():
            move_up()
            for c in range(15):
                if wall_is_above() and not cell_is_filled():
                    fill_cell()
                    y += 1
                elif wall_is_above() and cell_is_filled():
                    continue
                elif cell_is_filled():
                    move_up()
                elif not wall_is_above() and not cell_is_filled():
                    fill_cell()
                    y += 1
        else:
            while not wall_is_beneath():
                move_down()
            move_right()
    print("x=", x)
    print("y=", y)
    total = x + y
    print("Кол-во закрашенных клеток:", total)
    mov("ax", total)

Офлайн

#10 Апрель 2, 2020 22:02:52

riomenx
Зарегистрирован: 2019-09-13
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Графический исполнитель "Робот"

Условные действия на каждой итерации цикла
Задача №9: task_8_2
Закрасить клетки. Расстояние до стены не известно.
Решением этой задачи является клетки без верха,которые необходимо закрасить.Есть более простой вариант решения У меня получилось вот так:

 from pyrob.api import *
import time
@task
def task_8_2():
    while not wall_is_on_the_right():
        move_right()
        if not wall_is_above() and wall_is_beneath():
            fill_cell()
    while not wall_is_on_the_left():
        move_left()
        if not wall_is_above() and wall_is_beneath():
            fill_cell()
    while not wall_is_on_the_right():
        move_right()
        if not wall_is_above() and wall_is_beneath():
            fill_cell()
if __name__ == '__main__':
    run_tasks()

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version