diff --git a/packages/index.json b/packages/index.json index f2f1493..aaa931a 100644 --- a/packages/index.json +++ b/packages/index.json @@ -6,7 +6,7 @@ "trapos-net": "0.3.0", "trapos-ui": "0.2.2", "trapos-ai": "0.6.9", - "trapos-sandbox": "0.2.1", + "trapos-sandbox": "0.2.2", "trapos": "0.8.11" } } diff --git a/packages/trapos-sandbox/ccpm.json b/packages/trapos-sandbox/ccpm.json index bdd7d4c..288b9a2 100644 --- a/packages/trapos-sandbox/ccpm.json +++ b/packages/trapos-sandbox/ccpm.json @@ -1,6 +1,6 @@ { "name": "trapos-sandbox", - "version": "0.2.1", + "version": "0.2.2", "description": "TrapOS sandbox programs for ccpm experiments and Lua learning", "dependencies": ["trapos-core"], "files": [ @@ -8,6 +8,7 @@ "apis/libmcpcomputer.lua", "programs/carre.lua", "programs/creeper.lua", + "programs/mouton.lua", "programs/mcp-computer.lua", "servers/mcp-computer-server.lua" ], diff --git a/programs/mouton.lua b/programs/mouton.lua new file mode 100644 index 0000000..ab09028 --- /dev/null +++ b/programs/mouton.lua @@ -0,0 +1,252 @@ +local createVersion = require('/apis/libversion'); + +local args = table.pack(...); + +-- Tete de mouton style Minecraft: un carre de laine avec un visage carre au centre. +-- Les lettres sont des pixels de couleur. Le point est le fond. +local SHEEP = { + '..WWWWWWWWWWWW..', + '.WWwwWWwwWWwwWW.', + 'WWwwWWwwWWwwWWww', + 'Wwwwwwwwwwwwwwww', + 'WWwwKKKKKKKKwwWW', + 'WwwwKkkkkkkKwwww', + 'WWwwKfkkkkfKwwWW', + 'WwwwKfkkkkfKwwww', + 'WWwwKkkMMkkKwwWW', + 'WwwwKkkmmkkKwwww', + 'WWwwKkkkkkkKwwWW', + 'WwwwKKKKKKKKwwww', + 'WWwwwwwwwwwwwwWW', + 'WwWWwwWWwwWWwwWw', + '.WWwwWWwwWWwwWW.', + '..WWWWWWWWWWWW..', +}; + +local THEMES = { + classic = { + title = 'Mouton Minecraft', + background = colors.black, + text = colors.white, + palette = { + ['.'] = colors.black, + W = colors.white, + w = colors.lightGray, + K = colors.gray, + k = colors.lightGray, + f = colors.black, + M = colors.gray, + m = colors.black, + }, + }, + rose = { + title = 'Mouton Rose', + background = colors.black, + text = colors.pink, + palette = { + ['.'] = colors.black, + W = colors.pink, + w = colors.magenta, + K = colors.white, + k = colors.lightGray, + f = colors.black, + M = colors.pink, + m = colors.black, + }, + }, + nuage = { + title = 'Mouton Nuage', + background = colors.lightBlue, + text = colors.white, + palette = { + ['.'] = colors.lightBlue, + W = colors.white, + w = colors.lightGray, + K = colors.gray, + k = colors.white, + f = colors.black, + M = colors.lightGray, + m = colors.black, + }, + }, + arcenciel = { + title = 'Mouton Arc-en-ciel', + background = colors.black, + text = colors.yellow, + rainbow = true, + palette = { + ['.'] = colors.black, + K = colors.white, + k = colors.lightGray, + f = colors.black, + M = colors.pink, + m = colors.black, + }, + }, +}; + +local THEME_NAMES = { 'classic', 'rose', 'nuage', 'arcenciel' }; +local RAINBOW = { + colors.red, + colors.orange, + colors.yellow, + colors.lime, + colors.cyan, + colors.blue, + colors.purple, + colors.magenta, +}; + +local function printUsage() + print('mouton usage:'); + print(); + print(' mouton'); + print(' mouton '); + print(' mouton --theme '); + print(' mouton --random'); + print(' mouton --version'); + print(' mouton --help'); + print(); + print('themes: classic, rose, nuage, arcenciel'); +end + +local function drawRun(x, y, len, color) + term.setBackgroundColor(color); + term.setCursorPos(x, y); + term.write(string.rep(' ', len)); +end + +local function themeNamesText() + return table.concat(THEME_NAMES, ', '); +end + +local function parseArgs(argv) + local selectedTheme = 'classic'; + local selectedExplicitly = false; + local randomTheme = false; + local index = 1; + + while index <= argv.n do + local arg = argv[index]; + + if arg == '--random' or arg == '-random' then + if selectedExplicitly then + return nil, '--random ne peut pas etre combine avec un theme'; + end + randomTheme = true; + elseif arg == '--theme' or arg == '-theme' then + if randomTheme or selectedExplicitly then + return nil, arg .. ' ne peut pas etre combine avec un autre theme'; + end + index = index + 1; + selectedTheme = argv[index]; + if selectedTheme == nil then + return nil, 'theme manquant apres ' .. arg; + end + selectedExplicitly = true; + elseif THEMES[arg] ~= nil then + if randomTheme or selectedExplicitly then + return nil, arg .. ' ne peut pas etre combine avec un autre theme'; + end + selectedTheme = arg; + selectedExplicitly = true; + else + return nil, 'option ou theme inconnu: ' .. tostring(arg); + end + + index = index + 1; + end + + if randomTheme then + math.randomseed(os.epoch('utc')); + selectedTheme = THEME_NAMES[math.random(1, #THEME_NAMES)]; + end + + if THEMES[selectedTheme] == nil then + return nil, 'theme inconnu: ' .. tostring(selectedTheme) + .. ' (disponibles: ' .. themeNamesText() .. ')'; + end + + return THEMES[selectedTheme]; +end + +local function tokenColor(theme, token, row, col) + if theme.rainbow and (token == 'W' or token == 'w') then + -- Pour le mouton arc-en-ciel, seules les boucles de laine changent de couleur. + return RAINBOW[((row + col) % #RAINBOW) + 1]; + end + + return theme.palette[token] or theme.background; +end + +local function drawSheep(theme) + local width, height = term.getSize(); + local pixelW = math.max(1, math.floor(width / 20)); + local pixelH = math.max(1, math.floor(height / 20)); + + if pixelW < 2 and width >= #SHEEP[1] * 2 then pixelW = 2; end + if pixelW > 4 then pixelW = 4; end + if pixelH > 2 then pixelH = 2; end + + local artW = #SHEEP[1] * pixelW; + local artH = #SHEEP * pixelH; + local startX = math.max(1, math.floor((width - artW) / 2) + 1); + local startY = math.max(1, math.floor((height - artH) / 2) + 1); + + term.setBackgroundColor(theme.background); + term.setTextColor(theme.text); + term.clear(); + + for row = 1, #SHEEP do + for sy = 0, pixelH - 1 do + local y = startY + ((row - 1) * pixelH) + sy; + local col = 1; + + while col <= #SHEEP[row] do + local token = SHEEP[row]:sub(col, col); + local run = 1; + local color = tokenColor(theme, token, row, col); + + while col + run <= #SHEEP[row] + and SHEEP[row]:sub(col + run, col + run) == token + and tokenColor(theme, token, row, col + run) == color do + run = run + 1; + end + + drawRun(startX + ((col - 1) * pixelW), y, run * pixelW, color); + col = col + run; + end + end + end + + term.setBackgroundColor(theme.background); + term.setTextColor(theme.text); + + if height >= startY + artH then + term.setCursorPos(math.max(1, math.floor((width - #theme.title) / 2) + 1), startY + artH + 1); + term.write(theme.title); + end + + term.setCursorPos(1, height); +end + +local command = args[1]; + +if command == '-help' or command == '--help' or command == 'help' then + printUsage(); + return; +end + +if command == '-version' or command == '--version' or command == 'version' then + print('v' .. createVersion().forSelf()); + return; +end + +local theme, err = parseArgs(args); +if not theme then + print(err); + print('utilise: mouton -help'); + return; +end + +drawSheep(theme);