name | correct guesses | games together | ratio |
---|---|---|---|
seshoumara | 5 | 5 | 1.000 |
olive | 7 | 8 | 0.875 |
Palaiologos | 3 | 4 | 0.750 |
moshikoi | 5 | 10 | 0.500 |
luatic | 9 | 18 | 0.500 |
rrebbbbeca | 2 | 4 | 0.500 |
olus2000 | 9 | 19 | 0.474 |
ponydork | 2 | 5 | 0.400 |
oleander | 4 | 10 | 0.400 |
theqwertiest | 2 | 5 | 0.400 |
Dolphy | 7 | 18 | 0.389 |
LyricLy | 10 | 26 | 0.385 |
Olivia | 4 | 11 | 0.364 |
essaie | 5 | 14 | 0.357 |
yeti | 2 | 6 | 0.333 |
JJRubes | 2 | 6 | 0.333 |
taswelll | 3 | 11 | 0.273 |
chirk | 3 | 13 | 0.231 |
soup girl | 1 | 5 | 0.200 |
Moja | 1 | 7 | 0.143 |
yui | 1 | 8 | 0.125 |
hyacinth | 0 | 5 | 0.000 |
Makefile_dot_in | 0 | 6 | 0.000 |
ultlang | 0 | 4 | 0.000 |
razetime | 0 | 7 | 0.000 |
at | 0 | 4 | 0.000 |
name | correct guesses | games together | ratio |
---|---|---|---|
olive | 7 | 8 | 0.875 |
luatic | 12 | 18 | 0.667 |
Dolphy | 12 | 19 | 0.632 |
rrebbbbeca | 3 | 5 | 0.600 |
yui | 4 | 8 | 0.500 |
LyricLy | 13 | 26 | 0.500 |
Olivia | 5 | 11 | 0.455 |
razetime | 3 | 7 | 0.429 |
hyacinth | 2 | 5 | 0.400 |
seshoumara | 2 | 5 | 0.400 |
essaie | 5 | 14 | 0.357 |
moshikoi | 3 | 10 | 0.300 |
Moja | 2 | 7 | 0.286 |
Makefile_dot_in | 2 | 7 | 0.286 |
chirk | 3 | 11 | 0.273 |
oleander | 3 | 11 | 0.273 |
olus2000 | 5 | 19 | 0.263 |
theqwertiest | 1 | 5 | 0.200 |
taswelll | 2 | 11 | 0.182 |
JJRubes | 1 | 6 | 0.167 |
ponydork | 0 | 5 | 0.000 |
yeti | 0 | 4 | 0.000 |
Palaiologos | 0 | 4 | 0.000 |
ultlang | 0 | 4 | 0.000 |
at | 0 | 4 | 0.000 |
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | const target = 'https://codeguessing.gay/84/'; const reset = `${target}_verify/reset`; const opts = { headers: { 'Accept': 'text/html' } }; if (!('window' in globalThis)) { fetch = require("fetch-cookie").default(fetch); } class ReadIterator { reader; constructor(readableReader) { this.reader = readableReader; } [Symbol.asyncIterator]() { return this; } async return() { this.reader.releaseLock(); } async next() { return this.reader.read(); } } async function scrape() { let response = await fetch(target, opts).then(res => res.text()); if (!response.match(/anti-scraper protection.*\n.*meta http-equiv="refresh"/)) { return response; } response = ''; let reader = new ReadIterator(await fetch(target, opts).then(res => res.body.getReader())); let decoder = new TextDecoder(); let key; for await (let chunk of reader) { let m; if (!key) { response += decoder.decode(chunk); m = response.match(/a href=(\/84\/_verify\/[^ ]*)[^<]*verify/i); } if (m) { key = m[1]; await fetch(new URL(key, target), opts); } } response = await fetch(target, opts).then(res => res.text()); if (reset) fetch(reset).catch(() => {}); return response; } scrape().then(console.log); |
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | for line in io.lines(...) do local mines, msep local orig_line = line mines, msep, line = line:match('^(%d+)( *|)(.*)$') mines = tonumber(mines) or -1 msep = msep or "" line = line or "" local off = #(mines .. msep) local grid = {} for i = 1, #line do local c = line:sub(i,i) if c == '-' or (tonumber(c) and tonumber(c) <= 2) then grid[#grid+1] = { off = off + i - 1, val = c ~= '-' and tonumber(c), mine_hits = 0, total_hits = 0, local_mines = 0, local_hits = 0 } end end grid.total_hits = 0 grid.mine_hits = 0 grid.mines = mines local mutagen = {} local function writer() local off = 0 return function (x, c) c = tostring(c) assert(x >= off) io.write((' '):rep(x - off), c) off = x + #c end end local function postrecur() local sels = {} for i, v in ipairs(grid) do if grid[i].local_mines == 0 and grid[i].local_hits > 0 then sels[i] = true end end for i, v in ipairs(grid) do if grid[i].local_mines == grid[i].local_hits or (sels[i] and not sels[i]) then grid.total_hits = grid.total_hits - grid[i].total_hits grid.mine_hits = grid.mine_hits - grid[i].mine_hits grid[i].mine_hits = 0 grid[i].total_hits = 0 end end end local function recursor(len, mines) local function mutaget(i) if i > len or i < 1 then return 0 end return mutagen[i] and 1 or 0 end local function mutacheck(i) if i > len or i < 1 then return true end if not (grid[i] or {}).val then return true end return mutaget(i - 1) + mutaget(i + 1) == grid[i].val end if mines < 0 or not mutacheck(len - 1) then return end if len == #grid then if mines > 0 or not mutacheck(len) then return end local unknown = 0 for i = 1, len do if not grid[i].val then unknown = unknown + 1 end end if unknown > grid.mines then for i = 1, len do grid[i].local_hits = grid[i].local_hits + 1 grid[i].local_mines = grid[i].local_mines + (mutagen[i] and 1 or 0) if mutagen[i] then grid.total_hits = grid.total_hits + 1 grid.mine_hits = grid.mine_hits + 1 grid[i].mine_hits = grid[i].mine_hits + 1 grid[i].total_hits = grid[i].total_hits + 1 elseif not grid[i].val then local oldgrid = grid grid = {} for i, v in ipairs(oldgrid) do grid[i] = { val = v.val, off = v.off, mine_hits = 0, total_hits = 0, local_mines = 0, local_hits = 0 } end grid.total_hits = 0 grid.mine_hits = 0 grid.mines = oldgrid.mines local function reveal(i) if i > len or i < 1 then return false end if mutaget(i) > 0 then return end if grid[i].val then return false end grid[i].val = mutaget(i - 1) + mutaget(i + 1) if grid[i].val == 0 then reveal(i - 1) reveal(i + 1) end return true end reveal(i) local oldmutagen = mutagen mutagen = {} recursor(0, grid.mines) postrecur() oldgrid[i].mine_hits = oldgrid[i].mine_hits + grid.mine_hits oldgrid[i].total_hits = oldgrid[i].total_hits + grid.total_hits oldgrid.mine_hits = oldgrid.mine_hits + grid.mine_hits oldgrid.total_hits = oldgrid.total_hits + grid.total_hits grid = oldgrid mutagen = oldmutagen unknown = unknown + 1 end end else grid.total_hits = grid.total_hits + 1 end return end local i = len + 1 if not grid[i].val then mutagen[i] = true recursor(i, mines - 1) end mutagen[i] = false return recursor(i, mines) end recursor(0, mines) postrecur() if grid.total_hits == 0 then print('invalid board') else local minimum = math.huge for i = 1, #grid do if grid[i].mine_hits/grid[i].total_hits < minimum and not grid[i].val then minimum = grid[i].mine_hits / grid[i].total_hits end end local function stty(isterm, term) if isterm ~= nil then return isterm end isterm = os.execute('stty <&'..(term or 0)..' >/dev/null 2>&1') if tonumber(isterm) then isterm = tonumber(isterm) == 0 end return isterm end isterm_in = stty(isterm_in, 0) isterm_out = stty(isterm_out, 1) if isterm_out and not isterm_in then io.stderr:write(orig_line .. "\n") io.stderr:flush() end local write = writer() for i = 1, #grid do if grid[i].mine_hits/grid[i].total_hits == minimum and not grid[i].val then write(grid[i].off, '^') end end print((' %.1f%%'):format(math.floor((1-minimum)*1000+.5)/10)) end end |
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // ==ByteBeat== // @mode funcbeat // @freq 44100 // ^^^ in bytebeat-composer, // use 48kHz instead // @len 5780275 // @dcClean no // @term 80x13 // ==/ByteBeat== l=131.072,fnv=(v,h,p)=>(v|=0,v%=500*l,v?(h=0x811c9dc5,p=0x1000193, h^=(v>> 0)&0xff,h=(h-(1<<31))*p,h^=(v>> 8)&0xff,h=(h-(1<<31))*p, h^=(v>>16)&0xff,h=(h-(1<<31))*p,h^=(v>>24)&0xff,h=(h-(1<<31))*p, h=((h|0)-(1<<31))/2**32*2-1):0);ip=(c,d,x)=>(x=max(0,min(1,x))**2, c+(x*x*x*(x*(6*x-15)+10))*(d-c));vnoise=(x,X,Y)=>( X=fnv(floor(x)),Y=fnv(ceil(x)),ip(X,Y,x%1)); disp=(t,w,h,d)=>{throw w=80,h=12,d=[...Array(w)] .map((_,i)=>floor((vnoise(max(2,floor(t*500/16)) *16-(w-1-i)/w*32)+1)/2*h)),'\n'+[...Array(h)] .map((_,i)=>d.map(e=>((e<i)?'|':((e==i)?'O':'.'))).join('')) .join('\n')+`\n[${[Array(round(t%l/l*78)).fill('=').join('') +Array(78-round(t%l/l*78)).fill('-').join('')]}]`}; return t => t*100%1?vnoise(t*500):disp(t); |
submitted at
0 likes
top ten pro gamer tips:
10 use the left mouse button to create or reposition cubes
9 use the right mouse button to attach cubes to each other or the environment
8 be aware that cubes do not handle strong impacts well
7 press the space bar to toggle freezing and unfreezing the game world
6
5
4
3
2
1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | Object = { assign = function( dst , src ) for k , v in pairs( src ) do dst [ k ] = v end end }; function OOB( boulder ) local w = love . graphics . getWidth() local h = love . graphics . getHeight() for n = 1 , # boulder , 2 do if boulder [ n ] >= 0 and boulder [ n ] <= w and boulder [ n + 1 ] <= h then return false end end return true end function drawBoulder( body , ... ) love . graphics . polygon( "fill" , ... ) if body : getType() == "dynamic" and OOB { ... } then toDestroy [ body ] = true end end print( "meow\n" ) function checkBoulderDestructure( boulder , impulse ) if boulder : getType() ~= "dynamic" then return end if 32000 /( boulder : getMass()) < impulse then destructures [ boulder ] = true end end function destructure( b ) local b2s = {} local r = b : getFixtures()[ 1 ]: getUserData() / 2 local bins = { b : getWorldPoints( - r / 2 , - r / 2 , - r / 2 , r / 2 , r / 2 , - r / 2 , r / 2 , r / 2 )} for n = 1 , # bins , 2 do local b2 = love . physics . newBody( world , bins [ n ], bins [ n + 1 ], "dynamic" ) b2 : setAngle( b : getAngle()) b2 : setLinearVelocity(b : getLinearVelocityFromWorldPoint( bins [ n ], bins [ n + 1 ])) b2 : setAngularVelocity( b : getAngularVelocity()) b2s [ # b2s + 1 ] = b2 local f = love . physics . newFixture( b2 , love . physics . newRectangleShape( r , r ), 1 ) f : setUserData( r ) f : setFriction( 0.9 ) end b : destroy() return b2s end function findBody( x , y ) for _ , b in ipairs( world : getBodies()) do for _ , f in ipairs( b : getFixtures()) do if f : testPoint( x , y ) then return b end end end end Object . assign( love , { load = function() world = love . physics . newWorld( 0 , 800 ); ground = love . physics . newBody( world , love . graphics . getWidth() / 2 , love . graphics . getHeight() + 100 , "static" ) love . physics . newFixture( ground , love . physics . newRectangleShape( love . graphics . getWidth() * 2 , 200 ), 1 ): setFriction( 0.9 ) world : setCallbacks( nil , nil , nil , function( a , b , _ , ... ) local imps = { ... } local imp = 0 for n = 1 , # imps , 2 do imp = math . max( imp , imps [ n ]) end checkBoulderDestructure( a : getBody(), imp ) checkBoulderDestructure( b : getBody(), imp ) end ) end , update = function( dt ) if mouseJoint and mouseJoint : isDestroyed() then mouseJoint = nil end if mouseJoint then local mx , my = love . mouse . getPosition() if paused then local jx , jy = mouseJoint : getTarget() local b = mouseJoint : getBodies() local x , y = b : getPosition() b : setPosition( x + mx - jx , y + my - jy ) end mouseJoint : setTarget( mx , my ) end destructures = {} if not paused then world : update( dt ) end for b , _ in pairs( destructures ) do for _ , b in ipairs( destructure( b )) do destructure( b ) end end if mouseJoint and mouseJoint : isDestroyed() then mouseJoint = nil end end , mousepressed = function( x , y , k ) local body = findBody( x , y ) if k == 2 and body then toJoint = body preJoint = love . physics . newMouseJoint( body , x , y ) toJx = x toJy = y end if k ~= 1 then return end if not body then body = love . physics . newBody( world , x , y , "dynamic" ) local f = love . physics . newFixture( body , love . physics . newRectangleShape( 60 , 60 ), 1 ) f : setUserData( 60 ) f : setFriction( 0.9 ) end if mouseJoint then mouseJoint : destroy() end mouseJoint = love . physics . newMouseJoint( body , x , y ) end , keypressed = function( k ) if k == "space" then paused = not paused end end , mousereleased = function( x , y , k ) if k == 2 and toJoint then local body2 = findBody( x , y ) local body = toJoint if toJoint : isDestroyed() then preJoint = nil toJoint = nil toJx = nil toJy = nil end toJoint = nil local x2 , y2 = toJx , toJy toJx = nil toJy = nil preJoint : destroy() preJoint = nil if( not body2 ) or body2 == body then body2 = ground end love . physics . newDistanceJoint( body , body2 , x2 , y2 , x , y , true ) end if k ~= 1 then return end if mouseJoint then mouseJoint : destroy() mouseJoint = nil end end , draw = function() love . graphics . clear( 0 , 0 , 1 ) love . graphics . setColor( 1 , 1 , 1 ) toDestroy = {} local seenj = {} for _ , b in ipairs( world : getBodies()) do for _ , f in ipairs( b : getFixtures()) do if f : getShape(): getType() == "polygon" then drawBoulder( b , b : getWorldPoints( f : getShape(): getPoints())) end end end love . graphics . setColor( 0.5 , 0.5 , 0.5 ) if toJoint and not toJoint : isDestroyed() then love . graphics . line( toJx , toJy , love . mouse . getPosition()) end for _ , b in ipairs( world : getBodies()) do for _ , j in ipairs( b : getJoints()) do if j : getType() == "distance" and not seenj [ j ] then seenj [ j ] = true love . graphics . line( j : getAnchors()) end end end local seen = {} local todo = {} for _ , b in pairs( world : getBodies()) do for _ , j in ipairs( b : getJoints()) do if j : getType() == "mouse" then toDestroy [ b ] = nil break end end if not toDestroy [ b ] then todo [ b ] = true seen [ b ] = true end end while next( todo ) do local ntodo = {} for b , _ in pairs( todo ) do for _ , j in pairs( b : getJoints()) do for _ , b2 in ipairs({ j : getBodies()}) do if not seen [ b2 ] then ntodo [ b2 ] = true toDestroy [ b2 ] = nil seen [ b2 ] = true end end end end todo = ntodo end for b , _ in pairs( toDestroy ) do b : destroy() end toDestroy = nil end , }); |
submitted at
2 likes
extra details: set the frequency to 48000 to avoid distortion change the value twelve in the code to try out different tempos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // You can try this online at https://bytebeat.ficial.net/ // Use Funcbeat playback mode str="Hello, World!"; // <-- your data here t=[["A",".-"],["B","-..."],["C","-.-."],["D","-.."],["E","."], ["F","..-."],["G","--."],["H","...."],["I",".."],["J",".---"], ["K","-.-"],["L",".-.."],["M","--"],["N","-."],["O","---"], ["P",".--."],["Q","--.-"],["R",".-."],["S","..."],["T","-"], ["U","..-"],["V","...-"],["W",".--"],["X","-..-"],["Y","-.--"], ["Z","--.."],["0","-----"],["1",".----"],["2","..---"], ["3","...--"],["4","....-"],["5","....."],["6","-...."], ["7","--..."],["8","---.."],["9","----."],["&",".-..."], ["'",".----."],["@",".--.-."],[")","-.--.-"],["(","-.--."], [":","---..."],[",","--..--"],["=","-...-"],["!","-.-.--"], [".",".-.-.-"],["-","-....-"],["×","-..-"],["x","-..-"], ["%","------..-.-----"],["+",".-.-."],['"',".-..-."], ["?","..--.."],["/","-..-."],["\n",".-.-"],[" "," "]]; t=Object.fromEntries(t.map(([k,v])=>[k,[...v] .map(c=>(({'-':'111','.':'1',' ':'0'})[c])).join('0')])); l=[...str.toUpperCase()].map(c=>t[c]).join('000'); return (T,f)=>(d=1/16,i=T*12+d/2,p=min(1,(i)%1/d), ((+(l[int(i)-1]??0))*(1-p)+(+(l[int(i)]??0))*(p)) *(sin(T*440*PI*2)*0.5)) |
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | <!-- best played on computer, sorry phone prisoners --> <style> html, body { margin: 0; padding: 0; } body { background-color: black; width:100vw; height: 100vh; overflow: hidden; position: relative; } body[paused] { background-color: #111; } .star { background-color: #fff; } .fire { border: 1px solid red; } .sel { border: 1px solid cyan; } .fire, .star, .sel { border-radius: 100%; position: absolute; } </style> <body id="body"> <script> var datakey = "$XDG_CONFIG_DIR/CG79/entry.html.conf"; var config = { camX: 0, camY: 0, zoom: 1, speed: 1, objects: {}, pause: false, ...(localStorage[datakey] ? JSON.parse(localStorage[datakey]) : {}) }; Object.values(config.objects) .forEach(obj => starElement(obj)); function saveConfig() { localStorage[datakey] = JSON.stringify({ ...config, objects: Object.fromEntries( Object.entries(config.objects) .map(([k, v]) => [k, Object.fromEntries( Object.entries(v) .filter(([k, v]) => k != 'element') )]) ) }); } setInterval(_ => saveConfig(), 100); var newObj = null; var throwObj = null; var selObj = null; function screenToWorld(cx, cy) { var [w, h ] = [body.clientWidth, body.clientHeight]; var [wx, wy] = [cx - w/2, cy - h/2 ]; [wx, wy] = [wx / h, wy / h ]; [wx, wy] = [wx / config.zoom, wy / config.zoom ]; [wx, wy] = [wx + config.camX, wy + config.camY ]; return [wx, wy] ; } function worldToScreen(wx, wy) { var [w, h ] = [body.clientWidth, body.clientHeight]; var [cx, cy] = [wx - config.camX, wy - config.camY ]; [cx, cy] = [cx * config.zoom, cy * config.zoom ]; [cx, cy] = [cx * h, cy * h ]; [cx, cy] = [cx + w/2, cy + h/2 ]; return [cx, cy] ; } function randomID() { return [...crypto.getRandomValues(new Uint8Array(2))] .map(e => e.toString(16).padStart(2, 0)) .join(''); } function reset() { localStorage[datakey] = '{}'; saveConfig = function() {}; location.reload(); } randomID = (function(randomID) { return function() { if (Object.keys(config.objects).length >= (256 ** (randomID().length / 2)) * 0.8) { body.remove(); localStorage[datakey] = '{}'; document.innerHTML = `<body>You're cringe</body>`; throw new Error(document.textContent); } while (1) { var id = randomID(); if (!(id in config.objects)) return id; } } })(randomID); function starElement(obj) { if ((!obj.element) || obj.element.parentElement != body) { obj.element = document.createElement('div'); obj.element.className = obj.sel ? 'sel' : (obj.obj ? 'fire' : 'star'); body.append(obj.element); } var [ sx, sy ] = worldToScreen(obj.x, obj.y); var [ sx2, sy2 ] = worldToScreen( obj.x + obj.r, obj.y + obj.r, ); obj.element.style.width = '1000px'; obj.element.style.height = '1000px'; obj.element.style.top = '-500px'; obj.element.style.left = '-500px'; obj.element.style.transform = `translate(${sx}px, ${sy}px) scale(${(sx2 - sx)/500}, ${(sy2 - sy)/500})`; return obj; } var targetStep = 1/120; var accumTime = 0; var maxSteps = 1; var updateTime = 0; function draw(dt) { dt *= config.speed; if (updateTime / dt > 0.8) { maxSteps = Math.max(1, maxSteps - 1); } else { maxSteps = maxSteps + 1; } accumTime += dt; accumTime = Math.min(accumTime, 5); var begin = performance.now(); for (var i = 0; i < maxSteps && accumTime >= targetStep; i++) { update(targetStep); accumTime -= targetStep; } updateTime = performance.now() - begin; [ ...(newObj ? [newObj] : []), ...(throwObj ? [throwObj] : []), ...(selObj ? [selObj] : []), ...Object.values(config.objects) ] .forEach(e => starElement(e)); } function gravity(dest, src, out) { if (dest.mass == 0 || src.mass == 0) return; var G = 10; // cartoon physics var r = Math.hypot( dest.x - src.x, dest.y - src.y ); if (r < (dest.r + src.r)) { G = 0; let objs = [dest, src].sort((a, b) => a.mass - b.mass); [objs[0].x, objs[0].y, objs[0].vx, objs[0].vy] = [ (dest.x * dest.mass + src.x * src.mass) / (src.mass + dest.mass), (dest.y * dest.mass + src.y * src.mass) / (src.mass + dest.mass), (dest.vx * dest.mass + src.vx * src.mass) / (src.mass + dest.mass), (dest.vy * dest.mass + src.vy * src.mass) / (src.mass + dest.mass), ]; [objs[0].r, objs[0].mass] = [ (((4/3)*Math.PI*(src.r**3) + (4/3)*Math.PI*(dest.r**3)) / (4/3*Math.PI)) ** (1/3), src.mass + dest.mass ]; [src.anchor, dest.anchor] = [0,0].map(_ => src.anchor && dest.anchor); if (!src.anchor) delete src.anchor; if (!dest.anchor) delete dest.anchor; objs[1].r = 0; objs[1].mass = 0; delete config.objects[objs[1].id]; objs[1].element.remove(); } var [dx, dy] = [ src.x - dest.x, src.y - dest.y ]; var d = Math.hypot(dx, dy); [dx, dy] = [ dx / d, dy / d ]; out[0] += G * (dest.mass * src.mass) / (r**2) * dx / dest.mass; out[1] += G * (dest.mass * src.mass) / (r**2) * dy / dest.mass; } function update(dt) { if (throwObj || newObj || config.pause) { body.setAttribute('paused', ''); return; } else { body.removeAttribute('paused'); } // 4th order Yoshida integrator var w0 = -(2**(1/3))/(2-(2**(1/3))), w1 = 1/(2-(2**(1/3))), c1, c2, c3, c4, d1, d2, d3, a; c1 = c4 = w1 / 2; c2 = c3 = (w0 + w1) / 2; d1 = d3 = w1; d2 = w0; var c = [,c1,c2,c3,c4]; var d = [,d1,d2,d3]; let objs = Object.values(config.objects) .filter(obj => ( +obj.x == obj.x && +obj.y == obj.y && +obj.r == obj.r && +obj.mass == obj.mass && +obj.vx == obj.vx && +obj.vy == obj.vy )); for (let k = 1; k <= 4; k++) { for (let obj of objs) { if (c[k]) { [obj.x, obj.y] = [ obj.x + c[k]*obj.vx*dt, obj.y + c[k]*obj.vy*dt, ]; } if (d[k]) { let a = [0, 0]; for (let alt of objs) { if (alt != obj) { gravity(obj, alt, a); } } [obj.vx, obj.vy] = [ obj.vx + d[k]*a[0]*dt, obj.vy + d[k]*a[1]*dt, ]; } } } let objs2 = objs.filter(obj => obj.anchor); if(objs2.length == 0) { objs2 = objs; } let av = [0, 0, 0, 0, 0]; for (let obj of objs2) { if (obj.mass > 0) { av[0] += obj.vx * obj.mass; av[1] += obj.vy * obj.mass; av[2] += obj.mass; av[3] += obj.x * obj.mass; av[4] += obj.y * obj.mass; } } av = [av[0] / av[2], av[1] / av[2], av[3] / av[2], av[4] / av[2]]; for (let obj of objs) { obj.vx -= av[0]; obj.vy -= av[1]; obj.x -= av[2]; obj.y -= av[3]; } config.camX -= av[2]; config.camY -= av[3]; if (objs2.length == 0 || !( +config.camX == config.camX && +config.camY == config.camY && +config.zoom == config.zoom )) { config.camX = 0; config.camY = 0; config.zoom = 1; } } Object.assign(body, { onkeydown(e) { if (e.code == 'Space') { config.pause = !config.pause; } }, oncontextmenu(e) { return false; }, onmousedown(e) { let [x, y] = screenToWorld(e.clientX, e.clientY); if (e.button == 1) { selObj = starElement({x, y, r:0, sel:1}); return false; } else if (e.button == 0) { for (let obj of Object.values(config.objects)) { if (Math.hypot(obj.x - x, obj.y - y) <= obj.r) { if (throwObj) { throwObj.element.remove(); } throwObj = starElement({x, y, r: 0, dx: 0, dy: 0, obj}); return false; } } newObj = starElement({ x, y, r: 0, mass: 0, id: randomID(), vx: 0, vy: 0, }); return false; } else if (e.button == 2) { for (let obj of Object.values(config.objects)) { if (Math.hypot(obj.x - x, obj.y - y) <= obj.r) { obj.element.remove(); delete config.objects[obj.id]; return false; } } } }, onmousemove(e) { let [x, y] = screenToWorld(e.clientX, e.clientY); if (selObj) { selObj.r = Math.hypot(x - selObj.x, y - selObj.y); } if (newObj && !throwObj) { newObj.r = Math.hypot(x - newObj.x, y - newObj.y); newObj.mass = 4/3 * Math.PI * (newObj.r**3); return false; } else if (throwObj) { Object.assign(throwObj, { dx: x - throwObj.x, dy: y - throwObj.y, r: Math.hypot(x - throwObj.x, y - throwObj.y), }); return false; } }, onmouseup(e) { if (newObj && e.button == 0) { if (newObj.r > 0) { config.objects[newObj.id] = newObj; } else { newObj.element.remove(); } newObj = null; return false; } else if (throwObj && e.button == 0) { [throwObj.obj.vx, throwObj.obj.vy] = [ throwObj.dx, throwObj.dy, ]; throwObj.element.remove(); throwObj = null; } else if (selObj && e.button == 1) { for (let obj of Object.values(config.objects)) { if (Math.hypot(obj.x - selObj.x, obj.y - selObj.y) < (obj.r + selObj.r)) { obj.anchor = true; } else { delete obj.anchor; } } selObj.element.remove(); selObj = null; } }, onwheel(e) { let [x, y] = screenToWorld(e.clientX, e.clientY); let [dx, dy] = [ x - config.camX, y - config.camY, ]; let oldzoom = config.zoom; config.zoom -= (e.deltaY / body.clientHeight) * config.zoom; let zch = config.zoom / oldzoom; config.camX = x - dx / zch; config.camY = y - dy / zch; }, }); var prevAniTs; requestAnimationFrame((fun => fun = (ts) => { draw((prevAniTs != null) ? Math.min((ts - prevAniTs) / 1000, 1) : 0); prevAniTs = ts; requestAnimationFrame(fun); })()); </script> |
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | from learner import Learner import torch import random # train the gamer W = 10 H = 10 class HalfBattleship: def __init__(self): self.W = W self.H = H self.board = [None for i in range(W*H)] self.hits = [None for i in range(W*H)] self.pieces = [] for l in [2,3,4,5,6]: while True: h = random.randint(0, 1) == 1 if h: x = random.randrange(0, self.W - l + 1) y = random.randrange(0, self.H) row = [(x+dx,y) for dx in range(0, l)] else: x = random.randrange(0, self.W) y = random.randrange(0, self.H - l + 1) row = [(x,y+dy) for dy in range(0, l)] if len([v for v in filter(lambda o: self.get(o[0], o[1])[0] is not None, row)]) == 0: for x, y in row: self.board[x + y*self.W] = True self.pieces.append((x,y,h)) break def get(self, x, y): return (self.board[x + y*self.W], self.hits[x + y*self.W]) def state(self): return [item for it in [ [ 1 if x is not None and x else 0, 1 if x is not None and not x else 0 ] for x in self.hits ] for item in it] def actions(self): return [(x,y) if self.get(x,y)[1] is None else None for y in range(self.H) for x in range(self.W)] def get_str(self, x, y): piece, hit = self.get(x, y) if hit is not None: return '#' if hit else '.' return 'o' if piece is not None else ' ' def print(self, other): if self.W != other.W or self.H != other.H: raise ValueError('dimensions unequal') print('/'+''.join(['-' for i in range(0,self.W+self.W-1)])+'\\ /'+ ''.join(['-' for i in range(0,other.W+other.W-1)])+'\\') for y in range(self.H): print("|" + (' '.join([self.get_str(x,y) for x in range(self.W)])) + "| |" + (' '.join([other.get_str(x,y) for x in range(other.W)]))+'|') print('\\'+''.join(['-' for i in range(0,self.W+self.W-1)])+'/ \\'+ ''.join(['-' for i in range(0,other.W+other.W-1)])+'/') def play(self, x, y): piece, hit = self.get(x, y) if hit is not None: return None hit = True if piece else False self.hits[x + y*self.W] = hit if len([v for v in filter(lambda v: v[0] is not None and v[1] is None, [self.get(x,y) for y in range(self.H) for x in range(self.W)])]) == 0: return (True, True) return (False, hit) if __name__ == '__main__': state = None try: state = torch.load("model-bship.pt", weights_only = True) except: pass players = [1,2] games = [HalfBattleship() for pl in players] states = [None for pl in players] acts = [None for pl in players] next_states = [None for pl in players] agent = Learner(len(games[0].actions()), len(games[0].state()), state = state, EPS_DECAY=10000) while True: for i, pl in enumerate(players): print() game = games[i] states[i] = game.state() next_states[i] = None state = states[i] act = None actions = game.actions() while act is None: act = agent.decide(state) if actions[act] is None: print('badact', act) agent.learn(state, act, state, -1) act = None acts[i] = act term, winner = game.play(actions[act][0], actions[act][1]) print("state:",(term,winner)) next_states[i] = game.state() print("learn", 1 if winner else -0.1) agent.learn(states[i], acts[i], next_states[i], 1 if winner else 0) other_reward = 0 if term and winner: print() print("@@@@") print("@@@@") print("@@@@ WINNER :"+str(pl)+" @@@@") print("@@@@") print("@@@@") print() coverage = len([v for v in filter(lambda v: v is not None, game.hits)]) / len(game.hits) print(str(round(coverage*100))+"% covered") games[0].print(games[1]) torch.save(agent.get_model_state(), "model-bship.pt") if term or coverage > 0.6: games = [HalfBattleship() for pl in players] states = [None for pl in players] acts = [None for pl in players] next_states = [None for pl in players] break |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | from learner import Learner from battleship import HalfBattleship import torch import random state = None try: state = torch.load("model-bship.pt", weights_only = True) except: pass game = HalfBattleship() agent = Learner(len(game.actions()), len(game.state()), state = state, layers = [100,100]) for x, y, h in game.pieces: print(('-' if h else '|')+("ABCDEFGHIJ")[y]+("0123456789")[x]) gaming = True while gaming: act = None actions = game.actions() act = agent.decide(game.state(), final=True) while actions[act] is None: act = random.randrange(0, len(actions)) print(("ABCDEFGHIJ")[actions[act][1]]+("0123456789")[actions[act][0]]) while True: try: line = input() except: gaming = False break if line == "WIN": gaming = False break if line == "MISS" or line == "HIT": game.hits[actions[act][0] + actions[act][1]*game.W] = line == "HIT" break |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | # i dont know the math i stole it from https://docs.pytorch.org/tutorials/intermediate/reinforcement_q_learning.html import math import random from collections import namedtuple, deque from itertools import count import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F device = torch.device( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) Transition = namedtuple('Transition', ('state', 'action', 'next_state', 'reward')) class ReplayMemory(object): def __init__(self, capacity): self.memory = deque([], maxlen=capacity) def push(self, *args): self.memory.append(Transition(*args)) def sample(self, batch_size): return random.sample(self.memory, batch_size) def __len__(self): return len(self.memory) class DQN(nn.Module): def __init__(self, n_observations, n_actions, layers): super(DQN, self).__init__() self.layers = []; self.layers.append(nn.Linear(n_observations, layers[0])) for i, lay in enumerate(layers[:-1]): self.layers.append(nn.Linear(lay, layers[i+1])) self.layers.append(nn.Linear(layers[len(layers) - 1], n_actions)) self.layers = nn.Sequential(*[item for it in [[l, nn.ReLU()] for l in self.layers] for item in it][:-1]) def forward(self, x): return self.layers(x) class Learner: def __init__(self, n_actions, n_observations, state = None, layers = [128, 128], BATCH_SIZE = 128, GAMMA = 0.99, EPS_START = 0.9, EPS_END = 0.05, EPS_DECAY = 1000, TAU = 0.005, LR = 1e-4 ): self.BATCH_SIZE = BATCH_SIZE self.GAMMA = GAMMA self.EPS_START = EPS_START self.EPS_END = EPS_END self.EPS_DECAY = EPS_DECAY self.TAU = TAU self.LR = LR self.n_observations = n_observations self.n_actions = n_actions if state is not None and 'layers' in state: layers = state['layers']; self.layers = layers self.policy_net = DQN(n_observations, n_actions, layers).to(device) self.steps_done = 0 if state is not None: self.policy_net.load_state_dict(state['model']) self.steps_done = state['steps_done'] self.target_net = DQN(n_observations, n_actions, layers).to(device) self.target_net.load_state_dict(self.policy_net.state_dict()) self.state = None self.optimizer = optim.AdamW(self.policy_net.parameters(), lr=self.LR, amsgrad=True) self.memory = ReplayMemory(10000) def get_model_state(self): return { 'model': self.policy_net.state_dict(), 'steps_done': self.steps_done, 'layers': self.layers } def select_action(self, state, final=False): sample = random.random() if final: eps_threshold = 0 else: eps_threshold = self.EPS_END + (self.EPS_START - self.EPS_END) * \ math.exp(-1. * self.steps_done / self.EPS_DECAY) self.steps_done += 1 if sample > eps_threshold: with torch.no_grad(): return self.policy_net(state).max(1).indices.view(1, 1) else: return torch.tensor([[random.randrange(0, self.n_actions)]], device=device, dtype=torch.long) def optimize_model(self): memory = self.memory optimizer = self.optimizer policy_net = self.policy_net if len(memory) < self.BATCH_SIZE: return transitions = memory.sample(self.BATCH_SIZE) batch = Transition(*zip(*transitions)) non_final_mask = torch.tensor(tuple(map(lambda s: s is not None, batch.next_state)), device=device, dtype=torch.bool) non_final_next_states = torch.cat([s for s in batch.next_state if s is not None]) state_batch = torch.cat(batch.state) action_batch = torch.cat(batch.action) reward_batch = torch.cat(batch.reward) state_action_values = policy_net(state_batch).gather(1, action_batch) next_state_values = torch.zeros(self.BATCH_SIZE, device=device) with torch.no_grad(): next_state_values[non_final_mask] = self.target_net(non_final_next_states).max(1).values expected_state_action_values = (next_state_values * self.GAMMA) + reward_batch criterion = nn.SmoothL1Loss() loss = criterion(state_action_values, expected_state_action_values.unsqueeze(1)) optimizer.zero_grad() loss.backward() torch.nn.utils.clip_grad_value_(policy_net.parameters(), 100) optimizer.step() def decide(self, state, final=False): state = torch.tensor(state, dtype=torch.float32, device=device).unsqueeze(0) action = self.select_action(state, final=False) return action def learn(self, state, action, observation, reward): state = torch.tensor(state, dtype=torch.float32, device=device).unsqueeze(0) if not observation: next_state = None else: next_state = torch.tensor(observation, dtype=torch.float32, device=device).unsqueeze(0) reward = torch.tensor([reward], device=device) self.memory.push(state, action, next_state, reward) self.optimize_model() target_net_state_dict = self.target_net.state_dict() policy_net_state_dict = self.policy_net.state_dict() for key in policy_net_state_dict: target_net_state_dict[key] = policy_net_state_dict[key]*self.TAU + target_net_state_dict[key]*(1-self.TAU) self.target_net.load_state_dict(target_net_state_dict) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | from learner import Learner import torch # its for initial test def checkrow(row): if len(row) == 0: return None if row[0] is None: return None for x in row: if x != row[0]: return None return row[0] class TicTacToe: def __init__(self, W, H, L): self.W = W self.H = H self.L = L self.board = [None for i in range(W*H)] def get(self, x, y): return self.board[x + y*self.W] def state(self, pl): return [item for it in [ [ 1 if x == pl else 0, 1 if x is not None and x != pl else 0 ] for x in self.board ] for item in it] def actions(self): return [(x,y) if self.get(x,y) is None else None for y in range(self.H) for x in range(self.W)] def print(self): print("===") for y in range(self.H): print(" " + (' '.join([str(self.get(x,y)) if self.get(x,y) is not None else '.' for x in range(self.W)]))) print("===") def play(self, x, y, pl): v = self.get(x, y) if v is not None: return None self.board[x + y*self.W] = pl # rows for x, y in [(x,y) for y in range(self.H) for x in range(self.W - self.L + 1)]: row = [self.get(x+d, y) for d in range(self.L)] row = checkrow(row) if row is not None: return (True, row) # cols for x, y in [(x,y) for y in range(self.H - self.L + 1) for x in range(self.W)]: col = [self.get(x, y+d) for d in range(self.L)] col = checkrow(col) if col is not None: return (True, col) # diags for x, y in [(x,y) for y in range(self.H - self.L + 1) for x in range(self.W - self.L + 1)]: dia1 = [self.get(x+dx, y+dy) for dy in range(self.L) for dx in range(self.L)] dia2 = [self.get(x+self.L-1-dx, y+dy) for dy in range(self.L) for dx in range(self.L)] dia1 = checkrow(dia1) dia2 = checkrow(dia2) if dia1 is not None: return (True, dia1) if dia2 is not None: return (True, dia2) if len([i for i in filter(lambda x: x is not None, self.actions())]) == 0: return (True, None) return (False, None) W = 3 H = 3 L = 3 game = TicTacToe(W,H,L) state = None try: state = torch.load("model-ttt.pt", weights_only = True) except: pass agent = Learner(len(game.actions()), len(game.state(1)), state = state) players = [1,2] states = [None for pl in players] acts = [None for pl in players] next_states = [None for pl in players] while True: for i, pl in enumerate(players): print() states[i] = game.state(pl) next_states[i] = None state = states[i] act = None actions = game.actions() while act is None: act = agent.decide(state) if actions[act] is None: print('badact', act) agent.learn(state, act, None, -0.5) act = None acts[i] = act term, winner = game.play(actions[act][0], actions[act][1], pl) print("state:",(term,winner)) next_states[i] = game.state(pl) other_reward = 0 if term and winner == pl: print() print("@@@@") print("@@@@") print("@@@@ WINNER :"+str(pl)+" @@@@") print("@@@@") print("@@@@") print() other_reward = -1 print('learn', 1) agent.learn(states[i], acts[i], next_states[i], 1) elif term: print('learn', 0) agent.learn(states[i], acts[i], next_states[i], 0) for j, pln in filter(lambda p: p[1] != pl, enumerate(players)): if acts[j] is not None: print('learn', other_reward) agent.learn(states[j], acts[j], next_states[j], other_reward) game.print() if term: states = [None for pl in players] acts = [None for pl in players] next_states = [None for pl in players] game = TicTacToe(W,H,L) torch.save(agent.get_model_state(), "model-ttt.pt") break |
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | <?php ob_start(function($buffer) { fwrite(STDERR, $buffer); }, 1); if (!( file_exists(__DIR__.'/vendor/amphp/amp') && file_exists(__DIR__.'/vendor/amphp/byte-stream') && file_exists(__DIR__.'/vendor/amphp/websocket-client'))) { $composer_path = 'composer'; system($composer_path." -qV", $result_code); if ($result_code) { $composer_path = __DIR__.'/composer'; copy("https://getcomposer.org/download/latest-stable/composer.phar", $composer_path); chmod($composer_path, 0755); } system('cd '.__DIR__.'; '.$composer_path.' require '.implode(' ', [ 'amphp/websocket-client', 'amphp/byte-stream', 'amphp/amp' ])); } require __DIR__.'/vendor/autoload.php'; use function \Amp\async; use function \Amp\delay; use function \Amp\Websocket\Client\connect; use function \Amp\ByteStream\getStdin; use \Amp\ByteStream\BufferedReader; echo 'connecting -'; $conn = false; $spin = 0; async(function() { global $conn, $spin; while (!$conn) { $spin += 1; $spin %= 4; echo "\x08".['-','\\',"|",'/'][$spin]; delay(0.1); } }); $conn = connect('wss://codeguessing.gay/73/ws'); echo "\r \r"; ob_end_flush(); async(function() { global $conn; foreach($conn as $msg) { $msg = $msg->buffer(); $msg = json_decode($msg); switch($msg->reason) { case "connect": echo"*** ".$msg->name." joined the game. ***\n"; break; case "disconnect": echo "*** ".$msg->name." left the game. ***\n"; break; case "message": if (is_string($msg->content)) { echo "<".$msg->name."> ".$msg->content."\n"; break; } default: echo json_encode($msg)."\n"; } } }); $io = new BufferedReader(getStdin()); while(1) { try { $x = $io->readUntil("\n"); } catch (Exception $e) { break; } $conn->sendText(json_encode(["content" => $x])); } |
submitted at
3 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | (q=>(([x,y,z])=>y(`(require)=>{||${x}||}`)(z))(([(q=[ "𝟠𝜬𝜬𝜬𝄲𝟂𝕪𝕌𝟠𝃘𝂺𝁂𝁂𜾎𜼖𜼴𝄲𜾬𝁾𝂺𜼴𜼖𝕪𝕌𝂺𝄲𝟠𝃘𝂺𝁂𝁂𜾎𜼖𜼴𝄲𜾬𝁾𝂺𜼴𜼖𝟂𝟂𝟠𝢔𝂺𝄲𝟠𝇦𝜬𝜬𝜬𝃘𝂺𝁂𝁂𜾎𜼖𜼴𝄲𜾬𝁾𝂺𜼴𜼖𝆪𝜬𜼴𝂺𝂺𜼴𜼖𝂺𝟠𝟂𝜬𝀤𜾎𝁂𜾬𝟠𝟾𝟾𝟂𝟂𝜎𝜎𝟂𝟂𝟂𝟂𝟂𝚴𝂺𝚖𝜬𝜎𝟂𝟂𝟠𝓲𜾬𝁂𜾎𝌰𝂺𝃘𜾎𝜬𝝊𝙚𝂺𝚖𝜬𝛒𝟠𝟠𜼴𜾎𜾎𝂜𝜬𝁠𝄲𝕌𝕪𝟠𜽰𝄲𝜬𝆪𝜬𝜬𝜬𝇦𝜬𝜬𝜬𝟠𜾬𝁂𜾎𝌰𝂺𝃘𜾎𝒶𜾎𜼴𝂜𝜬𝁾𜾬𝁂𜼴𝕌𝕪𝟂𝝨𝅮𝟠𝝨𝁾𝜎𝇈𝇈𝇈𝇈𝟂𝞤𝜬𝟠𝇈𝇈𝇈𝇈𝜎𝟠𝓲𝂺𝄲𜽰𝂺𜼴𝜬𝟠𝄲𝂺𝕌𝕪𝢔𝟂𝟠𝜬𝜬𝜬𝄲𝟂", "🜠🁲🀶🜠𞺒🜂💩💋🜟🁒🁰🇶", "🜂𞹴💪🜟🜟🄥🀗🚧🁓🃩🚧🚦🚦𞸶🚦🜀💨💉🜝🪡💧🜝🚥🚤", "🚨🁲🚨🁔🜂💪💌🜠🪤🁱💩🂭💩💋📇😯👭🄤🙪🙪🙪🐰𞹲𞹲🁰🜝🚇🃧🙩🁯𞺬🜜🂪💦💈🀔🙨𞸖🜛📿🄡🙧🙧🙧🐭𞹮𞹮🁬🜚🛼🃤🙥🁫𞺩🜙🂧💣💅🀑🙤🀐🜘🛺🛺🚠🪜🁌💡🂥💡💃💿😧👥🄝🙢🙢🙢🐨𞹪𞹪🁨🜕🙿🛷🃟🙡🁧𞺥🜔🂢💞💀🀌🙠🜔🛵🛵📷🄙🙟🙟🙟🐥𞹧🁤🜒🛴🃜🙞🁣𞺡🜑💛👽🀉🙝𞹤🜐🛲🛲🚘🪔", "👮🜠🁲🜠🜂🚨🁔🜠🜂🜁🔃🜟🁓🜟🜁🚧🁱🜟🜀🜀🜀🚦🪢💨🜞🚥𞺭🚥🚥", "🚨🜂💪💌🜠💪🀘🙫🜟🜁🚧👭🜟💨🙪𞹔𞺮𞸶🜝🜻🄅🜻🙩🁯𞺬🜜💦💈🙨𞹒𞺫🜛🜹🜹🚢💤🄠🙦𞸱", "🚨🄦😰🃪🙬𞸷", "🃪🚨🪤🙬𞹴🎺🁱🀵", "🜠🜠𞹴🚨🜂💪💌𞹴🙫🎹🁱🀵", "🜠🜠🀶🚨🜂💪💌🀶💩💩🜽👏🜽👭𞺯💩🄥🚦🃨🔂🀴💨💨🜻🛃🜻👫💧🄣🚥🃦🔀🀲💦💦🜺🛠🜹👩", "💪🄦🚨🃪🔄🄦🃪🄥😯🃩🜁🜁🚧🄥🚧𞺮🚦🚦", "🃪🜂🔄𞸚🜂🚨🪣𞸷💩🜟🁱🚧🁓🚧🀵🜀💨💊🜞🀴🄤😮🃨📅💧🁯𞸵", "🙬🁲🜠🁲🄦😰🃪🚧🁓🄥😯🃩🜁🝛🝛🀵🄤😮🃨💊💨🁰𞸶", "🙬🜠🁲🄦😰🃪🚧🁓🄥😯🃩🜁🪣🝛🝛🀴🄤😐🃨📆💨🁰𞸵", "🙬🁲🜠🁲🄦😒🃪🚧🁓🄥😑🃩🜁🝛🝛🀵🄤😐🃨💊💨🁰𞸶", "🙬🜠🁲🄦😒🃪🚧🁓🄥😑🃩🜁🜁🚧🪣💨🜞🁰🚦🁒🚦🀖🚥", "🜂💪💌🜠🀘👮🜠🜠🄥🁱🄥😯🃩🚧🁱🄥😑🃨🃨🚦🄤🁒🄤😮🃨🚥🁯🄣😏🃧🃧🚥", "🜂🜠🄦🁔🄦😰🃩🚧🁱🄥😑🃩🃩🚧🄥🁒🄤😮🃨🚦🁒🄤😐🃧🃧🚥", "🜂🜂🪤🔄🜠🜠🄦🁲🄥😯🃩🚧🁱🄥😑🃩🃩🚦🄤🁰🄤😮🃨🚦🁒🄣😏🃧🃧🚥", "🜂🜠🄦🁲🄦😰🃩🚧🁓🄥😑🃩🃩🚧🄥🁒🄤😮🃨🚦🁒🄤😐🃧🃧🚥", "🜂🜂🜂🚨🪤🁲🀵🜟🜁💩💋🜞📤📤🜀𞸶𞹲🁯🁯𞸵🀕🙩🜜📢𞹰🜜📢📡🠋💥🜚🛼📠🜚🛻🁍𞹭🁫📟🪝𞸰🠈🄞𞹎🚠𞺨🚟🚟", "🃪💪📦🜠🀘🙬𞺯𞺯🝛🝛", "🜂🠐💪𞺰🚧💩😯🚧💩🈔𞸶🜞🜀📤", "🜠😒🜂🪤𞸷💩𞺯🄥😯🃩🗲🛢🗲🚈😐🚦🂬📣🄣🂫🚥𞺭🃧💧🜝𞺭🄢😎🃦🛂📄𞹒🄢😍🃥🝗🝗𞺫🄡😍🃥🛁💆💤😪🛼👨🄠🜙😩🚡🛻🚡🄟𞺩🄟😨🃢🚠𞺨🄞😊🃢🚾🃡🃡🪛📻🜗🜗💡🝰🗪🗪🚀😈🚞𞺥🄛😥🃟🚻💽𞹋🄛😤🃞🝐🝐🄚😤🃞🚹👿💝😣🛵𞴻𞴻🜓💜🙼🚚🚸🚸🛳🚙🄗🜑🚙😡🛳🚘🄖🄖😠🃚🚶🚘🄕😁🃙🃙🃙🛱📕🪒💘💘👹🜍🄓🙙🙙🙙🁁🃗🙘🁞🜌💖👸🙗", "🁲🜠🜂👮🔄🙫🁱🀗🀗🜟🙫🁰🜞🂬💨💉🜝🁑🙩🀕𞸵🜜🚤🙨🀔🜛🛼🙦🀰🁬𞸲🀰", "🜠🂮💪💌𞴪🜂🜂🜂🚧🀗🙫💩🁓🙫𞹔🜀🪢🜞📣🜝🁑🙩💈😎😬😬", "🜠🁔🙬💋🔡😯🜁🜟🜁🚧🪢🁰🁰𞸶𞺐🜝😏😭😭📣💧🜜📢🄢𞹒🚤🂪🚤🚣", "🃪💪📦🜠🝜🝛🄥🗕🃩🜁🀗🙫𞺮𞺮💨😮📤🁒𞹲🁯𞴧🪡𞴧𞴧🜜", "🜂🜠🄦😰🃪🚊𞺯🄥😯🃩🚧🄥😑🃩🚈𞺮🄤😐🃨🜀𞴨🪡𞸵🄢𞸖🚤🚤🃦💦🄡🄡𞺫🄡😫🃥🚣𞺫🄡😌🃤🃤🚢🁬𞸲", "🙬𞹴🁲🀘🜠🜂💋😯🙫🖙🚧🁱𞸷", "🙬𞹴🁲🀘🜠🜂💋😯🙫🖙🃩📥🪣𞸶💨😮📤", "🜠😒🜂🪤🜟🜟🜟𞺯🚧𞸙🚦🚦", "🜂🜠𞸚🚨🚨🚧", "🜂🜂🜂🠐🁔𞹴🁲📥🪣𞸙💩🄥🁱𞸷", "🙬𞹴🜠🁲𞸷", "🙬𞹴🁲🀘🜠🜂🛣🄥😯🃩🜁🚧🁱𞸶", "🙬𞹴🜠🁲𞸷", "🙬𞹴🁲🀘🜠🜂🛣🄥😑🃩🜁🃩📥🪣💨🁰𞸶", "🙬𞹴🁲🀘🜠🜂💋😯🙫🖙📥💩🁱𞸶", "🙬𞹴🁲🀘🜠🜂💋😯🙫🖙📥🪣🛅🛅📤🜞💊😐😮😭😭💧😭📣🀳𞹒🙨𞹯𞹯𞹯🜛🟏🟏📠🁬🁬𞸲🠊𞺌🜙😋😩😩🛻𞴣🪝𞴣🜘𞸒🄞😨🃢🚂𞺨🄞😧🃡🚟𞸑🄝😉🃡🚁𞺧🄜😈🃠🚞🛸📜🪚🜕🄛😥🃟🙿𞸏🄛😤🃞🚜🄚😆🃞🙾𞸍🄙😅🃝🚛🛵📙🪗𞴜🁤🁤𞸪🠂🜒💛👽🉡𞹇🙜🁢🜐🁄🛲🙜🁡🜏💘👺🙚𞹢🎨🁟🀣", "🜠💪💌🁔🙬🀘𞸷🜟🜁🜁🜁🜁🜞🄤🙪🙪🙪🁒🃨🜀📣🪡𞴧🁑𞹱🁯𞴧🀲🁮𞸴🀲", "🜠🜂🀶🙫🜟🜀📤🁰🁰𞸶𞺏🜝😏😭😭😭📣𞴦𞴦🪠🜜🜜🁏🁭🇳", "🙬🀘🜁👭🁱🁱𞸷🜟🁱𞹔🀴🜞🏴𞸵𞴧🚥🙋🛡🏲🀔🁭🁭🠋🚅🚅🚅🚅💇🛞🙈𞹮🚡🚡𞹎𞺨🁪𞴢🚠🪜𞹎🚟🚟🀏🚟🁋🛹💡💃🜖🟨🜖𞹪🝑🝑🀫🛶🛶🎐𞸎🀩𞸫🜓🜱🜱🚚🜰𞸪", "𞹴🠐🠐🎺🜟🜁🜽🜁🜞🜼🀴🙩💧🟐𞹰🟏📿🠋𞹯🀱🙦🀰🚢🠊🟎𞹏𞺩🁫🟍📽👧👧👧🚠🠈🟌🟋📻🠇🟋𞹍𞹍𞹍💠🜴🛸📜🪚𞹋💟🠅🏫𞸬🜔𞹨🚛𞺣𞺣📶😄😢😡🚙", "🁲🀘𞹴🇸𞸙𞸷🔃😑😯🗕🚦🁒🀖🇶𞸗𞸵🔁😏😭🗓𞴦📢🁐💦🠋🈑🜛📡🪟𞹑💤🜚💤💆🁬🜙🁍🀑🚡🛺💢💄🜘𞺨𞹬𞹍𞹍🙣𞹍𞸯🀏𞸑𞸮🙢🂤𞸮𞺦🟨💟🜳𞸭𞸭🜳🝑🝑𞺥𞹨🀪🙠𞸫🀋𞸍𞸫🙟𞹧𞸪🜒🌖🙞𞹇𞸩🜐🀈𞹤📴🟄𞸊𞸧🟃🚗🁃🀇𞴙🛰🚴🜬🜬🛰🚖🪒💗🜍💗🁟🁟𞸤𞹂🙘𞹾𞸆🜋🜋💕👷🜊🛬🛬🜊𞺚🁜𞸡", "🔄🟔🙎𞹴🁲🙎🁱🕝😯🟓🚧🁓🀴🔂🁯🚥🀕𞺬𞸴𞸴🔀𞹯𞸕🚣🪟", "🁲🀘𞹴🔄🀶🔃🀵🚦🙪🙪🙪🁒🀕👫🜻🀳𞸴𞸴🚆𞸴𞺬🜹📿🜹🁭𞺫𞺫🀰🁬𞸲🙈𞹏🜷𞴣🪝📽𞴣𞴢🚠🁌🀐📼🁌🀏👥🌛🙣𞸮𞹪🜕🁉🀍🛷📹𞸎🚜🪘𞸬", "🀘🔄🁔🀘👮🟔🈕🇷🟓🔃🟓🍽🎹🇶🟒𞴨🜀🜀🜀🚦💧🁯🁯𞸵🜝🁯🀲🜜💦💈🜜💥🁭🁭🠋🙦🁎🀒🙦𞸲𞸱🜙🛻🚡🌝🙤𞺨🁪𞹬𞹎🜘🛹🛹🛹🜗🛹🪛🙣🁨𞸮", "🜠🁲🀶🜠🜂💩💋🀵🙪𞹲𞹲𞹲🜞📣𞸵", "𞹴🠐𞴪🜂🚨🜠𞺯🀵🙫𞸶🀖𞸘𞸶🙪🂬𞸶𞺭💧🜻𞸵𞸵🜺🝘🝘🪠𞺬𞹰🀲𞹑𞹑🙧𞹑🀓𞸕𞸲🙦𞹮𞸲🜚🌝🙥𞹏𞸱𞹭🜘🀐📻🟋🟋🚟🁋🀎📺𞴠🛸🚼🜳🜳🛷🚝🜕🟧🛶𞴼𞴼🜔🙠👢👡😅🙁😣🛵💻🜓🙟👠👠😄🙀😢🛴🛴🪕🝍🝍🜑💛🚙🀉🙜🀦🙜🀦🁢🜏🛱🚗🀇🙛🀥🙚🜎🜎🙚🀣𞺻𞹡💗𞸆🝈🝈🙘𞹟🀃👙🁻🃳🃲𞸢🀠𞺸📮🞁🙕🀟𞺷𞹝𞴒🃰🃰🞀🙓𞹛🙓𞺗𞸞🜆🜤🃮🜤🛨🙑🁗𞺕🜅💏👱🜢🃬𞸜🜢🚪🛦🙐𞺱🜃🜡🃫🜡🜂𞴪🂐🔄🚨🀘🙬🟓🟓🜁🜁🜁🜀🜞𞹔🜀📤🀖💨𞴧📣🪡🀕🙩💧🂫💧💈🙨𞹰🀔📢🀓🙧𞺫𞺫💥🜛𞹑🁬👨👨😪🛼📠🀑🙥💣🠈𞹎🙣🏭𞹍🜗𞺦𞹪🙢𞹋𞸭🀍𞹩𞹩🛷📛🀍🙠🀪🙠🜓🟇🀩🀩𞸫🟆🛴📘🪖🄘🀉🙝🚙🀉🙝🚙🀉🙜𞸊🚘🀈🙜🀈🃚💚🄖🜭𞸧🜭🚗🜭𞹢", "🜾🚨🜾𞸚𞺰🜾🚨🜾🀗🜽🃩🪣🙫🁰𞺮🜞🜞🀖🚦𞺮🜀💧💉🂫💧💉🁑🙩🁯🀔🀔🜜𞺬💦𞹒🜜🀓𞹯📿🀓𞴥🙧", "🜠🂮💪💌🁔🙬🀘𞸷🜟𞺯🜁🜁🜀𞴨🜀📤🀖🙪💨💧💉🜝📣🪡", "🜠😒🜂𞹴🁱🁱𞸷🜟🜀📤🁒𞹲🁰𞴨🀳🁯𞸵🀳", "🜠🜂🀶🙫🜟🜀📤🁰🁰𞸶𞺏🜝😏😭😭😭𞴧𞹰𞸴𞸖𞹰🄢🀓🚣🁏🃥𞴥🜛𞹯𞺌𞸔𞹮🜚🜸𞸔🀑🜷🛻🚡🪝🌜🙤𞺨🁪𞹬𞹍🜗𞺉𞸑🜖🜴🜴🛸🙢𞹩🁧🀍🎑🀪🜔🟈🀪🙟𞹉🟇🛴🛴🛴📶🙀🙀💺🙼🙻🙻🙻🠁🏧🠀🪔🜐🜐🚗🀇🚗🚗🁃🚗🛰💘👺🀆💘📱🜍💗👹💗👹🙘🜋🁻🞡🀠🁺🛬🚒📭🁹🞟🁸🚐📬🁸🞞", "🂐🚨𞸚🔄🂐🞶𞸚𞺯🂏🚧🀗🔃🂏🞵🀗🂎𞴨📤🪢💧🄣🃧📣🀕🙩🁑💧𞴦📢🄢🀔🙨🁐🙨🚣🀓🙧🁏🙧𞹯🚣🀓🙧🁎🙦𞸔🚢🀒🙦🁎🙦🀑🃣💣🄟🙥🙥🙥🐫𞹭𞹬🁪🜘🖰🛺🃢🪜🙣🁩𞺧🜗💡💃🠆𞸮🜖🛸🛷📛🀍🙡🁉🙡💟𞸎📚🁈💞🠃𞸫🜓🛵📙🀋🙞💜💜👾𞸩🀧", "🐲🀘🈴🀘𞹴🜟🜁📥🪣🄥🀗🙫🚧🀖🙪𞹲🚦🀖🙪𞸘🚦🀕🙩🀕🃧💧🄣🄣🀕🙩🚤🀔🙨🁐🙨𞹰🚤🀓🙧🁏🙧🃥🚣🄡🀓🙦𞹮🚢🀒🙦🁎🙦🚡🀑🙥🁍🙥𞹭🃣🚡🪝🄞🀐🙤𞸒🚠🀐🙤🁌🙣🀏🚟🀏🙣🁋🙣𞸑🃡🚞🄜🀎🙢🀎🚞🀎🙢🁉🙡𞸏🚝🀍🙡🁉🙡🀍🃞🃞🙠🁦🜔🜔🄙🚛𞹉🚛", "🃪🜂💪💌🜠🁲🀵🜟𞺯🜁💩💋🜞🀖🙪🁒🙪🜀🁰🁯𞸵🀕🙩🁑🙩📢🪠🜜𞹒🙨𞹑💇😫𞺫💥𞹮🙦🁫🜙𞹏🛻🚡🁍🙥🁪🀐🀐🜘🀐🙤🁌🙤💡𞺧🪛💡𞺧🙣𞸯", "🜠💪💌🜠🁔🙬🀗𞸷🜟𞺯🜁🚦🀖🙪🁒🙪💨𞸗🚥🚥🁮🁮𞸴𞺬📢🪟🙧𞺫𞸕𞹑", "🜠𞺰💪💌", "🙬🁲🀘🀘🜠𞺰💪𞺰🙬𞸷", "🜠💪💌🜠", "🙬🀘🜠𞺰🜁🚧🜁🜁🜁🜁📥🙪🀴🀴🜞🜀𞴧📣🪡𞸵🀳", "🐲🀘🈴🀘𞹴💩🜟💩💋𞸙🀵𞸶🜞🙪🙪🙪🁯𞹱𞸵𞺬💦🜜🙨🙨🙨🁭𞹯𞹑📡🪟🜚🙦𞸲", "💌😰🜂🙬𞺰𞺰🜠🜁🜟𞺯🜁📥🁓🙫🁱🀗🀖🜞𞺮💨𞺮🙪𞸶", "🜠💪💌🜠🁔🙬🀗𞸷🜟𞺯🜁🚦🜀🜀🜀📤𞹲𞸵𞸗𞹱𞺭𞴧🜝𞸴🀲", "🐲🀘🈴🀘𞹴🜁📥🪣𞸷𞸙🄤🀖🚦🁒🃨𞴨🜀🜝💧💉🀕🀳𞸗𞸴🙨𞺎𞸖𞹰🈑🀱𞹯🜚🛼🛼🛼📠🪞𞸱𞹭🜙🛻𞴣🛻🜙🜘🚠𞺨🛺💢💄🜘🠇🜖💠💂𞸭🇭𞸏𞸭🜕🚜🛶🛶🛶🛶🪘" ]).filter((_,i)=>i).join(''),eval(String.fromCodePoint(...[...q[0]].map(x=>(1.22e5-x.codePointAt())/.3e2))),(()=>{try{return require}catch{}})()])))() |
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ; step 1 (import (rename (rnrs(6)) (lambda h)(define s) (begin z)(set! q))) ; step 2 (s entry(let*((g call-with-string-output-port)(j abs)(c expt)(p(h(b)(s i 0)(h()(q i(+ 1 i))(/ b(c 2(- i 1))))))(k log)(d(h(x)(c 2(exact(ceiling(/ (k(let((x(j x)))(if(= x 0)1 x)))(k 2)))))))(m display)(w write))(h(x)( let((b(p(d x)))(y 0))(g(h(o)(m"x = "o)(do((n(b)(b))(i 0(+ 1 i)))((or(= y x)(> i 1000)(<(j(let((f(j x)))(-(/ y f)(/ x f))))#e1e-9)))(let*((a(+ y n ))(b(- y n))(u(j(- x a)))(v(j(- x b))))(if(< u v)(z(q y a)(m(if(= i 0)"" " + ")o)(w n o))(z(q y b)(m(if(= i 0)"-"" - ")o)(w n o)))))(if(= y 0)(m 0 o)0))))))) ; step 3 (s(main args)(apply(h(_ x)(display(entry(string->number x))) (display "\n"))args))(main (command-line)) |
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | none: # do nothing CODEGUESS = \ codeguess-unpacked/1 \ codeguess-unpacked/2 \ codeguess-unpacked/3 \ codeguess-unpacked/4 \ codeguess-unpacked/5 \ codeguess-unpacked/6 \ codeguess-unpacked/7 \ codeguess-unpacked/8 \ codeguess-unpacked/9 \ codeguess-unpacked/10 \ codeguess-unpacked/11 \ codeguess-unpacked/12 \ codeguess-unpacked/13 \ codeguess-unpacked/14 \ codeguess-unpacked/15 \ codeguess-unpacked/16 \ codeguess-unpacked/17 \ codeguess-unpacked/18 \ codeguess-unpacked/19 \ codeguess-unpacked/20 \ codeguess-unpacked/21 \ codeguess-unpacked/22 \ codeguess-unpacked/23 \ codeguess-unpacked/24 \ codeguess-unpacked/25 \ codeguess-unpacked/26 \ codeguess-unpacked/27 \ codeguess-unpacked/28 \ codeguess-unpacked/29 \ codeguess-unpacked/30 \ codeguess-unpacked/31 \ codeguess-unpacked/32 \ codeguess-unpacked/33 \ codeguess-unpacked/34 \ codeguess-unpacked/35 \ codeguess-unpacked/36 \ codeguess-unpacked/37 \ codeguess-unpacked/38 \ codeguess-unpacked/39 \ codeguess-unpacked/40 \ codeguess-unpacked/41 \ codeguess-unpacked/42 \ codeguess-unpacked/43 \ codeguess-unpacked/44 \ codeguess-unpacked/45 \ codeguess-unpacked/46 \ codeguess-unpacked/47 \ codeguess-unpacked/48 \ codeguess-unpacked/49 \ codeguess-unpacked/50 \ codeguess-unpacked/51 \ codeguess-unpacked/52 \ codeguess-unpacked/53 \ codeguess-unpacked/54 \ codeguess-unpacked/55 \ codeguess-unpacked/56 \ codeguess-unpacked/57 \ codeguess-unpacked/58 \ codeguess-unpacked/59 \ codeguess-unpacked/60 \ codeguess-unpacked/61 \ codeguess-unpacked/62 \ codeguess-unpacked/63 \ codeguess-unpacked/64 \ codeguess-unpacked/65 \ codeguess-unpacked/66 \ codeguess-unpacked/67 \ codeguess/%.tar.bz2: @mkdir -p codeguess @echo fetching $@ @while ! curl --retry-all-errors --retry 1000000 -sS https://codeguessing.gay/$*.tar.bz2 > codeguess/$*.tar.bz2; do :; done @echo fetched $@ codeguess-unpacked/%: codeguess/%.tar.bz2 @mkdir -p codeguess-unpacked cd codeguess-unpacked && tar xf ../codeguess/$*.tar.bz2 codeguess-all: $(CODEGUESS) models.h: analyzer.scm $(CODEGUESS) ratio(){ echo | awk "{ a=$$(cat "$$@"|wc -c); b=$$(cat "$$@"|gzip|wc -c); print a/b }"; }; \ find $(CODEGUESS) -name '.git' -prune -o -type f -print | while read line; do \ if [ "$$(du -b "$$line" | grep -oE ^[0-9]\*)" -le 16384 ] && \ [ $$(echo|awk "{ n=$$(ratio "$$line")>3?1:0; print n; }") = 1 ]; then \ printf '%s\n' "$$line"; fi; done | \ ( echo 'static const struct model models[] = {'; \ while read line; do printf '%s\n' "$$(wc -c "$$line")" >&2; \ guile analyzer.scm < "$$line"; done; echo '};' ) > models.h decipher: decipher.c models.h $(CC) -O3 decipher.c -o decipher |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | (import (rnrs (6))) ((lambda (fd-in fd-out) (define freq (make-vector 256 0)) (letrec ((loop (lambda () (define char (get-u8 fd-in)) (if (not (eof-object? char)) (begin (vector-set! freq char (+ 1 (vector-ref freq char))) (loop)))))) (loop)) (letrec ((loop (lambda (i) (if (< i (vector-length freq)) (begin (vector-set! freq i (cons i (vector-ref freq i))) (loop (+ i 1))))))) (loop 0)) (vector-sort! (lambda (sa ba) (> (cdr sa) (cdr ba))) freq) (define total (letrec ((loop (lambda (i c) (if (< i (vector-length freq)) (loop (+ i 1) (+ c (cdr (vector-ref freq i)))) c)))) (loop 0 0))) (if (> total 0) (letrec ((loop (lambda (i) (if (< i (vector-length freq)) ((lambda () (define elem (vector-ref freq i)) (vector-set! freq i (cons (car elem) (exact->inexact (/ (cdr elem) total)))) (loop (+ i 1)))))))) (loop 0))) (put-string fd-out "\t(struct model) {\n\t\t.items = {\n") (letrec ((loop (lambda (i) (if (< i (vector-length freq)) ((lambda () (define char (car (vector-ref freq i))) (define ratio (cdr (vector-ref freq i))) (put-string fd-out (string-append "\t\t\t(struct char_freq) { .who = " (if (and (<= 32 char) (> 127 char)) (let ((char (integer->char char))) (string-append "'" (if (or (eq? #\' char) (eq? #\\ char)) "\\" "") (make-string 1 char) "'")) (number->string char)) ", .when = " (number->string ratio) " },\n")) (loop (+ i 1)))))))) (loop 0)) (put-string fd-out "\t\t}\n\t},\n")) (standard-input-port) (current-output-port)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #include <stdlib.h> #include <stddef.h> #include <stdio.h> struct char_freq { char who; double when; }; struct model { struct char_freq items[256]; }; #include "models.h" #define lenof(obj) (sizeof(obj) / sizeof(*(obj))) void halt_and_catch() { fprintf(stderr, "critical error occurred. please leave the building immediately\n"); exit(1); } char *readfile(FILE *file, size_t *size) { int cap = 16; char *buf = malloc(cap); if (!buf) return NULL; int count = 0, c; while ((c=fgetc(file))!=EOF) { count++; if (count > cap) { char *buf_ = buf; if (!(buf = realloc(buf, (cap *= 2)))) { free(buf_); return NULL; } } buf[count-1] = c; } char *buf_ = buf; if (!(buf = realloc(buf, count))) { free(buf_); return NULL; } *size = count; return buf; } int sort_model_cb(const void *a_, const void *b_) { const struct char_freq *a = a_; const struct char_freq *b = b_; double diff = b->when - a->when; return diff < 0 ? -1 : (diff > 0 ? 1 : 0); } void sort_model(struct model *model) { qsort(model->items, 256, sizeof(*model->items), sort_model_cb); } double cmp_model(struct model *a, struct model *b) { double accum = 0; for (int i = 0; i < 256; i++) { double diff = (a->items[i].when - b->items[i].when); accum += diff * diff; } return accum; } void merge_model(const struct model *a, double a_weight, const struct model *b, struct model *out) { if (a_weight == 0) { *out = *b; return; } struct model b_raw; for (int i = 0; i < 256; i++) { b_raw.items[(unsigned char)b->items[i].who] = b->items[i]; } for (int i = 0; i < 256; i++) { out->items[i] = (struct char_freq) { .who = a->items[i].who, .when = (a->items[i].when + b_raw.items[(unsigned char)a->items[i].who].when) / (a_weight+1) }; } sort_model(out); } int analyze_buffer(const char *str, size_t size) { size_t freqs[256] = {0}; for (int i = 0; i < size; i++) { freqs[(unsigned char)str[i]]++; } struct model model; for (int i = 0; i < 256; i++) { model.items[i] = (struct char_freq) { .who = i, .when = ((double)freqs[i])/size, }; } sort_model(&model); double bestest_score = 1.0/0.0; struct model bestest_model; for (int d = 0 ;; d++) { double best_model_score = 1.0/0.0; struct model best_model; struct model new_model; for (int i = 0; i < lenof(models); i++) { merge_model(&bestest_model, d, &models[i], &new_model); double score = cmp_model(&model, &new_model); if (score < best_model_score) { best_model_score = score; best_model = new_model; } } if (best_model_score >= bestest_score) { break; } bestest_score = best_model_score; bestest_model = best_model; } char map[256]; for (int i = 0; i < 256; i++) { map[(unsigned char)model.items[i].who] = bestest_model.items[i].who; } for (int i = 0; i < size; i++) { fputc(map[(unsigned char)str[i]], stdout); } return 0; } int analyze_file(FILE *file) { size_t size; char *data = readfile(file, &size); if (!(data && !analyze_buffer(data, size))) { return 1; } return 0; } int main(int argc, char **argv) { FILE *file = stdin; if(argc > 1) { file = fopen(argv[1], "rb"); if (!file) { halt_and_catch(); } } if (analyze_file(file)) { halt_and_catch(); } return 0; } |
submitted at
1 like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | #include <errno.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <sys/time.h> #include <sys/wait.h> #include <time.h> #include <unistd.h> #define THE_SIZE 0x20000000000 // also known as 2 TiB void sin(const char *err) { fprintf(stderr, "fatal: sinful system%s%s\n", err ? ": " : "", err ? err : ""); exit(1); } typedef struct { uint8_t a : 4, b : 4; } bitbyte_t; typedef struct { uint64_t total; uint64_t off_8; uint64_t off_16; uint64_t off_32; uint64_t off_64; uint64_t data; } data_t; static data_t *data; void *align(void *ptr, int ligma) { return (void *)(((size_t)ptr + (ligma - 1)) & -ligma); } uint64_t get(uint64_t i) { if (i >= data->total) { sin("sinful memory access"); } char *ptr = (char *)&data->data; uint64_t off = 0; if ((data->off_8 - 1) <= i) { ptr += (data->off_8 - 1 - off) / 2 + (data->off_8 - 1 - off) % 2; ptr = align(ptr, 1); off += data->off_8 - 1; } else { bitbyte_t *v = &((bitbyte_t *)ptr)[(i - off) / 2]; return (i - off) % 2 ? v->b + 1 : v->a + 1; } if ((data->off_16 - 1) <= i) { ptr += 1 * (data->off_16 - 1 - off); ptr = align(ptr, 2); off += data->off_16 - 1; } else { return ((uint8_t *)ptr)[i - off] + 1; } if ((data->off_32 - 1) <= i) { ptr += 2 * (data->off_32 - 1 - off); ptr = align(ptr, 4); off += data->off_32 - 1; } else { return ((uint16_t *)ptr)[i - off] + 1; } if ((data->off_64 - 1) <= i) { ptr += 4 * (data->off_64 - 1 - off); ptr = align(ptr, 8); off += data->off_64 - 1; } else { return ((uint32_t *)ptr)[i - off] + 1; } return ((uint64_t *)ptr)[i - off] + 1; } void append(uint64_t val) { uint64_t i = data->total++; if (val < 1) { sin("sinful data"); } val--; if (val >= (1ULL << 4) && !data->off_8) { data->off_8 = i + 1; } if (val >= (1ULL << 8) && !data->off_16) { data->off_16 = i + 1; } if (val >= (1ULL << 16) && !data->off_32) { data->off_32 = i + 1; } if (val >= (1ULL << 32) && !data->off_64) { data->off_64 = i + 1; } char *ptr = (char *)&data->data; uint64_t off = 0; if ((data->off_8 - 1) <= i) { ptr += (data->off_8 - 1 - off) / 2 + (data->off_8 - 1 - off) % 2; ptr = align(ptr, 1); off += data->off_8 - 1; } else { bitbyte_t *v = &((bitbyte_t *)ptr)[(i - off) / 2]; (i - off) % 2 ? (v->b = val) : (v->a = val); return; } if ((data->off_16 - 1) <= i) { ptr += 1 * (data->off_16 - 1 - off); ptr = align(ptr, 2); off += data->off_16 - 1; } else { ((uint8_t *)ptr)[i - off] = val; return; } if ((data->off_32 - 1) <= i) { ptr += 2 * (data->off_32 - 1 - off); ptr = align(ptr, 4); off += data->off_32 - 1; } else { ((uint16_t *)ptr)[i - off] = val; return; } if ((data->off_64 - 1) <= i) { ptr += 4 * (data->off_64 - 1 - off); ptr = align(ptr, 8); off += data->off_64 - 1; } else { ((uint32_t *)ptr)[i - off] = val; return; } ((uint64_t *)ptr)[i - off] = val; } int generator(const char *path) { int fd = open(path, O_RDWR | O_CREAT, 0644); if (fd == -1) sin(strerror(errno)); if (truncate(path, THE_SIZE)) sin(strerror(errno)); data = mmap(NULL, THE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) sin(strerror(errno)); int column = 0; int human_readable = isatty(fileno(stdout)); for (uint64_t i = 0; i < data->total; i++) { column += printf("%llu", (unsigned long long)get(i)); if (!human_readable) { column = 100; } if (column > 72) { printf("\n"); column = 0; } else { column += printf(" "); } } struct timespec ts_begin; clock_gettime(CLOCK_MONOTONIC, &ts_begin); for (;;) { uint64_t max_rep = 1; for (uint64_t stride = 1; stride <= data->total / (max_rep + 1); stride++) { uint64_t rep; for (rep = 1; (rep + 1) <= data->total / stride; rep++) { for (uint64_t i = 0; i < stride; i++) { if (get(data->total - 1 - i - rep * stride) != get(data->total - 1 - i - (rep - 1) * stride)) { goto repeat_out; } } } repeat_out: if (max_rep < rep) { max_rep = rep; } } column += printf("%llu", (unsigned long long)max_rep); if (!human_readable) { column = 100; } if (column > 72) { printf("\n"); column = 0; } else { column += printf(" "); } struct timespec ts_end; clock_gettime(CLOCK_MONOTONIC, &ts_end); if ((ts_end.tv_sec * 1000 + ts_end.tv_nsec / 1000000) - (ts_begin.tv_sec * 1000 + ts_end.tv_nsec / 1000000) > 50) { fflush(stdout); clock_gettime(CLOCK_MONOTONIC, &ts_begin); } append(max_rep); } return 0; } int main() { const char *cfg_home = getenv("XDG_CONFIG_HOME"); if (!cfg_home) { const char *home = getenv("HOME"); if (!home) { return generator("/tmp/cg666.bin"); } char path[strlen(home) + sizeof("/.config/cg666/data.bin")]; path[0] = '\0'; strcat(path, home); strcat(path, "/.config/cg666"); pid_t pid; if (!fork()) { if (execl("/usr/bin/env", "/usr/bin/env", "mkdir", "-p", "--", path, NULL)) sin(strerror(errno)); return 0; } int status; if (waitpid(pid, &status, 0) == -1) { sin(strerror(errno)); } else if (status != 0) { sin("mkdir is a sinner"); } strcat(path, "/data.bin"); return generator(path); } else { char path[strlen(cfg_home) + sizeof("/cg666/data.bin")]; path[0] = '\0'; strcat(path, cfg_home); strcat(path, "/cg666"); pid_t pid; if (!fork()) { if (execl("/usr/bin/env", "/usr/bin/env", "mkdir", "-p", "--", path, NULL)) sin(strerror(errno)); return 0; } int status; if (waitpid(pid, &status, 0) == -1) { sin(strerror(errno)); } else if (status != 0) { sin("mkdir is a sinner"); } strcat(path, "/data.bin"); return generator(path); } } |
submitted at
0 likes
submitted at
0 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 | -- -- // Code by SoundOfSpouting#6980 (UID: 151149148639330304) -- -- visual text editor inspired by Emacs evil mode -- term = require "term" text = require "text" event = require "event" unicode = require "unicode" keyboard = require "keyboard" serialization = require "serialization" local args = {...} editor = {} editor.commands = {} editor.buffer = {} function dump(v) return serialization.serialize(v, math.huge) end function dumpfile(f,v) local f = io.open(f,"w") f:write(type(v) == "string" and v or dump(v)) f:close() end local function main() local state = { args = args, arg_n = 1, arg_type = nil, short_arg_n = nil, args_done = false, } editor.set_mode("normal") editor.buffer = editor.new_buffer() while state.arg_n <= #state.args do local arg = state.args[state.arg_n] if not state.arg_type then if arg == "--" then state.args_done = true elseif not state.args_done and arg:match("^%-%-") then state.arg_type = "long" state.arg = state.args[state.arg_n]:sub(3, -1) elseif not state.args_done and arg:match("^%-") then state.arg_type = "short" state.short_arg_n = 2 state.arg = state.args[state.arg_n]:sub( state.short_arg_n, state.short_arg_n ) else editor.commands.open(arg) end end if state.arg_type then local func = editor[state.arg_type .. "opts"][state.arg] local ok, err = true if not func then ok, err = nil, "unknown option: " .. ({ long = '--', short = '-' })[state.arg_type] .. state.arg end if ok then ok, err = func() end if not ok then io.stderr:write(err,'\n') return end if state.exit then return end end state.arg_n = state.arg_n + 1 end editor.run() return true end TheWeakster = { __mode = "k" } function class(obj, super) obj.__index = function(self, i) local v if self ~= obj then v = obj[i] end if super and v == nil then return super[i] end if self == obj then return nil end return v end obj.__proto__ = obj setmetatable(obj, obj) return obj end function static(fn) return function(self, ...) if self.__proto__ ~= self then return fn(self.__proto__, ...) end return fn(self, ...) end end function unrecursive(fn) local n = 0 local function pack(...) return {n = select('#', ...), ...} end return function(...) assert(n < 1, "recursion forbidden here") n = n + 1 local ret = pack(fn(...)) n = n - 1 return (unpack or table.unpack)(ret, 1, ret.n) end end local function DumpLengths(obj) local prim = obj:Length() for k,v in pairs(obj:Lengths()) do if k ~= "chars" then prim = ("%s, %s=%s"):format(prim, k, type(v)=="table" and v.chars or v) end end return prim end Rope = class {} Rope.__Fibo = {[0] = 1} for n=1,64 do Rope.__Fibo[n] = (Rope.__Fibo[n - 1] or 0) + (Rope.__Fibo[n - 2] or 0) end function Rope:__call(String, LeafSize) local obj = class ({}, self) obj.String = String obj.__LeafSize = __LeafSize or 200 obj.__empty = obj:New() return obj end function Rope:__New(data, left, right, norebal) local obj = setmetatable({}, self) if data then obj.__height = 1 obj.__data = data obj.__count = 1 obj.__Lengths = data:Lengths() assert(not (left or right), "branching leaf") return obj end if left and not right then return left end if right and not left then return right end assert(left or right, "Bad") obj.__height = math.max(left.__height, right.__height) + 1 obj.__count = left.__count + right.__count obj.__left = left obj.__right = right local add = function(a,b) return a+b end obj.__Lengths = self:LengthAdd(left:Lengths(), right:Lengths()) if not norebal then if obj:__BalanceFactor() < -1 then if left:__BalanceFactor() > 0 then left = left:__rotateLeft() end obj = obj:__rotateRight() left, right = obj.__left, obj.__right elseif obj:__BalanceFactor() > 1 then if right:__BalanceFactor() < 0 then right = right:__rotateRight() obj = self:__New(nil, left, right, true) end obj = obj:__rotateLeft() left, right = obj.__left, obj.__right end end return obj end Rope.__New = static(Rope.__New) function Rope:__BalanceFactor() if self.__height == 1 then return 0 end return self.__right.__height - self.__left.__height end function Rope:New(...) assert(self.String, "usage: Rope(String[, LeafSize]):New()") local obj for n = 1, select('#', ...) do local v = select(n, ...) local i = 1 local l = v:Length() local objs = {} if obj then objs[#objs + 1] = obj end if l <= self.__LeafSize then objs[#objs + 1] = self:__New(v) else while i <= l do local s = v:Slice(i, i + self.__LeafSize - 1) i = i + s:Length() objs[#objs + 1] = self:__New(s) end end obj = self:Join(objs) end return obj end function Rope:__rotateLeft() if self.__height < 3 or self.__right.__height < 2 then return self end local a, b, c = self.__left, self.__right.__left, self.__right.__right return self:__New(nil, self:__New(nil, a, b, true), c, true) end function Rope:__rotateRight() if self.__height < 3 or self.__left.__height < 2 then return self end local a, b, c = self.__left.__left, self.__left.__right, self.__right return self:__New(nil, a, self:__New(nil, b, c, true), true) end function Rope:Dump(i1) i1 = i1 or "" local i2 = i1 .. " " if self.__data then return self.__data:Dump(i1) end return (("%sRope(%s, height=%s(%s)) {\n%s\n%s\n%s}"):format( i1, DumpLengths(self), self.__height, self:__BalanceFactor(), self.__left:Dump(i2), self.__right:Dump(i2), i1 )) end function Rope:Length(Cat) return self.String.Length(self, Cat) end function Rope:Lengths() return self.__Lengths end function Rope:LengthAdd(this, other) return self.String:LengthAdd(this, other) end function Rope:DefaultLengthAdd(this, other) return self.String:DefaultLengthAdd(this, other) end function Rope:SliceTest(Cat, a, i,j, w) return self.String:SliceTest(Cat, a, i,j, w) end function Rope:Leaves(rev) if self.__data then local b = true return function() if not b then return end b = false return self.__data end end local function lazy(f) local v = nil local b = false return function() if not b then v = f() b = true end return v end end local a, b = lazy(function() return self.__left:Leaves(rev) end), lazy(function() return self.__right:Leaves(rev) end) if rev then a, b = b, a end local function iter() if not a then return end local v = a()() if v == nil then a, b = b return iter() end return v end return iter end function Rope:Implode() if self.__data then return self.__data end local leaves = {} for leaf in self:Leaves() do leaves[#leaves + 1] = leaf end return self.String:Join(leaves) end function Rope:__Join(other, rev) if other.__height > self.__height then return other:__Join(self, not rev) end if self.__data and other.__data then if self:DefaultLengthAdd(self:Lengths(), other:Lengths()) <= self.__LeafSize then if rev then return self:__New(self.String:Join { other.__data, self.__data }) else return self:__New(self.String:Join { self.__data, other.__data }) end else if rev then return self:__New(nil, other, self) else return self:__New(nil, self, other) end end end if self.__height - other.__height > 1 or (self.__height == 2 and other.__height == 1 and self:DefaultLengthAdd(self[rev and "__left" or "__right"]:Lengths(), other:Lengths()) <= self.__LeafSize) then if rev then return self:__New(nil, self.__left:__Join(other, rev), self.__right) else return self:__New(nil, self.__left, self.__right:__Join(other, rev)) end end if rev then return self:__New(nil, other, self) else return self:__New(nil, self, other) end end function Rope:Join(Ropes) local obj = self:PreJoin(Ropes, function(str) local neut = false return function() if neut then return end neut = true return str end end, function(...) return self:New(...) end) if obj then return obj end for _, v in ipairs(Ropes) do assert(v) obj = obj and obj:__Join(v) or v end return obj end function Rope:SliceBy(Cat, i, j) if i > j then return self:Empty(self) end if self.__data then local origin = self.__data local sliced if Cat == nil then sliced = origin:Slice(i, j) else sliced = origin:SliceBy(Cat, i, j) end if origin == sliced then return self end return self.__proto__:__New(sliced) end local test = function(a, i,j, w) local b, ii, jj = self:SliceTest(Cat, a, i,j, w) if b ~= nil then return b, ii, jj end if not w then return i<=a, i, j else return i>a or j>a, i-a, j-a end end local t = {} local f, ni, nj = test(self.__left:Length(Cat), i, j, false) local f2, ni2, nj2 = test(self.__left:Length(Cat), i, j, true) if f2 and i == -math.huge then t[#t + 1] = self.__left elseif f then t[#t + 1] = self.__left:SliceBy(Cat, ni, f2 and math.huge or nj) end if f and j == math.huge then t[#t + 1] = self.__right elseif f2 then t[#t + 1] = self.__right:SliceBy(Cat, f and -math.huge or ni2, nj2) end return self:Join(t) end function Rope:PreJoin(strs, bomb, factory) return self.String.PreJoin(self, strs, function(obj) return coroutine.wrap(function() for obj in bomb(obj) do for obj in obj:Leaves() do coroutine.yield(obj) end end end) end, function(...) return factory(self.String:New(...)) end) end function Rope:Empty(base) return self:New(self.String:Empty(base)) end function Rope:Slice(i, j) return self:SliceBy(nil, i, j) end EditorString = class {} function EditorString:__CharLProc(char, to) if char == "\t" or char == "\n" then to.tabcells_first = self:Empty(self):Lengths() to.tabcells_last = self:Empty(self):Lengths() to.tabcells = 2 else to.tabcells_first = to to.tabcells_last = to to.tabcells = 1 end if char == "\n" then to.lines_first = self:Empty(self):Lengths() to.lines_last = self:Empty(self):Lengths() to.lines = 2 else to.lines_first = to to.lines_last = to to.lines = 1 end to.lines_longest_visual = to.lines_first end function EditorString:__NewLength() local t = { chars = 0, visual = 0, vis_broken_left = 0, vis_broken_right = 0, tabcells = 1, lines = 1, tabstop = nil, offset = 0, } t.lines_first = t t.lines_last = t t.lines_longest_visual = t t.tabcells_first = t t.tabcells_last = t return t end function EditorString:LengthAdd(this, other) assert( this.vis_broken_right == 0 and other.vis_broken_left == 0, "cannot join") local to = {} assert(this.tabcells_first.tabcells == 1) assert(this.tabcells_last.tabcells == 1) assert(this.lines_first.lines == 1) assert(this.lines_last.lines == 1) to.chars = this.chars + other.chars to.visual = this.visual + other.visual to.vis_broken_left = this.vis_broken_left to.vis_broken_right = other.vis_broken_right to.tabcells = this.tabcells + other.tabcells - 1 to.lines = this.lines + other.lines - 1 to.tabstop = this.tabstop to.offset = this.offset if this.lines == 1 and other.lines > 1 then to.lines_first = self:LengthAdd( this, other.lines_first ) elseif this.lines == 1 then to.lines_first = to else to.lines_first = this.lines_first end if other.lines == 1 and this.lines > 1 then to.lines_last = self:LengthAdd( this.lines_last, other ) elseif other.lines == 1 then to.lines_last = to else to.lines_last = other.lines_last end if to.lines > 1 then local longest = this.lines_longest_visual if this.lines > 1 and other.lines > 1 then local middle = self:LengthAdd(this.lines_last, other.lines_first) longest = longest.visual < middle.visual and middle or longest end local last = to.lines_last longest = longest.visual < last.visual and last or longest local long2 = other.lines_longest_visual longest = longest.visual < long2.visual and long2 or longest to.lines_longest_visual = longest else to.lines_longest_visual = to end if this.tabcells == 1 and other.tabcells > 1 then to.tabcells_first = self:LengthAdd( this, other.tabcells_first ) elseif this.tabcells == 1 then to.tabcells_first = to else to.tabcells_first = this.tabcells_first end if other.tabcells == 1 and this.tabcells > 1 then to.tabcells_last = self:LengthAdd( this.tabcells_last, other ) elseif other.tabcells == 1 then to.tabcells_last = to else to.tabcells_last = other.tabcells_last end to.tabwidth = this.tabwidth or other.tabwidth or nil if to.tabcells_first.chars == to.lines_first.chars then to.tabwidth = nil end return to end function EditorString:DefaultLengthAdd(this, other) return this.chars + other.chars end function EditorString:New(str, tabstop, offset) local obj = setmetatable({}, self.__proto__) offset = offset or 0 local i = 1 local t = {} local charlen = self:__NewLength() charlen.chars = 1 obj.__Lengths = self:__NewLength() obj.__Lengths.tabstop = tabstop obj.__Lengths.offset = offset % tabstop while i <= #str do local char = unicode.sub(str:sub(i, i+3), 1, 1) i = i + #char local charW obj:__CharLProc(char, charlen) if char == "\t" then charW = tabstop - offset % tabstop char = "\t" .. string.char(charW) charlen.tabwidth = charW else charW = unicode.charWidth(char) charlen.tabwidth = nil end if char == "\n" then offset = -charW end charlen.visual = charW offset = ((offset + charW) % tabstop) obj.__Lengths = self:LengthAdd( obj.__Lengths, charlen, obj.__Lengths ) t[#t + 1] = char end obj.__data = table.concat(t) return obj end function EditorString:SliceBy(Cat, i, j) if i > j then return self:Empty(self) end if (Cat == nil or Cat == "chars") and i <= 1 and j >= self.__Lengths.chars then return self end local obj = setmetatable({}, self.__proto__) obj.__Lengths = self:__NewLength() obj.__Lengths.tabstop = self.__Lengths.tabstop obj.__Lengths.offset = self.__Lengths.offset local charlen = self:__NewLength() charlen.chars = 1 local _ic = 1 local _i = 1 if Cat == "visual" then _i = _i - self.__Lengths.vis_broken_left j = math.min(self.__Lengths.visual, j) i = math.max(1, i) end local t = {} local left, right = 0, 0 while _ic <= #self.__data and _i <= j do local char = unicode.sub(self.__data:sub(_ic, _ic+3), 1, 1) local tab _ic = _ic + #char if char == "\t" then tab = self.__data:sub(_ic, _ic) _ic = _ic + 1 end local charW if tab then charW = tab:byte() else charW = unicode.charWidth(char) end local ins if Cat == nil or Cat == "chars" then ins = _i >= i if _i > j then break end _i = _i + 1 elseif Cat == "visual" then local _j = _i + charW - 1 if _i < i and _j >= i then left = i - _i ins = true elseif _i >= i and _j > j then right = _j - j ins = true elseif _i >= i then ins = true elseif _i > j then break end _i = _j + 1 elseif Cat == "tabcells" or Cat == "lines" then ins = _i >= i local found = false if char == "\n" or (Cat == "tabcells" and char == "\t") then found = math.ceil(j) > j and _i <= j _i = _i + 1 end if _i > j and not found then break end end obj.__Lengths.offset = (obj.__Lengths.offset + charW) % obj.__Lengths.tabstop if char == "\n" or tab then obj.__Lengths.offset = 0 end if ins then self:__CharLProc(char, charlen) if tab then t[#t + 1] = char .. tab charlen.tabwidth = tab:byte() else t[#t + 1] = char charlen.tabwidth = nil end charlen.visual = charW obj.__Lengths = self:LengthAdd( obj.__Lengths, charlen ) end end obj.__Lengths.vis_broken_left = left obj.__Lengths.vis_broken_right = right obj.__data = table.concat(t) return obj end function EditorString:PreJoin(strs, bomb, factory) local modified = false local strs2 = {} local length for k, v in ipairs(strs) do local lv = v:Lengths() if length then if lv.tabstop ~= length.tabstop then local tar = {} for par in bomb(v) do local offset = length.tabcell_last.visual tar[#tar + 1] = factory(par:Implode(), length.tabstop, offset) length = self:LengthAdd(length, tar[#tar]:Lengths()) end v = self:Join(tar) error("whag") modified = true else local offset = length.tabcells_last.visual + lv.tabcells_first.visual if lv.tabwidth and lv.tabcells_first.chars < lv.lines_first.chars and length.tabcells >= 2 and lv.tabwidth ~= length.tabstop - offset % length.tabstop then v = self:Join { v:Slice(-math.huge, lv.tabcells_first.chars), factory("\t", length.tabstop, offset), v:Slice(lv.tabcells_first.chars + 2, math.huge) } modified = true end length = self:LengthAdd(length, v:Lengths()) end else length = lv end assert(v) strs2[#strs2 + 1] = v end if modified then local jj = self:Join(strs2) return jj end end function EditorString:Join(strs) if #strs == 0 then error(" ") end local obj = self:PreJoin(strs, function(str) local neut = false return function() if neut then return end neut = true return str end end, function(...) return self:New(...) end) if obj then return obj end obj = setmetatable({}, self) obj.__Lengths = nil local t = {} for k, v in ipairs(strs) do obj.__Lengths = obj.__Lengths and self:LengthAdd(obj.__Lengths, v.__Lengths) or v.__Lengths t[#t + 1] = v.__data end obj.__data = table.concat(t) return obj end EditorString.Join = static(EditorString.Join) function EditorString:Implode(visual) if visual then local str = self.__data local t = {} local i = 1 local charWf = nil local charWl = nil while i <= #str do local char = unicode.sub(self.__data:sub(i, i+3), 1, 1) local tab i = i + #char if char == "\t" then tab = self.__data:sub(i, i) i = i + 1 end local charW if tab then char = (" "):rep(tab:byte()) charW = #char else charW = unicode.charWidth(char) end if not charWf then charWf = charW end charWl = charW t[#t + 1] = char end if self:Length("vis_broken_left") > 0 then t[1] = (" "):rep(charWf - self:Length("vis_broken_left")) end if self:Length("vis_broken_right") > 0 then t[#t] = (" "):rep(charWl - self:Length("vis_broken_right")) end return table.concat(t) end return self.__data:gsub("\t(.)",function(tab) return "\t" end) end function EditorString:Slice(i, j) return self:SliceBy(nil, i, j) end function EditorString:Dump(i1) return i1.."String("..DumpLengths(self)..") "..(("%q"):format(self:Implode()):gsub("\\\n","\\n")) end function EditorString:SliceTest(Cat, a, i,j, w) if Cat ~= "tabcells" and Cat ~= "lines" then assert( Cat == nil or Cat == "chars" or Cat == "visual", "cannot slice" ) return nil end if not w then return i<=a, i, j else return i>=a or j>=a, i-a+1, j-a+1 end end function EditorString:Lengths() return self.__Lengths end function EditorString:Length(Cat) if Cat == nil then return self:Length("chars") end return self:Lengths()[Cat] end function EditorString:Empty(base) return self:New("", base:Length("tabstop"), 0) end EditorRope = Rope(EditorString) function editor.new_buffer() local buffer = {} buffer.vdirty = {all=true} buffer.data = EditorRope:New(EditorString:New("", editor.tabstop)) buffer.row = 1 buffer.col = 1 buffer.colTo = 1 buffer.vx = 1 buffer.vy = 1 return buffer end editor.movement = {} editor.movement.arrows = {} function editor.camera_move_horz(where) local limit = editor.buffer.data :SliceBy("lines", editor.buffer.vy, editor.buffer.vy + editor.buffer.vh - 1 ) :Lengths() .lines_longest_visual .visual - editor.buffer.vw + 2 local oldpos = editor.buffer.vx local pos = math.max(1, math.min(limit, editor.buffer.vx + where)) if oldpos ~= pos then editor.buffer.vx = pos editor.buffer.vdirty = {all=true} end end function editor.camera_notify_shift(r1, r2, where) local gpu = term.gpu() r1 = r1 - editor.buffer.vy + 1 r2 = r2 - editor.buffer.vy + 1 if (r1 > editor.buffer.vh and r2 > editor.buffer.vh) or (r1 < 1 and r2 < 1) then return end r1, r2 = math.max(r1, 1), math.min(r2, editor.buffer.vh) local t1, t2 = r1 + where, r2 + where local o if not editor.buffer.vdirty.all then if math.abs(where) < editor.buffer.vh then if where < 0 then t2 = math.min(t2, editor.buffer.vh) o = math.min(t2-t1+1, r2-r1+1) r2, t2 = r1+o-1, t1+o-1 else t1 = math.max(t1, 1) o = math.min(t2-t1+1, r2-r1+1) r1, t1 = r2-o+1, t2-o+1 end gpu.copy(1, r1, editor.buffer.vw, o, 0, t1-r1) local b2 = editor.buffer.vdirty editor.buffer.vdirty = {} for y = 1, #b2 do if y >= t1 and y <= t2 then editor.buffer.vdirty[y] = b2[y + (r1 - t1)] elseif y >= r1 and y <= r2 then editor.buffer.vdirty[y] = true end end else editor.buffer.vdirty.all = true end end end function editor.camera_move_vert(where) local limit = editor.buffer.data:Length("lines") - editor.buffer.vh + 1 local oldpos = editor.buffer.vy local pos = math.max(1, math.min(limit, editor.buffer.vy + where)) if oldpos ~= pos then editor.camera_notify_shift(-math.huge, math.huge, oldpos - pos) editor.buffer.vy = pos end end function editor.cursor_move_horz(where) local line = editor.buffer.data :SliceBy("lines", editor.buffer.row, editor.buffer.row) local width = line:Length() local oldrow = editor.buffer.row local oldcol = editor.buffer.col editor.buffer.col = math.max(1, math.min(width + 1, editor.buffer.col + where)) if where == math.huge then editor.buffer.colTo = math.huge else if not (oldrow == editor.buffer.row and oldcol == editor.buffer.col) then editor.cursor_refresh_col() end end end function editor.cursor_refresh_col() local colvis = editor.buffer.data :SliceBy("lines", editor.buffer.row, editor.buffer.row) :Slice(1,editor.buffer.col - 1) :Length("visual") + 1 editor.buffer.colTo = colvis end function editor.cursor_move_vert(where) editor.buffer.row = math.max( 1, math.min( editor.buffer.data:Length("lines"), editor.buffer.row + where ) ) local data = EditorRope:Join { editor.buffer.data, EditorRope:New(EditorString:New("\n", editor.buffer.data:Length("tabstop"), 0)) } editor.buffer.col = data :SliceBy("lines", editor.buffer.row, editor.buffer.row + .5) :SliceBy("visual", -math.huge, editor.buffer.colTo) :Length() end function editor.camera_to_cursor() local colvis = editor.buffer.data :SliceBy("lines", editor.buffer.row, editor.buffer.row) :Slice(1,editor.buffer.col - 1) :Length("visual") + 1 local x1,x2, y1,y2 = editor.buffer.vx, editor.buffer.vx + editor.buffer.vw - 1, editor.buffer.vy, editor.buffer.vy + editor.buffer.vh - 1 if colvis < x1 then editor.camera_move_horz(colvis - x1) elseif colvis > x2 then editor.camera_move_horz(colvis - x2) end if editor.buffer.row < y1 then editor.camera_move_vert(editor.buffer.row - y1) elseif editor.buffer.row > y2 then editor.camera_move_vert(editor.buffer.row - y2) end end function outnormal_on_key(char, key, mod) if key == "c" and mod.control then editor.set_mode("normal") return true end return end function rowcol_to_char(row, col, data) return (data or editor.buffer.data) :SliceBy("lines", -math.huge, row - 0.5) :Length() + math.min(row >= 1 and (editor.buffer.data:SliceBy("lines", row, row):Length() + 1) or 0,math.max(1, col)) end function char_to_rowcol(char, data) local sub = (data or editor.buffer.data) :Slice(-math.huge, char - 1) local row = sub :Length("lines") local col = sub:Lengths().lines_last.chars + 1 return row, col end function rechar() editor.buffer.row, editor.buffer.col = char_to_rowcol(rowcol_to_char(editor.buffer.row,editor.buffer.col)) end function editor.delete(r1, c1, r2, c2) if r1 > r2 or (r1 == r2 and c1 > c2) then return editor.delete(r2, c2, r1, c1) end local i, j = rowcol_to_char(r1, c1), rowcol_to_char(r2, c2) local count = j - i + 1 if count <= 0 then return end local pos2 = rowcol_to_char(editor.buffer.row, editor.buffer.col) local data = editor.buffer.data:Slice(i, j) editor.buffer.data = EditorRope:Join { editor.buffer.data:Slice(-math.huge, i - 1), editor.buffer.data:Slice(j + 1, math.huge) } if pos2 > j then editor.buffer.row, editor.buffer.col = char_to_rowcol(pos2 - count) editor.cursor_refresh_col() editor.camera_to_cursor() elseif pos2 >= i then editor.buffer.row, editor.buffer.col = char_to_rowcol(i) editor.cursor_refresh_col() editor.camera_to_cursor() end local r1v = r1 - editor.buffer.vy + 1 if r1v <= editor.buffer.vh and not editor.buffer.vdirty.all then editor.buffer.vdirty[r1v] = true editor.camera_notify_shift(r2 + 2, math.huge, -(data:Length("lines") - 1)) end editor.buffer.dirty = true end function editor.insert(row, col, data) local pos = rowcol_to_char(row, col) editor.buffer.data = EditorRope:Join { editor.buffer.data:Slice(-math.huge, pos - 1), data, editor.buffer.data:Slice(pos, math.huge) } local rv = row - editor.buffer.vy + 1 if rv <= editor.buffer.vh and not editor.buffer.vdirty.all then editor.buffer.vdirty[rv] = true editor.camera_notify_shift(rv + 1, math.huge, (data:Length("lines") - 1)) end local pos2 = rowcol_to_char(editor.buffer.row, editor.buffer.col) if pos2 >= pos then editor.buffer.row, editor.buffer.col = char_to_rowcol(pos2 + data:Length()) editor.cursor_refresh_col() editor.camera_to_cursor() end editor.buffer.dirty = true end function navigation_on_key(char, key, mod) if tonumber(char) then editor.counter = (editor.counter or 0)*10 + tonumber(char) return true end local pg = math.ceil(editor.buffer.vh / 4) if mod.control then if key == "left" then editor.camera_move_horz(-(editor.counter or 1)) elseif key == "right" then editor.camera_move_horz((editor.counter or 1)) elseif key == "home" then editor.camera_move_horz(-math.huge) elseif key == "end" then editor.camera_move_horz(math.huge) elseif key == "up" then editor.camera_move_vert(-(editor.counter or 1)) elseif key == "down" then editor.camera_move_vert((editor.counter or 1)) elseif key == "pageUp" then editor.camera_move_vert(-(editor.counter or 1) * pg) elseif key == "pageDown" then editor.camera_move_vert((editor.counter or 1) * pg) else return end else if key == "left" then editor.cursor_move_horz(-(editor.counter or 1)) elseif key == "right" then editor.cursor_move_horz((editor.counter or 1)) elseif key == "home" then editor.cursor_move_horz(-math.huge) elseif key == "end" then editor.cursor_move_horz(math.huge) elseif key == "up" then editor.cursor_move_vert(-(editor.counter or 1)) elseif key == "down" then editor.cursor_move_vert((editor.counter or 1)) elseif key == "pageUp" then editor.cursor_move_vert(-(editor.counter or 1) * pg) editor.camera_move_vert(-(editor.counter or 1) * pg) elseif key == "pageDown" then editor.cursor_move_vert((editor.counter or 1) * pg) editor.camera_move_vert((editor.counter or 1) * pg) elseif char == "G" then if not editor.counter then return end local diff = editor.counter - editor.buffer.row if diff ~= 0 then editor.cursor_move_vert(diff) end else return end editor.camera_to_cursor() end editor.counter = nil return true end editor.modes = {} editor.modes.normal = {} function editor.modes.normal.init() editor.set_status("") editor.counter = nil end function editor.modes.normal.on_key(char, key, mod) if outnormal_on_key(char, key, mod) then return true end if char == "i" then editor.set_mode("insert") return true end if char == ":" then editor.command_line() return true end return navigation_on_key(char, key, mod) end editor.modes.insert = {} function editor.modes.insert.init() editor.set_status("-- INSERT --") editor.counter = nil end function editor.modes.insert.on_key(char, key, mod) if outnormal_on_key(char, key, mod) then return true end if key == "back" then local col = editor.buffer.col - 1 local row = editor.buffer.row if col < 1 then row = row - 1 col = math.huge end editor.delete(row, col, row, col) return elseif key == "delete" then editor.delete(editor.buffer.row, editor.buffer.col, editor.buffer.row, editor.buffer.col) return end if char == "\r" then char = "\n" end if char then editor.insert(editor.buffer.row, editor.buffer.col, EditorRope:New(EditorString:New(char, editor.buffer.data:Length("tabstop"), 0)) ) end return navigation_on_key(char, key, mod, true) end function editor.set_mode(mode) editor.mode = editor.modes[mode] editor.mode.init() end editor.status_line = "" function editor.set_status(line) editor.status_line = line end function editor.run() while true do editor.draw() local ev = {(editor.buffer.cursor_oob and event or term).pull()} if ev[1] == "key_down" then local _, addr, char, code, player = (unpack or table.unpack)(ev) editor.mode.on_key(char ~= 0 and unicode.char(char) or nil, keyboard.keys[code], { control = keyboard.isControlDown(), meta = keyboard.isAltDown(), shift = keyboard.isShiftDown(), }) end end end function editor.set_cursor(x, y) local ls = editor.buffer.data:Length("lines") end editor.cmd_hist = {} function editor.command_line() local gpu = term.gpu() local vw, vh, vx, vy = term.getViewport() term.setCursor(2,vh) term.clearLine() term.write(":") local line = term.read(editor.cmd_hist) editor.buffer.vdirty = {all = true} if not line then editor.set_status("") return end line = line:match("([^\n]*)") local cmd = line:match("([^ ]+)") if not cmd then editor.set_status("") return end local param = line:sub(#cmd+2,-1) editor.set_status(":"..line) if not editor.commands[cmd] then editor.set_status("No such command: "..cmd) return end editor.commands[cmd](param) end function editor.draw() local t = os.clock() local gpu = term.gpu() local vw, vh, vx, vy = term.getViewport() local statusRight = {} local resize = false if editor.buffer.vw ~= vw or editor.buffer.vh ~= (vh-1) then editor.buffer.vdirty.all = true editor.buffer.vw = vw editor.buffer.vh = vh - 1 end editor.camera_move_horz(0) editor.camera_move_vert(0) if editor.buffer.vdirty.all then editor.buffer.vdirty = {} for n = 1, editor.buffer.vh do editor.buffer.vdirty[n] = true end end local ls = editor.buffer.data:Length("lines") for y = 1, editor.buffer.vh do if editor.buffer.vdirty[y] then editor.buffer.vdirty[y] = false local yy = editor.buffer.vy + y - 1 local xx = editor.buffer.vx if yy < 1 or y > ls then gpu.set(1, y, "~"..(" "):rep(vw - 1)) else local pref = (" "):rep(math.max(0,1-xx)) local i = xx + #pref local j = i + vw - #pref - 1 str = editor.buffer.data :SliceBy("lines", yy, yy) :SliceBy("visual", i, j) local vlen = str:Length("visual") str = str:Implode():Implode("visual") str = pref .. str .. (" "):rep(vw - (vlen + #pref)) gpu.set(1, y, str) end end end local status = editor.status_line if editor.counter then statusRight[#statusRight+1] = editor.counter.."" end local colvis = editor.buffer.data :SliceBy("lines", editor.buffer.row, editor.buffer.row) :Slice(1,editor.buffer.col - 1) :Length("visual") + 1 statusRight[#statusRight + 1] = editor.buffer.row..","..editor.buffer.col.."-"..colvis local lines = editor.buffer.data:Length("lines") local where = (editor.buffer.vy - 1) / (lines - editor.buffer.vh) if where == 0 then where = "Top" if lines < editor.buffer.vh then where = "All" end elseif where == 1 then where = "Bot" else where = ("%i%%"):format(math.floor(where * 100 + .5)) end statusRight[#statusRight + 1] = where statusRight = table.concat(statusRight," ") status = status .. (" "):rep(vw - unicode.wlen(statusRight..status)) .. statusRight gpu.set(1, vh, status) local tx, ty = colvis - editor.buffer.vx + 1, editor.buffer.row - editor.buffer.vy + 1 if tx >= 1 and ty >= 1 and tx <= vw and ty < vh then editor.buffer.cursor_oob = false term.setCursor(tx, ty) else editor.buffer.cursor_oob = true term.setCursor(1,1) end end editor.tabstop = 4 function editor.__file_progressbar(file, progress, time, lines, chars) local tw,th = term.getViewport() local pgy = math.floor((th-2) / 2) local pgw = math.ceil(tw*0.8) local pgx = math.floor((tw-pgw)/2) term.clear() local oldbr = term.getCursorBlink() term.setCursorBlink(false) term.setCursor(pgx,pgy) local progresst = math.floor(progress*(pgw-2)+.5) term.write(("[%s%s]"):format( ("#"):rep(math.min(progresst,pgw-2)), (" "):rep(pgw-2-progresst) )) term.setCursor(pgx,pgy+2) term.write(("%.1fs\t%q %sL, %sC"):format(time, file, editor.buffer.data:Length("lines"), editor.buffer.data:Length())) term.setCursor(pgx+2+progresst,pgy) term.setCursorBlink(oldbl) end function editor.commands.open(arg) local file, err = io.open(arg,"rb") if not file then editor.set_status(err) return nil, err end editor.buffer = editor.new_buffer() editor.buffer.filename = arg local block local t = os.clock() local tt = os.clock() local invalid local function check(s) s = unicode.sub(s:sub(-4,-1), -1, -1) if not pcall(unicode.charWidth, s) then return #s end return 0 end local tw,th = term.getViewport() local pgy = math.floor((th-2) / 2) local pgw = math.ceil(tw*0.8) local pgx = math.floor((tw-pgw)/2) local oldbl = term.getCursorBlink() term.setCursorBlink(true) term.clear() local size = file:seek('end') file:seek('set') local progressb = 0 local progresst = 0 local begint = os.clock() local drawbr = editor.__file_progressbar drawbr(arg, 0, 0, 1, 0) os.sleep() while true do block = file:read(40) if not block then break end if invalid then block = invalid .. block invalid = nil end local trail = check(block) if trail > 0 then invalid = block:sub(-trail, -1) block = block:sub(1, -trail - 1) end local data = editor.buffer.data local str = EditorString:New(block, editor.tabstop, data:Lengths().tabcells_last.chars) local app = EditorRope:New(str) editor.buffer.data = EditorRope:Join { editor.buffer.data, app } data = editor.buffer.data progressb = progressb + #block if os.clock()-tt > 0.5 then drawbr(arg, progressb/size, os.clock()-begint, data:Length("lines"), data:Length()) os.sleep(0) tt = os.clock() end end editor.buffer.vdirty = {all=true} os.sleep(0) local data = editor.buffer.data editor.set_status(("%q %sL, %sC"):format(arg, data:Length("lines"), data:Length())) term.setCursorBlink(oldbl) term.clear() end function editor.commands.eval(param) local ok, err = (loadstring or load)(param) local vw, vh = term.getViewport() local out if ok then ok, err = pcall(function() local ok, err = xpcall(ok,debug.traceback) out = err if type(out) ~= "string" then out = serialization.serialize(out, vh) end return err end) end err = out or err err = text.detab(err) err = {text.wrap(err, vw, vw)} err[#err] = nil if #err <= 1 then editor.set_status(err[1] or "") else term.setCursor(1,vh) term.clearLine() print(table.concat(err,"\n")) term.write("Press enter to continue... ") editor.set_status("") term.read() editor.buffer.vdirty = {all=true} end end function editor.commands.q() os.exit() end function editor.commands.w(param) if param == "" then param = nil end param = editor.buffer.filename or param if not param then editor.set_status("No filename") return end local file = io.open(param,"wb") local progressb = 0 local size = editor.buffer.data:Length() local begint = os.clock() local drawbr = editor.__file_progressbar drawbr(param, progressb/size, os.clock()-begint, 1, 0) local len local tt = os.clock() for line in editor.buffer.data:Leaves() do file:write((line:Implode())) progressb = progressb + line:Length() len = len and EditorString:LengthAdd(len, line:Lengths()) or line:Lengths() if os.clock() - tt > 0.5 then os.sleep() tt = os.clock() drawbr(param, progressb/size, os.clock()-begint, len.lines, len.chars) end end file:close() editor.set_status(("%q %sL, %sC written"):format(param, len.lines, len.chars)) editor.buffer.vdirty = {all = true} editor.buffer.dirty = false return true end function editor.commands.wq(param) if not editor.commands.w(param) then return end editor.commands.q() return true end local function dirty_checked(k) editor.commands[k .. "!"] = editor.commands[k] editor.commands[k] = function(...) if editor.buffer.dirty then editor.set_status("No write since last change") return end return editor.commands[k .. "!"](...) end end dirty_checked("open") dirty_checked("q") editor.longopts = {} editor.shortopts = {} function editor.longopts.help() local helpful_quotes = { "Nothing is impossible, the word itself says ‘I’m possible.’", "I cannot express how important it is to believe that taking one tiny—and possibly very uncomfortable—step at a time can ultimately add up to a great distance.", "Here comes the sun. And I say, it’s all right.", "Do your thing and don't care if they like it.", "I’d rather regret the things I’ve done than the things I haven’t done.", "Try to be a rainbow in someone else’s cloud.", "Real change, enduring change, happens one step at a time.", "A dead end is just a good place to turn around.", "Choose to be optimistic, it feels better.", "Just say yes and you’ll figure it out afterwards.", "You can’t make a cloudy day a sunny day, but you can embrace it and decide it’s going to be a good day after all.", "Find a group of people who challenge and inspire you, spend a lot of time with them, and it will change your life.", "You can, you should, and if you’re brave enough to start, you will.", "In your life expect some trouble. But when you worry, you make it double. But don't worry, be happy, be happy now.", "You’re in the same boat with a lotta your friends. Waitin’ for the day your ship’ll come in, and the tide's gonna turn and it’s all gonna roll your way.", "Keep your face always toward the sunshine, and shadows will fall behind you.", "You are never too old to set another goal or to dream a new dream.", "Life is like riding a bicycle. To keep your balance, you must keep moving.", "It is never too late to be what you might have been.", "Some people look for a beautiful place. Others make a place beautiful.", "We must be willing to let go of the life we planned so as to have the life that is waiting for us.", "Happiness is not by chance, but by choice.", "If I cannot do great things, I can do small things in a great way.", "My mission in life is not merely to survive, but to thrive.", "You are enough just as you are.", "The bad news is time flies. The good news is you're the pilot.", "You make a life out of what you have, not what you're missing.", "There are years that ask questions and years that answer.", "All we have to decide is what to do with the time that is given us.", "At first people refuse to believe that a strange new thing can be done, then they begin to hope it can be done, then they see it can be done—then it is done and all the world wonders why it was not done centuries ago.", "Each of us is more than the worst thing we've ever done.", "That is one good thing about this world ... there are always sure to be more springs.", "These things are good things.", "Pay attention to the present, you can improve upon it.", "Be yourself; everyone else is already taken.", "Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.", "You cannot change what you are, only what you do.", "Thou must gather thine own sunshine.", "It is not enough to have a good mind; the important thing is to use it well.", "People begin to become successful the minute they decide to be.", "Walk to your goal firmly and with bold steps.", "Every strike brings me closer to the next home run.", "Concentrate all your thoughts upon the work in hand. The Sun's rays do not burn until brought to a focus.", "Lay plans for something big by starting with it when small.", "No exact recipe for today. Gather all available ingredients and whip yourself up something delicious.", "One's destination is never a place, but a new way of seeing things.", "It's how you deal with failure that determines how you achieve success.", "I have not failed. I've just found 10,000 ways that won't work.", "It takes as much energy to wish as it does to plan.", "Do anything, but let it produce joy.", "Do your little bit of good where you are; it's those little bits of good put together that overwhelm the world.", "No one is useless in this world who lightens the burdens of another.", "As we work to create light for others, we naturally light our own way.", "Dwell on the beauty of life. Watch the stars, and see yourself running with them.", "That's what I consider true generosity: You give your all, and yet you always feel as if it costs you nothing.", "You have brains in your head. You have feet in your shoes. You can steer yourself any direction you choose.", "You rarely win, but sometimes you do.", "I've got nothing to do today but smile.", "I believe great people do things before they are ready.", "I have discovered in life that there are ways of getting almost anywhere you want to go, if you really want to go.", "If you spend too much time thinking about a thing, you'll never get it done.", "For me, becoming isn't about arriving somewhere or achieving a certain aim. I see it instead as forward motion, a means of evolving, a way to reach continuously toward a better self. The journey doesn't end.", "Anything is possible with sunshine and a little pink.", "Imagine this: What would happen if we were all brave enough to believe in our own ability, to be a little more ambitious? I think the world would change.", "You are the one that possesses the keys to your being. You carry the passport to your own happiness.", "Take your victories, whatever they may be, cherish them, use them, but don't settle for them.", "We do not need magic to change the world, we carry all the power we need inside ourselves already: We have the power to imagine better.", "Just believe in yourself. Even if you don’t, pretend that you do and, at some point, you will.", "Believe you can and you're halfway there.", "You are imperfect, you are wired for struggle, but you are worthy of love and belonging.", "If you see someone without a smile, give 'em yours!", "You get in life what you have the courage to ask for.", "Act as if what you do makes a difference. It does.", "For there is always light. If only we’re brave enough to see it. If only we’re brave enough to be it.", "You are your best thing.", "There is no greater thing you can do with your life and your work than follow your passions–in a way that serves the world and you.", "We talk on principal, but act on motivation.", "The secret of getting ahead is getting started.", "Winners never quit, and quitters never win.", "When the going gets tough, the tough get going.", "The best way to predict the future is to create it.", "Always make a total effort, even when the odds are against you.", "Don’t be afraid to give up the good to go for the great.", "Don’t let the fear of losing be greater than the excitement of winning.", "The question isn’t who is going to let me; it’s who is going to stop me.", "It is better to fail in originality than to succeed in imitation.", "Start where you are. Use what you have. Do what you can.", "Your present circumstances don’t determine where you can go; they merely determine where you start.", "You must expect great things of yourself before you can do them.", "Do what you have to do until you can do what you want to do.", "You can never cross the ocean until you have the courage to lose sight of the shore.", "One way to keep momentum going is to have constantly greater goals.", "You don’t have to see the whole staircase, just take the first step.", "We are what we repeatedly do. Excellence, then, is not an act, but a habit.", "God always strives together with those who strive.", "Change your thoughts and you change your world.", "It’s hard to beat a person who never gives up.", "The only person you should try to be better than, is the person you were yesterday.", "Never give up, for that is just the place and time that the tide will turn.", "The difference between a stumbling block and a stepping stone is how high you raise your foot.", "Study while others are sleeping; work while others are loafing; prepare while others are playing; and dream while others are wishing.", "The difference between the impossible and the possible lies in a person’s determination.", "More powerful than the will to win is the courage to begin.", "Don’t be pushed by your problems; be led by your dreams.", "You don’t drown by falling in water; you drown by staying there.", "If you’re going through hell, keep going", "Better to do something imperfectly than to do nothing flawlessly.", "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.", "Fortune sides with him who dares.", "If you want something you’ve never had, you must be willing to do something you’ve never done.", "Nobody can go back and start a new beginning, but anyone can start today and make a new ending.", "Nothing will work unless you do.", "The more I want to get something done the less I call it work.", "The work you do when you procrastinate is probably the work you should be doing for the rest of your life.", "Focus on being productive instead of busy.", "The beginning is the most important part of the work.", "An employee’s motivation is a direct result of the sum of interactions with his or her manager.", "If you don’t value your time, neither will others. Stop giving away your time and talents- start charging for it.", "Things work out best for those who make the best of how things work out.", "There will be obstacles. There will be doubters. There will be mistakes. But with hard work, there are no limits.", "Build your own dreams, or someone else will hire you to build theirs.", "If you are working on something that you really care about, you don’t have to be pushed. The vision pulls you.", "To be successful you must accept all challenges that come your way. You can’t just accept the ones you like.", "If you want to achieve excellence, you can get there today. As of this second, quit doing less-than-excellent work.", "The only place where success comes before work is in the dictionary.", "We aim above the mark to hit the mark.", "Successful and unsuccessful people do not vary greatly in their abilities. They vary in their desires to reach their potential.", "When someone tells me ‘no,’ it doesn’t mean I can’t do it, it simply means I can’t do it with them.", "Strive not to be a success, but rather to be of value.", "The individual who says it is not possible should get out of the way of those doing it.", "You’ve got to get up every morning with determination if you’re going to go to bed with satisfaction.", "I find that the harder I work, the more luck I seem to have.", "Do not wait to strike till the iron is hot; but make it hot by striking.", "Focus on the journey, not the destination. Joy is found not in finishing an activity but in doing it.", "The secret of joy in work is contained in one word – excellence. To know how to do something well is to enjoy it.", "Much of the stress that people feel doesn’t come from having too much to do. It comes from not finishing what they’ve started.", "Don’t let what you cannot do interfere with what you can do.", "The wise does at once what the fool does at last.", "To know and not to do, is not to know.", "Zeal without knowledge is fire without light.", "Perfection is boring. Getting better is where all the fun is.", "Our greatest fear should not be of failure but of succeeding at things in life that don’t really matter.", "The most common way people give up their power is by thinking they don’t have any.", "It’s not what you look at that matters, it’s what you see.", "Somewhere, something incredible is waiting to be known.", "Experience is a hard teacher because she gives the test first, the lesson afterwards.", "Keep your eyes on the stars, and your feet on the ground.", "I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do.", "There are two kinds of people in this world; those who want to get things done, and those who don’t want to make mistakes.", "If you are not willing to risk the usual you will have to settle for the ordinary.", "Live out of your imagination, not your history.", "If the decisions you make about where you invest your blood, sweat, and tears are not consistent with the person you aspire to be, you’ll never become that person.", "A person who never made a mistake never tried anything new.", "Always remember that you are absolutely unique; just like everyone else.", "Twenty years from now you will be more disappointed by the things that you didn’t do than by the ones you did do, so throw off the bowlines, sail away from safe harbor, catch the trade winds in your sails. Explore, Dream, Discover.", "The will to succeed is important, but what’s more important is the will to prepare.", "Obstacles don’t have to stop you. If you run into a wall, don’t turn around and give up.", "We can’t help everyone, but everyone can help someone.", "There are two types of people who will tell you that you cannot make a difference in this world: those who are afraid to try and those who are afraid you will succeed.", "We become what we think about most of the time, and that’s the strangest secret.", "Develop success from failures. Discouragement and failure are two of the surest stepping stones to success.", "If you continue to think they way you’ve always thought, you’ll continue to get what you’ve always got.", "If you can imagine it, you can achieve it; if you can dream it, you can become it.", "It is during our darkest moments that we must focus to see the light.", "The more difficult the victory, the greater the happiness in winning.", "Good things come to people who wait, but better things come to those who go out and get them.", "Your talent is God’s gift to you. What you do with it is your gift back to God.", "Real difficulties can be overcome; it is only the imaginary ones that are unconquerable.", "You measure the size of the accomplishment by the obstacles you had to overcome to reach your goals.", "The key is to keep company only with people who uplift you, whose presence calls forth your best.", "Nurture your mind with great thoughts. To believe in the heroic makes heroes.", "Don’t spend time beating on a wall, hoping to transform it into a door.", "Work like there is someone working 24 hours a day to take it away from you.", "I am not a product of my circumstances. I am a product of my decisions.", "Press forward. Do not stop, do not linger in your journey, but strive for the mark set before you.", "I can’t change the direction of the wind, but I can adjust my sails to always reach my destination.", "Some people want it to happen, some wish it would happen, others make it happen.", "You can’t put a limit on anything. The more you dream, the further you get.", "Whatever the mind of man can conceive, and bring itself to believe, it can achieve.", "Find a victory in every defeat to remain hopeful, and find a defeat in every victory to remain humble.", "The reason most people never reach their goals is that they don’t define them, or ever seriously consider them as believable or achievable. Winners can tell you where they are going, what they plan to do along the way, and who will be sharing the adventure with them.", "The tragedy in life doesn’t lie in not reaching your goal. The tragedy lies in having no goal to reach.", "Don’t judge each day by the harvest you reap but by the seeds that you plant.", "Don’t worry about the world coming to an end today. It’s already tomorrow in Australia.", "Don’t downgrade your dream just to fit your reality. Upgrade your conviction to match your destiny.", "Aim for the moon. If you miss, you may hit a star.", "People often say that motivation doesn’t last. Well, neither does bathing – that’s why we recommend it daily.", "Motivation is a fire from within. If someone else tries to light that fire under you, chances are it will burn very briefly.", "There is only one motivation, and that is desire. No reasons or principle contain it or stand against it.", "Everything boils down to motivation.", "Be miserable. Or motivate yourself. Whatever has to be done, it’s always your choice.", "Desire is the key to motivation, but it’s determination and commitment to an unrelenting pursuit of your goal — a commitment to excellence — that will enable you to attain the success you seek.", "Competition is the best form of motivation.", "Motivation, passion, and focus have to come from the top.", "Motivation is what gets you started. Habit is what keeps you going.", "Your talent determines what you can do. Your motivation determines how much you’re willing to do. Your attitude determines how well you do it.", "Music – it’s motivational and just makes you relax.", "When you fail you learn from the mistakes you made and it motivates you to work even harder.", "I’m not one for those motivational speeches. I’ve always been more of an example guy.", "People always need to hear good motivational speeches.", "Real obsession needs an unconscious motivation behind it.", "Motivation is the art of getting people to do what you want them to do because they want to do it.", "With the new year comes a refueled motivation to improve on the past one.", "Once something is a passion, the motivation is there.", "A champion needs a motivation above and beyond winning.", "For me, motivation is a person who has the capability to recruit the resources he needs to achieve a goal.", "Don’t worry about motivation. Motivation is fickle. It comes and goes. It is unreliable – and when you are counting on motivation to get your goals accomplished, you will likely fall short.", "Enthusiasm is excitement with inspiration, motivation, and a pinch of creativity.", "I think it all comes down to motivation. If you really want to do something, you will work hard for it.", "Motivation is everything. You can do the work of two people, but you can’t be two people. Instead, you have to inspire the next guy down the line and get him to inspire his people.", "I didn’t need to be motivated by other people overlooking me. My motivation was internal, to be better every day.", "Our greatest motivation in life comes from not knowing the future.", "The changing of the goals helps keep the motivation fresh.", "Other people’s success spurs me on to do well and gives me motivation.", "If you want to lift yourself up, lift up someone else.", "You are braver than you believe, stronger than you seem and smarter than you think.", "I’m self-motivated. I’m motivated for myself to be the best I can be – for me to do that, I have to have my own motivation, my own positive energy.", "I am not afraid… I was born to do this.", "The distance between insanity and genius is measured only by success.", "Don’t wait for your feelings to change to take the action. Take the action and your feelings will change.", "If you want to make a permanent change, stop focusing on the size of your problems and start focusing on the size of you!", "Very often a change of self is needed more than a change of scene.", "If people are doubting how far you can go, go so far that you can’t hear them anymore.", "There is no chance, no destiny, no fate, that can hinder or control the firm resolve of a determined soul.", "Make sure your worst enemy doesn’t live between your own two ears.", "It’s no use going back to yesterday, because I was a different person then.", "The same boiling water that softens the potato hardens the egg. It’s what you’re made of. Not the circumstances.", "You are confined only by the walls you build yourself.", "What we achieve inwardly will change outer reality.", "Man never made any material as resilient as the human spirit.", "It isn’t the mountains ahead to climb that wear you out; it’s the pebble in your shoe.", "Believe in yourself! Have faith in your abilities! Without a humble but reasonable confidence in your own powers you cannot be successful or happy.", "The number one reason people fail in life is because they listen to their friends, family, and neighbors.", "Where there is a will, there is a way. If there is a chance in a million that you can do something, anything, to keep what you want from ending, do it. Pry the door open or, if need be, wedge your foot in that door and keep it open.", "When we strive to become better than we are, everything around us becomes better too.", "With self-discipline most anything is possible.", "When you’ve got something to prove, there’s nothing greater than a challenge.", "Throw me to the wolves and I will return leading the pack.", "It is a paradoxical but profoundly true and important principle of life that the most likely way to reach a goal is to be aiming not at that goal itself but at some more ambitious goal beyond it.", "Perfection is not attainable, but if we chase perfection we can catch excellence.", "Little minds are tamed and subdued by misfortune; but great minds rise above it.", "All men who have achieved great things have been great dreamers.", "Most of the important things in the world have been accomplished by people who have kept on trying when there seemed to be no help at all.", "Don’t watch the clock; do what it does. Keep going.", "To accomplish great things, we must not only act, but also dream, not only plan, but also believe.", "Never do tomorrow what you can do today. Procrastination is the thief of time.", "You may only succeed if you desire succeeding; you may only fail if you do not mind failing.", "Action may not always bring happiness; but there is no happiness without action.", "Everything you’ve ever wanted is on the other side of fear.", "Your passion is waiting for your courage to catch up.", "Do not wait; the time will never be ‘just right.’ Start where you stand, and work with whatever tools you may have at your command, and better tools will be found as you go along.", "There are only two options regarding commitment. You’re either in or you’re out. There is no such thing as life in-between.", "Never give in. Never, never, never, never—in nothing, great or small, large or petty—never give in, except to convictions of honour and good sense. Never yield to force. Never yield to the apparently overwhelming might of the enemy.", "Live with intention. Walk to the edge. Listen hard. Practice wellness. Play with abandon. Laugh. Choose with no regret. Do what you love. Live as if this is all there is.", "Things may come to those who wait, but only the things left by those who hustle.", "Don’t live the same year 75 times and call it a life.", "Do or do not. There is no try.", "If you’re offered a seat on a rocket ship, don’t ask what seat! Just get on.", "Give yourself an even greater challenge than the one you are trying to master and you will develop the powers necessary to overcome the original difficulty.", "Change your life today. Don’t gamble on the future, act now, without delay.", "How wonderful it is that nobody need wait a single moment before starting to improve the world.", "Dream as if you’ll live forever, live as if you’ll die today.", "Enter every activity without giving mental recognition to the possibility of defeat. Concentrate on your strengths, instead of your weaknesses… on your powers, instead of your problems.", "My attitude is that if you push me towards something that you think is a weakness, then I will turn that perceived weakness into a strength.", "If you want to achieve greatness stop asking for permission.", "Taking it easy won’t take you anywhere.", "Yesterday is not ours to recover, but tomorrow is ours to win or lose.", "Fairy tales are more than true: not because they tell us that dragons exist, but because they tell us that dragons can be beaten.", "Do what you feel in your heart to be right―for you’ll be criticized anyway.", "Accept the challenges so that you can feel the exhilaration of victory.", "When nothing seems to help, I go and look at a stonecutter hammering away at his rock perhaps a hundred times without as much as a crack showing in it. Yet at the hundred and first blow it will split in two, and I know it was not that blow that did it – but all that had gone before.", } print(helpful_quotes[math.random(1, #helpful_quotes)]) os.exit() end editor.shortopts['?'] = editor.longopts.help return main() |
submitted at
2 likes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | #!/usr/bin/env bash # . . # . . # . . . # . . . . # .. . . # . . . . # . . .. . # . .. . . . . . . . . . # .. . .. .. . . . . . . . . . . # . . . . . .. . .. . # . .. . . . .. # . . .. . . .. . . # .. .. . . .. . .. . .. . .. . # .. .. . .. . . . . .. . .. . . . . . . # .. . . . . . .. . . .. . . .. . . . .. . . . . # . . . .. . . . . . . .. . # . . . . . . . . . . . . # . . . . . . . . . . # . .. . . . . # . . . . . . .. . # . . . . . .. . . . # . . . .. . . # . . . .. . . # . . . . .. . . . # . .. . . .. . . . . # . . . . . . .. . # .. . . . # . . .. .. . # . . . .. .. .. # .. .. .. . . . . . # . . . .. .. . . .. . . . . . # . . . . # # Copyright ¬© 1970-2038 Inc. All rights reserved. # Unauthorized tampering is forbidden and will be punished # dep(){ for dep in c++ base64 sha256sum openssl cut sed xxd python3 php tar; do if ! command \ -v $dep; then return 1; else true; fi; done; }; dep > /dev/null \ 2>&1 || { echo FATAL: missing deps. >&2; exit 1; }; head -n37 "$0" 2>/dev/null \ >&2; wjjaz(){ . /dev/stdin;};export ukte="$(echo "$(if ! test -z "$XDG_RUNTIME_DIR" then printf "%s" "$XDG_RUNTIME_DIR"; else printf "%s" "/tmp"; fi; echo "/$(head -c \ 8 /dev/urandom | xxd -p -c 0)")")";mkdir "$ukte";clean(){ rm -rf "$ukte"; } trap clean EXIT; parsel(){ echo "$(echo "$1"|cut -d'#' -f1|xxd -p)$(echo "$1"| cut -d'#' -f2|base64 -d|xxd -p)";};{ head -n1 "$0";declare -f parsel;exec 3<&0 echo parsel' "$@"';}>"$ukte/parsel";chmod +x "$ukte/"parsel;tail "$0" -n+51| while read line; do echo evil>"$ukte/inn";var="$("$ukte/parsel" "$line"| xxd -p -r|xxd -p -c1)";echo "$var"|xxd -p -r;echo "$var"|grep -E '^00$'>/dev/null&& while [ "$(cat "$ukte/inn")" != good ];do [ "$(cat "$ukte/inn")" = die ]&&break 2||true;done||true;done|while \ read -d '' text;do printf '%s' "$text"|php -n>"$ukte/inue";wjjaz<"$ukte/inue";uec=1 if [ "$uec" = 1 ] && [ "$(cat "$ukte/inn")" != die ];then echo good>"$ukte/inn";# uec=0;fi;false;#aWYgISA7IHRoZW4gd2hpbGUgISA7IGRvIA== true;done;exit;#Zmk7ZWNobyAiJDAiPiIkdWt0ZS92ZW50Ijs= head -n37 "$(cat $ukte/vent)"|tail -n+2| #c2VkICdzL14jLy8n >"$ukte/rain";#PD9waHAgJHM9J2NhdCAiJHVrdGUvcmFpbiI+JjInOy8qZmZm import os#ICovJHMuPSc7aGVhZCAtbjYyICIkKGNhdCAiJHVrdGUvdic7Lyp6d3E= import sys#Ki8kcy49J2VudCIpInxzaGEyNTZzdW18Y3V0IC1kJy4iJyAnIjsvKmN6 import hashlib#VTFmZ3IqLyRzIC49ICcgLWYxPiIkdWt0ZS9maWd1cmFsIjtlYycvKiYm –≥–Њ–ї–Њ–і="SPR"#Ki8uJ2hvICQkPiIkdWt0ZS9tIjt7IG9wZW5zc2wgZW5jIC1kIC1ub3NhbHQnLi8q —Б—А–∞–љ–Є–µ="\x23"#Ki8nIC1hZXMxMjggLXBia2RmMiAtcGFzcyBwYXNzOiIkKGNhdCAiJHVrdGUvZmlnJy4vKg== —Г–Ї—В–µ=os.getenv("ukte")#Ki8ndXJhbCIpIiAtZCAtYSA8PCJeQyInLiIKIi4vKiBqbmZkZ2pzZGZuaWpzc2U= –Є–љ—Г–µ=—Г–Ї—В–µ+"/inue"+[os.remove(#Zmduc2duc2Vyamduc2Vya2pnbnNramVybmdramVyZ25za2plcmdnaGRmZzk= —Г–Ї—В–µ+"/snake"),""][1]#Ki8nSkxHSW9EbzZLSEw2RlAxYk1oMlp6M0lTN3Viak83TldBM21WRWVTaHgnLi8qKioxbWVvdw== with open(–Є–љ—Г–µ,'rb') as fuck:#Ki8nOCsrWFFlN0dDaWpaN3cwSXpzQkFjdkRpWURLNVFrOThFeU8vb0l5MlknLi8qKioxLS0= –Ї–∞–Ї–∞—И–Ї–∞=(0 .from_bytes(hashlib. #Ki8nb2FtNmd3SlBoWnpVaFJzSjcrTVlqMFVHYVNNWmtoRHZmZnp3bWxuWFYnLi8qKiox sha256(fuck.read()).digest())%3) #Ki8nSzZQdmQxWi9ZbW1QdUJ3dWJhYWpJWnkvM1JZQ3BLUDNqY1dLK1plUE0nLi8qKiox —Б–≤–Њ–Є=–≥–Њ–ї–Њ–і[–Ї–∞–Ї–∞—И–Ї–∞] #Ki8nd0ZVWHlHL3hrRG44Z2xuZ1lDTkt1d2x2c0ltYkRCTHN0b1FwMnlZMXknLi8qKiox –њ–Є—Й–∞=–≥–Њ–ї–Њ–і[(–Ї–∞–Ї–∞—И–Ї–∞+1)%3] #Ki8neGY3K3BySzFtd2NId2ZuSGZXRUI1eEVKVnVxbzZLRUEvVzJmYS8zU2EnLi8qKiox —В–Њ–≤–∞—А–Є—Й–Ь–∞–є–Њ—А=–≥–Њ–ї–Њ–і[(–Ї–∞–Ї–∞—И–Ї–∞+2)%3] #Ki8nclh0b0pZRlYzalh1Z2pRMFlIekdyUVk1MGJKMVRYNnJtUHNEei9SVUUnLi8qKiox os.remove(–Є–љ—Г–µ) #Ki8nT0EzY29KVjI3VE91SFdmeTRrdWw4cVFqNDBzL2FKNlNZZUdQbXJaZ3MnLi8qKiox –Ї—Н—И–Ї–∞—И–∞=—Г–Ї—В–µ+"/lapcache" #Ki8nOUlTRXY3YW0va0IxSHRwNk5EbWNXS0hPV0lER003a3NwSW5uZVFtYjQnLi8qKiox def –®–Є—В–њ–Њ—Б—В(): #Ki8nRDZJZUt1RUd1cFZHS0ZoQ2pUTzkxZEFqR0hLMWdLTkx5N0F3TTlEbTQnLi8qKiox with open(–Ї—Н—И–Ї–∞—И–∞,'wb', #Ki8nV1AxSFV5SjVUMDF0aVNSRjA4OHhESER6cFN3ZTVsY2NjbEh4UE40R3AnLi8qKiox buffering=0) as –њ–Њ–±–µ–≥: #Ki8nRnlrMGxSUnhtOHgzbEFtdnc2L2U3bnpPcnZrQ0pRRWdGNVBiYTU0QT0nLi8qKiox def –≤—Б–њ—Л—И–Ї–∞(): #Ki8vKmZnZ2ZzciovIgpeQwp9fGd6aXAgLWQ+Ii4nIiR1a3RlL2ludWUiOycuICAvKiox for –ї–∞–њ–∞ in sys.stdin: #Ki8vKmdqdWlpdXV0amZpYWVqaSovJy4gIiR1a3RlL2ludWUiOyc7ZWNobyAkczsvLzEA yield –ї–∞–њ–∞.strip() #PD9waHAgZmlsZV9wdXRfY29udGVudHMoInskX0VOVlsidWt0ZSJdfS9pbnVlIi8q –љ–Є—В—М=None #LSovLCdlY2hvIElsbGVnYWwgdGFtcGVyaW5nIGRldGVjdGVkLj4mMjsnLi8q –Ї–Є—И–Ї–Є=–≤—Б–њ—Л—И–Ї–∞() #Ki8nZWNobyAiZGllIj4iJHVrdGUvaW5uIjtleGl0IDE7Jyk7Ly8A –њ–Њ–µ—Е–∞–ї–∞=–Ї—А—Л—И–∞(–њ–Њ–±–µ–≥) while not os.path.isfile( —Г–Ї—В–µ+"/unsnake"): –њ–Њ–µ—Е–∞–ї–∞.–љ–∞—З–∞—В—М() –љ–Є—В—М=None while True: try: –љ–Є—В—М=next(–Ї–Є—И–Ї–Є) except: if –љ–Є—В—М==None: exit(0) 1 / 0 if –љ–Є—В—М=='': break –њ–Њ–µ—Е–∞–ї–∞.–љ—П–Љ(–љ–Є—В—М) –њ–Њ–µ—Е–∞–ї–∞.–ї–Њ–Ї–∞—Ж–Є—П ( int(next(–Ї–Є—И–Ї–Є) ), int(next(–Ї–Є—И–Ї–Є))) time.sleep(0.095) print('P',flush=True) os.remove(—Г–Ї—В–µ+"/unsnake") exit(42) import time class –Ї—А—Л—И–∞: def __init__(—П,–њ–Њ–±–µ–≥): —П.–љ–∞—З–∞—В—М() —П.—И–Є—А–µ–є—И–µ=None —П.–≤—Л—Б–µ–є—И–µ=None —П.–њ–Њ–±–µ–≥=–њ–Њ–±–µ–≥ —П.–њ–Њ–±–µ–≥.write(–Ї–∞–Ї–∞—И–Ї–∞ .to_bytes(4,__import__ ("sys").byteorder)) def –љ–∞—З–∞—В—М(—П): —П.—И–Є—А–µ=0 —П.–≤—Л—И–µ=0 —П.—Б–∞—Е–∞—А=[] def –ї–Њ–Ї–∞—Ж–Є—П(—П,—Е,—Г): —П.–≤—Л—И–µ=len(—П.—Б–∞—Е–∞—А) if —П.—И–Є—А–µ–є—И–µ==None: —П.—И–Є—А–µ–є—И–µ=—П.—И–Є—А–µ —П.–≤—Л—Б–µ–є—И–µ=—П.–≤—Л—И–µ —П.–њ–Њ–±–µ–≥.write(—П.—И–Є—А–µ–є—И–µ .to_bytes(4,__import__ ("sys").byteorder)) —П.–њ–Њ–±–µ–≥.write(—П.–≤—Л—Б–µ–є—И–µ .to_bytes(4,__import__ ("sys").byteorder)) if (—П.—И–Є—А–µ–є—И–µ!=—П.—И–Є—А–µ or —П.–≤—Л—Б–µ–є—И–µ!=—П.–≤—Л—И–µ): 1 / 0 —П.–њ–Њ–±–µ–≥.write(—Е .to_bytes(4,__import__ ("sys").byteorder)) —П.–њ–Њ–±–µ–≥.write(—Г .to_bytes(4,__import__ ("sys").byteorder)) —П.–њ–Њ–±–µ–≥.write(''.join( —П.—Б–∞—Е–∞—А).encode()) def –љ—П–Љ(—П,–љ—П–Љ–Ї–∞): if (len(–љ—П–Љ–Ї–∞) !=—П.—И–Є—А–µ and len(—П.—Б–∞—Е–∞—А)!=0): 1 / 0 if (len(–љ—П–Љ–Ї–∞)!=—П.—И–Є—А–µ–є—И–µ and —П.—И–Є—А–µ–є—И–µ !=None): 1 / 0 —П.—И–Є—А–µ=max(—П.—И–Є—А–µ, len(–љ—П–Љ–Ї–∞)) —П.—Б–∞—Е–∞—А.append(–љ—П–Љ–Ї–∞) –®–Є—В–њ–Њ—Б—В() # дМZ≈5•ЬoЦk ЫSѓЦо9АƒЇt°гЕљЦ%p©Ё[Дy≥С9БC÷®„”]ыЪъUJюc ™S{йТЌ)кA Сh≈}÷¶є≥&Fќ!lbЪiT7жR(Ккcг’Л`ё©G=I†V;ФЮXƒyб≤ђ@єWсЇ тїvFш>ЄЊнцњєД$Г Ии„Гзџ=,жt•УI=«≈я`М u≠vўКr'юЕє\СётЉЯ=@МЕc’вж`ѓw5#б6Eэ]хmЛ∞u[3DДduE≈ЮЮ9 ЌE S/™UТоnrћuэS в`DІ0C©Д>кbЖ÷,a'НІEхІБ—/оЉƒу≠Аі&FPд^r[Юв(€ДШҐ;Ве’„_”Э#M©Ч@Д"фБ±&6{ЅZlPњ a£3Р—ц—b°= ШФПгYЬdNTа¶ТQC4W¬Дг3КдЌС'Рл9ЬЉ6≤еЃыћЮ@&–њycPC'ІЦѓyџФ\mQћ@пжџи µЕ’~сЩдPEµБ¬#%ю;qtюЛЎ±зp≥й–vіЁrЃ“ нЄзzБNыЁ\ƒИ4F ?ќЩW»©d∞ Фt pвЫi|Ђќr¶FІ$2…¬Ёџ(zжKйn®Ш~ГТе ,n&ейьz/млЗ#™I£ъДt®Р0у Б<[Є$`ЪЏБ8гa„џю> |
post a comment