Перейти к публикации
Форум - ComputerCraft
DKok

Утилита для форматирования кассет [Computronics]

Рекомендованные сообщения

Написал, вот, утилитку для форматирования кассет из аддона Computronics для OC.

Вообще, эта утилита планируется как часть программного пакета для упрощения работы с кассетами, но её я решил выложить заранее.

 

Процесс форматирования не быстрый и упирается он, в основном, в моё незнание преобразования форматов в Lua. Так как я не нашёл способа преобразования массива в строку, пришлось использовать вот такой костыль:

x = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

В итоге, я тупо храню в коде строку с 256ю терминальными нулями, которыми и забивается кассета (чистые кассеты из мода ими и заполнены). Именно 256 символов за 1 проход цикла я выбрал просто, чтобы не забивать код простынёй нулей, как только я найду способ реализовать это менее банально, планирую увеличить количество терминальных нулей в строке до 512 или 1024. Это ощутимо ускорило бы работу программы.

 

Ссылка на пастебин:

https://pastebin.com/3ucbj3fr

 

Скриншотов не прилагаю, так как интерфейс программы прост, как палка.

 

З.Ы. Это далеко не финальная версия утилиты, выставил её на всеобщее обозрение я только, чтобы получить несколько дельных советов по улучшению проги.

Изменено пользователем DKok
  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Критика принимается? Вот и отлично, пора бы мне набивать количество постов здесь. Итак, что мне не нравится.

 

Хотя нет, сначала отмечу, что эта утилита является велосипедом с tape.lua (см. tape wipe). А теперь отбросим этот факт в сторону и проедемся уже по коду.

 

Стиль кода необычный. Обычно люди так ифы делают:

 

-- Вариант 1
if condition then
  doCode()
end
 
-- Вариант 2
if condition then doCode() end
Хотя я второй вариант не люблю и так не делаю.

 

Ещё по стилю: всякие операторы типа ==, ~= и т. д. лучше отбивать пробелами.

 

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

 

L3. Я сомневаюсь, что "Event" будет работать. Замени на "event"

 

 

local event = require("Event")

 

local event = require("event")
 

L11-12. Переменные size и label объявлены без указания local, поэтому они стали глобальными. Глобальные переменные редко когда требуются, а чаще они просто мешают и творят лишние баги. Поэтому когда без них можно обойтись, делайте переменные локальные.

 

 

size = tape.getSize()
label = tape.getLabel()

 

local size = tape.getSize()
local label = tape.getLabel()
L14-19. Ветки отличаются лишь тем, что при not label пишется "N/A". Дальше нигде отсутствие значения не используется, поэтому код можно сократить, просто присвоив "N/A", если соблюдается not label. Для таких ситуаций офигенно подходит оператор or (подробнее). Кроме того, print уже и так ставит \n, поэтому лучше разделить на два принта.

 

 

if label
then
  print("Tape label: "..label.."\nSize "..size.." bytes.")
else
  print("Tape label: N/A\nSize: "..size.." bytes.")
end

 

label = label or "N/A"
print("Tape label: " .. label)
print("Size: " .. size .. " bytes")
 

Кроме того, зачем просить пользователя самому отмотать кассету в начало, если то же самое делается одной строчкой кода?

 

tape.seek(-math.huge)
 

L28. Для повторения одного символа несколько раз используется функция string.rep. Переменная опять не локальна. И что значит "x"?

 

 

x = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

 

local blockSize = 256
local block = string.rep("\0", blockSize)
 

L30-31. Используем вместо 256 переменную blockSize. И устанавливаем её в качестве шага цикла (0, 256, 512, 768, 1024, ...), потому что так логичнее. И мы не цикл итерируем, поэтому имя у переменной i не соответствует цели использования.

 

 

for i=0,size/256
  do

 

for pos = 0, size, blockSize do
L32-33. Используем переменную block. tape.write сама уже отматывает кассету на позицию, следующую за последним записанным байтом, зачем ещё раз отматывать?

 

 

    tape.write(x)
    tape.seek(256)

 

  tape.write(block)
 

L34. Нет, конечно, можно дать ему заспамить всю консольку прогрессом, но я бы предпочёл немного украсить: заставить его прогресс писать на одной и той же строке. Для этого можно использовать функцию term.clearLine (библиотека term) для очистки строки и io.write вместо print, чтобы не переносился курсор на следующую строку. Первый кусок, который с require, надо поместить в начало файла, где остальные реквайры.

 

 

    print(i.."/"..size/256)

 

local term = require("term")
  term.clearLine()
  io.write(pos .. "/" .. size)
 

L37. С ней проблем нет в оригинальном коде. Однако мы изменили вывод прогресса, так что после выхода из цикла на строке, где стоит курсор, будет находиться ещё какой-то текст с прогрессом. Поэтому надо очистить её перед принтом.

 

 

print("Tape "..label.." was formatted")

 

term.clearLine()
print("Tape has been wiped.")
 

Конец. Итого мы получаем вот такой код мечты:

 

local component = require("component")
local event = require("event")
local term = require("term")
local tape = component.tape_drive
 
if tape.getSize() == 0 then
  print("Tape drive is empty!")
  os.exit(1)
end
 
local size = tape.getSize()
local label = tape.getLabel()
 
label = label or "N/A"
print("Tape label: " .. label)
print("Size: " .. size .. " bytes")
 
print("Press [Y] to wipe the tape. It may take a while.")
local _, _, keyCode = event.pull("key_down")
 
if keyCode ~= 121 then
  os.exit(1)
end

tape.seek(-math.huge)
 
local blockSize = 256
local block = string.rep("\0", blockSize)
 
for pos = 0, size, blockSize do
  tape.write(block)
  term.clearLine()
  io.write(pos .. "/" .. size)
end
 
term.clearLine()
print("Tape has been wiped.")
Изменено пользователем Fingercomp
  • Like 6

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

...

Ух, сколько всего. В общем-то, да. Все замечания, кроме Event по делу и я учту их при доработке утилиты, да и всего пакета ПО для работы с кассетами. А что, касается Event/event, он прекрасно линкуется и с большой буквы. Изменено пользователем eu_tomat
злоупотребление цитированием

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А что до стиля, я перебежчик с Си, там вообще then нет, потому по привычке и перенёс строку, как делаю с фигурными скобками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас

×