local os = require("os") local term = require("term") local event = require("event") local component = require("component") local gpu = component.gpu math.randomseed(os.time()) local version = "Cube v1.0" local level = {} local doors = {} local indicator={} local nick_player local markColor = {0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff, 0xffffff} local playerColor = 3 local sx,sy = gpu.getResolution() sx, sy = math.modf(sx/4), math.modf(sy/2) -- точка отступа/координата игрока на экране (статичные)/центр событий local px,py = 3,3 -- относительные координаты игрока в комнате local min_map, max_map = 1, 1000 -- ограничители номеров комнат, чтобы сильно не запутаться при прохождении level[1] = {number=1, color = 0xffffff, mark=false} -- цель игры - попасть в эту комнату ------------------------------------------------------------------------------------- ----------------------- Генерация случайных формул для дверей ----------------------- local rand_1, rand_2 ,rand_3, rand_4 while true do rand_1, rand_2 ,rand_3, rand_4 = math.random(1,2), math.random(10,30), math.random(1,2), math.random(10,30) if rand_1~=rand_3 and rand_2~=rand_4 then break end end formula={} formula[1]=function(n) return n*rand_1 + rand_2 end formula[2]=function(n) return n*rand_3 + rand_4 end formula[-1]=function(n) return (n - rand_2)/rand_1 end formula[-2]=function(n) return (n - rand_4)/rand_3 end ------------------------------------------------------------------------------------- ---------------------- Возвращает или генерирует новую комнату ---------------------- function gen_level(i) i = tonumber(i) if not level[i] then level[i]={number=i, color = math.random(0x000000, 0xffffff), mark=false} end return level[i] end ------------------------------------------------------------------------------------- -------------------------- Проверка, существует ли комната -------------------------- function proverka(x,y) -- где x номер формулы, y номер текущей комнаты local number = formula[x](y) return number >= min_map and number <= max_map and number == math.modf(number) end ------------------------------------------------------------------------------------- ---------------------------- Генерация статистики комнат ---------------------------- function sorting(sorting_table, not_sorting_table) local trash_table={} while true do if #not_sorting_table==0 then break else local new_level = not_sorting_table[1] local power = true for i=1, #sorting_table do if sorting_table[i][1]== new_level[1] then power = false if new_level[2] < sorting_table[i][2] then sorting_table[i][2]=new_level[2] if proverka(1,new_level[1]) then trash_table[#trash_table+1] = {formula[1](new_level[1]), new_level[2]+1} end if proverka(2,new_level[1]) then trash_table[#trash_table+1] = {formula[2](new_level[1]), new_level[2]+1} end if proverka(-1,new_level[1]) then trash_table[#trash_table+1] = {formula[-1](new_level[1]), new_level[2]+1} end if proverka(-2,new_level[1]) then trash_table[#trash_table+1] = {formula[-2](new_level[1]), new_level[2]+1} end end table.remove(not_sorting_table,1) end end if power then sorting_table[#sorting_table+1] = new_level table.remove(not_sorting_table,1) if proverka(1,new_level[1]) then not_sorting_table[#not_sorting_table+1] = {formula[1](new_level[1]), new_level[2]+1} end if proverka(2,new_level[1]) then not_sorting_table[#not_sorting_table+1] = {formula[2](new_level[1]), new_level[2]+1} end if proverka(-1,new_level[1]) then not_sorting_table[#not_sorting_table+1] = {formula[-1](new_level[1]), new_level[2]+1} end if proverka(-2,new_level[1]) then not_sorting_table[#not_sorting_table+1] = {formula[-2](new_level[1]), new_level[2]+1} end end end end return sorting_table, trash_table end -- первая сортировка local not_sorting_tb, trash_tb={} not_sorting_tb[1]={1,0} local sorting_tb, trash_tb = sorting({}, not_sorting_tb) -- последующие сортировки while true do not_sorting_tb = trash_tb sorting_tb, trash_tb = sorting(sorting_tb, not_sorting_tb) if #trash_tb == 0 then break end end -- очищаем память not_sorting_tb, trash_tb = nil, nil -- перестраиваем таблицу local stat_table={} for i=1, #sorting_tb do stat_table[sorting_tb[i][1]]=sorting_tb[i][2] end ------------------------------------------------------------------------------------- ------------------ Находим номер самой удалённой комнаты от выхода ------------------ local j=1 for i=1, #sorting_tb do if sorting_tb[i][2]>sorting_tb[j][2] then j=i end end ------------------------------------------------------------------------------------- ----------------------- Устанавливаем номер стартовой комнаты ----------------------- local chamber = gen_level(sorting_tb[j][1]) -- запишем количество комнат в игре local max_table, max_level = #sorting_tb, sorting_tb[j][2] -- удалим из памяти ненужную таблицу sorting_tb = nil ------------------------------------------------------------------------------------- --------------------------- Переставляет двери в комнате ---------------------------- function reload_doors() local rezerv={} for i=1,4 do -- занесём двери в базу данных, чтобы знать использованные формулы if doors[i] then rezerv[#rezerv+1]=doors[i] end end for i=1,4 do -- перебираем все 4 двери if not doors[i] then while true do local rand = math.random(-2,2) local rezerv_2 = 0 if rand ~= 0 then if #rezerv > 0 then -- проверка, есть ли комната с такой же формулой for j=1, #rezerv do if rezerv[j] == rand then break else rezerv_2 = rezerv_2 + 1 end end end if rezerv_2 == #rezerv then -- если нет повторяющихся формул, то присваивается данная формула doors[i] = rand rezerv[#rezerv+1]=rand break end end end end end end -- //данная функция достаточно сложна чтобы запутаться ------------------------------------------------------------------------------------- ---------------------------------- Рисования меток ---------------------------------- function mark_print(nx, ny, number) if level[number].mark then for i=1, #level[number].mark do gpu.setBackground(level[number].mark[i][3]) gpu.set((level[number].mark[i][1]+nx)*2, level[number].mark[i][2]+ny, " ") end end end ------------------------------------------------------------------------------------- ------------------------- Рисования комнаты по координатам -------------------------- function level_print(nx, ny, color, number) number = tostring(number) gpu.setBackground(color) gpu.set(nx*2, ny, " ") gpu.set((nx+4)*2, ny, " ") gpu.set(nx*2, ny+6, " ") gpu.set((nx+4)*2, ny+6, " ") gpu.set(nx*2, ny+1, " ") gpu.set(nx*2, ny+2, " ") gpu.set(nx*2, ny+4, " ") gpu.set(nx*2, ny+5, " ") gpu.set((nx+6)*2, ny+1, " ") gpu.set((nx+6)*2, ny+2, " ") gpu.set((nx+6)*2, ny+4, " ") gpu.set((nx+6)*2, ny+5, " ") gpu.setBackground(0x000000) gpu.set(nx*2+6-math.modf((string.len(number)-1)/2), ny+3, number) end ------------------------------------------------------------------------------------- ----------------------------- Переходы между комнатами ------------------------------ pxx, pyy = {}, {} pxx[-1]=function(nx) local rezerv_3 = doors[1] if proverka(rezerv_3, chamber.number) then doors={} doors[2] = -rezerv_3 reload_doors() chamber = gen_level(formula[rezerv_3](chamber.number)) ppx = 6 else ppx = px end end pxx[7]=function(nx) local rezerv_3 = doors[2] if proverka(rezerv_3, chamber.number) then doors={} doors[1] = -rezerv_3 reload_doors() chamber = gen_level(formula[rezerv_3](chamber.number)) ppx = 0 else ppx = px end end pyy[-1]=function(ny) local rezerv_3 = doors[3] if proverka(rezerv_3, chamber.number) then doors={} doors[4] = -rezerv_3 reload_doors() chamber = gen_level(formula[rezerv_3](chamber.number)) ppy = 6 else ppy = py end end pyy[7]=function(ny) local rezerv_3 = doors[4] if proverka(rezerv_3, chamber.number) then doors={} doors[3] = -rezerv_3 reload_doors() chamber = gen_level(formula[rezerv_3](chamber.number)) ppy = 0 else ppy = py end end -- //работает как надо, но лучше подредактировать ------------------------------------------------------------------------------------- -------------------------------- Передвижение игрока -------------------------------- function player_update(nx,ny) ppx, ppy = px+nx, py+ny if not ((ppx==0 or ppy==0 or ppx==6 or ppy==6) and ppx~=3 and ppy~=3) then if pxx[ppx] then pxx[ppx](ppx) elseif pyy[ppy] then pyy[ppy](ppy) end px,py = ppx,ppy end end -- //работает как надо, но лучше подредактировать ------------------------------------------------------------------------------------- --------------------------------- Блок отображения ---------------------------------- function update(nick) nick_player = nick term.clear() -- текущая комната gen_level(chamber.number) mark_print(sx-px,sy-py, chamber.number) level_print(sx-px,sy-py,chamber.color, chamber.number) -- комната слева if proverka(doors[1], chamber.number) and px==0 then local number = formula[doors[1]](chamber.number) gen_level(number) mark_print(sx-7-px,sy-py, number) level_print(sx-7-px,sy-py,gen_level(formula[doors[1]](chamber.number)).color, gen_level(formula[doors[1]](chamber.number)).number) end -- комната справа if proverka(doors[2], chamber.number) and px==6 then local number = formula[doors[2]](chamber.number) gen_level(number) mark_print(sx+7-px,sy-py, number) level_print(sx+7-px,sy-py,gen_level(formula[doors[2]](chamber.number)).color, gen_level(formula[doors[2]](chamber.number)).number) end -- комната сверху if proverka(doors[3], chamber.number) and py==0 then local number = formula[doors[3]](chamber.number) gen_level(number) mark_print(sx-px,sy-7-py, number) level_print(sx-px,sy-7-py,gen_level(formula[doors[3]](chamber.number)).color, gen_level(formula[doors[3]](chamber.number)).number) end -- комната снизу if proverka(doors[4], chamber.number) and py==6 then local number = formula[doors[4]](chamber.number) gen_level(number) mark_print(sx-px,sy+7-py, number) level_print(sx-px,sy+7-py,gen_level(formula[doors[4]](chamber.number)).color, number) end -- отображение игрока gpu.setBackground(0xff0000) gpu.set(sx*2, sy, " ") -- текстовые индикаторы for i=1, #indicator do indicator[i]() end -- индикатор выбранного цвета gpu.setBackground(markColor[playerColor]) gpu.set(2, sy*2, " ") end ------------------------------------------------------------------------------------- ---------------------------------- Блок управления ---------------------------------- local command={} command[200]=function() player_update(0,-1) end -- вверх command[208]=function() player_update(0,1) end -- вниз command[203]=function() player_update(-1,0) end -- влево command[205]=function() player_update(1,0) end -- вправо command[17]=function() -- ставить метку if not level[chamber.number].mark then level[chamber.number].mark={} end level[chamber.number].mark[#level[chamber.number].mark+1]={px,py,markColor[playerColor]} end command[30]=function() if playerColor-1<1 then playerColor=#markColor else playerColor=playerColor-1 end end -- цвет слева command[32]=function() if playerColor+1>#markColor then playerColor=1 else playerColor=playerColor+1 end end -- цвет справа command[31]=function() -- удалить метку if level[chamber.number].mark then for i=#level[chamber.number].mark, 1, -1 do if px==level[chamber.number].mark[i][1] and py==level[chamber.number].mark[i][2] then table.remove(level[chamber.number].mark,i) end end end end command[23]=function() -- включает режим разработчика if #indicator==0 then indicator[1]=function() gpu.setBackground(0x000000) gpu.setForeground(0xffff00) gpu.set(2, 2, "max level: "..max_level) gpu.set(2, 3, "all levels: "..max_table) gpu.set(2, 4, "this level: "..stat_table[chamber.number]) gpu.setForeground(0xff0000) gpu.set(2, 5, "formula 1: ".."n".."*"..rand_1.." + "..rand_2) gpu.set(2, 6, "formula 2: ".."n".."*"..rand_3.." + "..rand_4) gpu.set(2, 7, "formula -1: ".."(n - "..rand_2..")/"..rand_1) gpu.set(2, 8, "formula -2: ".."(n - "..rand_4..")/"..rand_3) gpu.setForeground(0xff00ff) gpu.set(2, 9, "progress: " .. math.modf(100-stat_table[chamber.number]*100/max_level).."%") gpu.setForeground(0xff00ff) gpu.set(2, 10, "color: "..playerColor) gpu.setForeground(0xffffff) end else table.remove(indicator,1) end end command[35]=function() -- отобразить управление term.clear() gpu.setForeground(0xff0000) print(version) print("") gpu.setForeground(0x00ff00) print("Target: searching chamber 1") print("Game 100% passable") gpu.setForeground(0xffff00) print("Control:") print("Q - exit game") print("H - help") print("I - info") print("W - set mark") print("S - remove mark") print("A - back color mark") print("D - next color mark") print("") gpu.setForeground(0xffffff) print("press enter to continue...") while true do _,_,_, key = event.pull("key_down") if key == 28 then break end end end ------------------------------------------------------------------------------------- ---------------------- Показываем управление до начала игры ------------------------- command[35]() ------------------------------------------------------------------------------------- ------------------------- Отображение комнат до начала игры ------------------------- reload_doors() update(nick) gpu.setBackground(0x000000) ------------------------------------------------------------------------------------- ------------------------------------- Тело игры ------------------------------------- while true do _,_,_, key, nick = event.pull("key_down") if key==16 then term.clear() gpu.setForeground(0xff0000) print("Exit to game?") gpu.setForeground(0xffffff) print("") print("y/n") while true do _,_,_, key = event.pull("key_down") if key == 21 then term.clear() return elseif key == 49 then break end end elseif command[key] then command[key]() end update(nick) gpu.setBackground(0x000000) if chamber.number == 1 then break end -- цель игры, комната с этим номером os.sleep(1/15) -- задержка, для более удобного управления end ------------------------------------------------------------------------------------- ------------------------------------- Прощание ------------------------------------- term.clear() gpu.setForeground(0x00ff00) print("Congratulations "..nick_player.."!") print("You win!") print("") gpu.setForeground(0xffffff) print("press enter to exit...") while true do _,_,_, key = event.pull("key_down") if key == 28 then break end end term.clear() -------------------------------------------------------------------------------------