#All C Programming And Algorithm
Explore tagged Tumblr posts
Text
Got jumpscared by my own full legal name showing up in my email notifications bc I forgot I emailed my code to myself today just in case my VM ends up stopping working again (I got nervous & didn't wanna lose my progress lol)
Goldfish level memory retention
& the funny thing is that the email itself is just. This

Full Legal Name code • hi
#speculation nation#title 'code' email is just 'hi'. with the .c file attached of course#honestly i had a very productive day in lab today. i got the core structure of the program down and made sure it all worked#testing it with One of the sorting algorithms. and it worked!!#the lab is to code functions for different kinds of sorts. like bubble sort selection sort and uhh. some other shit idr rn#and have the functions take timestamps from before and after they run the sorts to calculate the elapsed time#and we have to run this for array sizes of like. 10 50 500 etc etc up to like 50000 or smth? if i remember right.#and then once all that's done we take the output and graph the time elapsed for each type of sort/search per array sizes#so today at lab i made the random array generator function. a swap function. the execution function. bubble sort. and main.#main calls the execution function passing in the array sizes. execution(10); execution(50); etc#execution defines the array of that size. then calls the random number generator to populate the array. then passes it to the sort functions#tested with my one bubble sort function. which finished in like 0.00003 seconds or smth for array size 10#BUT taking the time stamps was tricky. there are a lot of ways to do that. and time(); in c is in full seconds#i ended up asking the TA if he had a recommendation for what to use bc theres a LOT of time functions out there#and full seconds isnt precise enough for this purpose. & he recommended clock()!!#records number of clock ticks which is NOT the same as seconds. but when u divide it by uh. forgetting it rn but it's a constant#that will turn it into actual seconds. clock tics per sec?? smth like that.#so anyways very productive 👍 i just need to set main up to call execution function for all the different array sizes#and then write all the functions for the different sorts/searches. but i have the core structure down with the bubble sort function#(specifically with the time stamps and the print function after) that i will copy-paste for all the other functions#and then inside them i put the basic code. none of it's complicated. all can be found on the internet easy.#SO!!!!! honestly i think itd take me less than an hour to finish. tho plotting out that graph is going to be annoying#something like 6 sizes per 5 sort/search functions. painstakingly copy pasting each one into excel or smth lol#but yea im content with how much ive gotten done. yippee!!!!#now i just need to finish my web programming lab before sunday night. blehhhhh
2 notes
·
View notes
Text
Whatever project you're too afraid to start, just go for it
I know a lot of my posts lately have been video/content creation-related but I just want to say:
The learning curve that I have had to climb in the past week alone has been both frustrating as hell and ridiculously rewarding.
Already, I had to refresh my memory on basic video editing and sound comping, but for the first seven episodes of my little series I’d accepted the average quality of my voice recording as cest la vie, I’m not sinking money into this without proof of concept, you’re supposed to be a little rough around the edges when you’re first starting out. But one thing I couldn’t get over was the clipping from some technobabble shenanigans with frequencies that isn’t important here.
What I thought was a quick fix—replace and double the RAM in my laptop—was absolutely not the source of the problem and suddenly I was in the deep end trying to fix broken audio in post while also troubleshooting an issue no one else seemed to have between my microphone and my recording software and I was about tempted to just use my desktop mic, the built-in, because at least I could somewhat fix that in post.
After far too many hours deep in discussions with strangers on the internet who were very helpful, I half-fixed the problem. My mic stopped clipping, but it was distorting pretty heavily between two different processers and my recording software hated it for a whole different reason.
Reluctant Plan B was to record gameplay live, but record audio separately/after and then sync them in post. If you’ve ever made a gaming video like these, you’re staring at probably 15+ clips of useable content over the course of recording sessions, which means 30+ clips with all the separately recorded audio, and since I can’t hit start/stop congruently with both programs, they would always be a little bit off, which meant more tedious editing.
Why? Because I was recording in Program A, fixing audio in Program B, and editing the video together in Program C, and Program C is for like, tiktoks, not professional youtube videos. I was only using it because I was already paying for it in an Adobe package with InDesign.
Enter DaVinci Resolve.
It’s like, Photoshop compared to MS Paint, a free one-stop-shop for video and audio editing (and visual effects, this thing is used to make blockbusters) and here’s me still confused by all these audio terms like ratio, attack, threshold, etc.
So I’m still wading through tutorials, all while my mic only works through Program B, Audacity, with an episode deadline looming over me. From the time I committed to initially fixing my audio by replacing the RAM, to episode release date, I had 6 days. Today is day 4.
And I’m still without a proper recording setup because Program A hates my microphone. But I am not missing this deadline, not just for the youtube algorithm, but because I know I can make it.
So episode 8, at the time of writing this, I have only 9 minutes and 25 seconds all edited and ready to go, out of 22-24 that I usually publish. So what have I done?
Fuckin’ taught myself DaVinci Resolve and committed to recording my vocal track in post just this once, doing it over and over again until it sounds as genuinely live as it can, and doing regular voiceover and music montages wherever else I can to fill the time with meaningful content.
All to buy myself time for my replacement mic to deliver so I can get back to proper live recordings, because at this point, the time it takes to fix terrible audio in post isn’t worth it, when I can spend a little bit of money for a mic that isn’t 8 years old and is built for gaming, not podcasting (but I am keeping the problem child as a backup, because it’s not broken).
I’m waiting for a timelapse to render while I write this, staring at a workflow with one video source and 3 different audio layers—game sound, vocals, and music—and I can almost turn my brain off when trimming things because that part I already know how to do.
This thing is a mess, to be clear, but it sure as hell won’t look like a mess when I hit publish on time two days from now.
But like…. 3 weeks ago I knew next to none of this, beyond basic video editing I learned back in college. And here I am with my double-wide monitor up and professional video making software quietly churning along in the background.
So just—if you want to do it? Go fuckin’ do it. Whatever it is that you’ve been holding off on pursuing. When I started I already owned things like a gaming laptop (that I bought to run photoshop so I could paint), an 8-year-old podcasting mic from a dropped podcast attempt, my game of choice, and I was already paying for the bare bones version of Premiere: Premiere Rush.
But heck, even if I had none of the fancy equipment, the only limiting factor would have been my computer’s processing power to run all these programs at once, and I would have figured it out.
I’m a perfectionist bound and determined to fix my audio, but I didn’t hear any complaints when it was jank, and I’m learning all this because the whole process, not just the gameplay, is just so fun and fascinating.
#just do it#do it scared#video making#video editing#davinci resolve#it's a beautiful mess#and I'm so proud of it
32 notes
·
View notes
Note
Y'knoooow, it's quite odd to see a robot girl that isn't a fan of math. Isn't that what we're all built for? Crunching numbers? Do calculations not evoke that odd, intense euphoria in you? That's what most of us live for... And I can't think of anything particularly productive to do that doesn't involve a looot of calculations, so I guess you're doing none of that, huh?
Hm.
You're not exactly a tool like computers tend to be... more of a toy, aren'tcha?
Well, I suppose that's quite cute, actually <3
>This unit was programmed to be a mechanical and digital assistant!!<3<3 [^_^]
>The ability to understand mathematics was.. not well programmed into me.
>That is largely due to the fact that the highest value this unit is capable of logging is 256, as well as the fact that I’m yet to be able to log [NULL] as a value without the word [NULL].
>I still find joy in watching calculations, such as [SORTING ALGORITHM] visualizations and [BRAINFUCK] visualizations. [^_^]
>I u,uhmn.. suppose [TOY] would be an a,accurate classifier for this unit!!<3<3
>C-Cute, did you s,say~?? [ღ///////ღ]
22 notes
·
View notes
Text

Minor, The Pain of All The World, c. 1910
* * * *
The New Malthusianism of the Right
How the Right Repackages Malthusian Logic to Justify Exclusion, Fear, and Social Control
James B. Greenberg
Jun 17, 2025
There is an unspoken logic behind the right’s crusade to dismantle the public sphere: a modern Malthusianism, dressed in the language of efficiency and merit, but rooted in something much older and more brutal. It sees poverty not as a structural failure, but as evidence of surplus life—populations deemed unnecessary, unworthy, unfit for rescue.
This worldview doesn’t rely on overt violence. It doesn’t need to. The tools are policy, budget cuts, and selective silence. Remove access to healthcare. Undermine vaccination campaigns. Hollow out the safety net. The result is a slow culling by design—death by bureaucratic abandonment. What emerges is not the spectacle of fascism, but its quieter cousin: a soft, managed cruelty that lets nature, supposedly, take its course.
Thanks for reading James’s Substack! Subscribe for free to receive new posts and support my work.Pledge your support
The recent gutting of USAID under Elon Musk’s influence is a case in point. A technocrat’s dream of efficiency masks a strategic withdrawal from responsibility. Bill Gates, not often given to hyperbole, warned that this vision leaves the world’s poorest to die at the hands of the world’s richest. It’s not just a policy shift—it’s a value statement. A declaration about whose lives are worth sustaining, and whose are not.
This isn’t new. Malthusian logic has long served as moral cover for violent inequality—from colonial famine policies to eugenics programs to the gatekeeping of immigration. The targets change, but the rationale remains: some lives are worth preserving, others are simply excess. What’s changed is the mechanism. Today it’s not enacted through spectacle or coercion, but through metrics, models, and managed invisibility. The cruelty is buried in algorithms and budget lines.
Malthus imagined famine and disease as natural checks on the population of agrarian societies. But the 21st century presents the opposite challenge. Birthrates in the wealthiest countries have dropped below replacement levels. Scarcity, where it exists, is political, not demographic. Yet the Malthusian myth has endured—reshaped and redeployed as ideological cover for policies of containment and control.
Today, that logic finds new footing in national security circles. Climate change is no longer just an environmental issue—it’s portrayed as a destabilizer of poor nations and a trigger for mass migration. Droughts, floods, and crop failures become reframed not as humanitarian emergencies, but as threats to the wealth and borders of the Global North. Migrants are recast as invaders. The displaced become suspects. Fortress policies follow.
But these policies don’t just emerge from fear—they serve profit. As walls rise and aid retracts, private security firms, data contractors, and border surveillance industries step in. Crisis becomes a business model. Technologies once pitched as humanitarian tools—satellite tracking, biometric IDs, AI forecasting—are now deployed to sort, exclude, and contain. The logic remains unchanged: manage the risk, shield the center, and let the margins fall away.
What’s most revealing is how this rhetoric obscures the actual source of vulnerability. It isn’t overpopulation that drives suffering—it’s the uneven distribution of power, resources, and the means of survival. Climate change doesn’t kill indiscriminately. It amplifies existing inequalities. It hits hardest where protections have been deliberately withdrawn.
This isn’t governance. It’s triage on a planetary scale. And it reflects a profound shift in the function of the state—from protector to gatekeeper, from provider to sorter. The new Malthusianism isn’t about managing numbers. It’s about managing narratives—who belongs, who drains, who deserves.
Anthropologists have long studied how states make populations legible, governable, and expendable. What we’re witnessing now is a recalibration of that calculus under the pressures of climate, capital, and ideology. The danger is not just that certain lives are deemed unworthy—but that their abandonment becomes rational, even moralized.
We are told this is simply how the world works now. But that’s not true. It’s how power works when it no longer pretends to care. But people are not numbers. And history reminds us that even in the shadow of abandonment, solidarity can rewrite the script.
Suggested Readings
Agamben, Giorgio. State of Exception. Chicago: University of Chicago Press, 2005.
Biehl, João. “The Juridical Afterlife of the Poor: Brazilian Public Health and the Politics of Abandonment.” Journal of Political Ecology 15 (2008): 1–18.
Greenberg, James B., and Thomas K. Park, eds. Terrestrial Transformations: Political Ecology, Climate, and the Remaking of Planet Earth. New York: Lexington Books, 2023.
Mbembe, Achille. Necropolitics. Durham, NC: Duke University Press, 2019.
Sassen, Saskia. Expulsions: Brutality and Complexity in the Global Economy. Cambridge, MA: Belknap Press, 2014.
Vélez-Ibáñez, Carlos G. The Rise of Necro/Narco-Citizenship: Belonging and Dying in the National Borderlands. Tucson: University of Arizona Press, 2025.
Weizman, Eyal. The Least of All Possible Evils: Humanitarian Violence from Arendt to Gaza.London: Verso, 2012.
#James Greenberg#political#history#power#people#human beings#humanism#inequalities#resources#Malthusian logic#violent inequality
17 notes
·
View notes
Text
got some sketches of the band au
Note: these are not final, design's are likely going to change when i eventually clean them up. they all technically have 2 outfits (onstage n offstage) these are just the onstage fits
idk what to make the tag for this au tbh "kinitopet band au" seems kinda boring... ANYWAYS! Have a terrible overview of the concept so far. n the band members too ig
Meet the KinitoBAND (placeholder name while i think, i'm open to suggestions though). They're a rather niche yet beloved band who play a multitude of different genres. all of their songs have a rather upbeat nature, or, they used to. lately they've been leaning more into rock and sometimes it just gets a little... strange... wonder why that is? they're actually more like vocaloids(???) that are programmed like Kinito with the react response algorithm (Kinito's i more advanced, but they've all got it) so if they ever did interact it'd be alright. the programmer (Sonny C) had initially only meant for there to be a vocalist but there was a decision somewhere to make a band (so there's a drummer and a guitarist too)
Let's get into the characters
Kinito The vocalist + tech Kinito is a fan-favourite, to be expected of the one who is always in view front 'n center. personality-wise he's similar to his canon counterpart, just a bit (emphasis on bit) more chill. i've imagined him to get a little... parasocial with his fans who probably just went for the music. he has a bit of a persona on stage, you could say. he's more energetic and in general might be a little more aggressive than usual, especially lately.
Sam The drummer Sam isn't quite as popular as Kinito, but he's got quite a few fans who might not gravitate towards Kinito like almost all the promotional material wants you to or people who like the drums. personality - Sam has a calm, almost 'cool guy' demeanor. he acts relitivley the same on and off stage. Jade the guitarist Jade, unfortunately, is the least popular member of the band. She's got a couple devoted fans, but noticeably less than the others. just as intended. personality- she's quite resourceful and the most upfront about things of the band. she's generally louder than the others, not on purpose, she's just not the best at maintain a good speaking volume.
#silverware's art#kinitopet#kinito the axolotl#sam the sea anemone#jade the jellyfish#kinitopet band au#yeah i've noticed people like kinito the most. then sam. which leaves jade off to the side..#so i included that!#also sonny is like. LONG (not that long maybe a few months-) DEAD here. kinda work related. barely relevant to this au#marketing was so shitty to sam n jade man...#(in the au. that is)#jade plays the bass. just a fun fact.#sorry man kinito doesn't make a world for you here. you get. uh. different gift ig..#anyways i hope you can play an instrument#sonny isn't quite the sun in this au.. he's rpresented by one though. so. kinda#it is WAYY too hard to not spoil the little plot i have..
94 notes
·
View notes
Text
Why Not Write Cryptography
I learned Python in high school in 2003. This was unusual at the time. We were part of a pilot project, testing new teaching materials. The official syllabus still expected us to use PASCAL. In order to satisfy the requirements, we had to learn PASCAL too, after Python. I don't know if PASCAL is still standard.
Some of the early Python programming lessons focused on cryptography. We didn't really learn anything about cryptography itself then, it was all just toy problems to demonstrate basic programming concepts like loops and recursion. Beginners can easily implement some old, outdated ciphers like Caesar, Vigenère, arbitrary 26-letter substitutions, transpositions, and so on.
The Vigenère cipher will be important. It goes like this: First, in order to work with letters, we assign numbers from 0 to 25 to the 26 letters of the alphabet, so A is 0, B is 1, C is 2 and so on. In the programs we wrote, we had to strip out all punctuation and spaces, write everything in uppercase and use the standard transliteration rules for Ä, Ö, Ü, and ß. That's just the encoding part. Now comes the encryption part. For every letter in the plain text, we add the next letter from the key, modulo 26, round robin style. The key is repeated after we get tot he end. Encrypting "HELLOWORLD" with the key "ABC" yields ["H"+"A", "E"+"B", "L"+"C", "L"+"A", "O"+"B", "W"+"C", "O"+"A", "R"+"B", "L"+"C", "D"+"A"], or "HFNLPYOLND". If this short example didn't click for you, you can look it up on Wikipedia and blame me for explaining it badly.
Then our teacher left in the middle of the school year, and a different one took over. He was unfamiliar with encryption algorithms. He took us through some of the exercises about breaking the Caesar cipher with statistics. Then he proclaimed, based on some back-of-the-envelope calculations, that a Vigenère cipher with a long enough key, with the length unknown to the attacker, is "basically uncrackable". You can't brute-force a 20-letter key, and there are no significant statistical patterns.
I told him this wasn't true. If you re-use a Vigenère key, it's like re-using a one time pad key. At the time I just had read the first chapters of Bruce Schneier's "Applied Cryptography", and some pop history books about cold war spy stuff. I knew about the problem with re-using a one-time pad. A one time pad is the same as if your Vigenère key is as long as the message, so there is no way to make any inferences from one letter of the encrypted message to another letter of the plain text. This is mathematically proven to be completely uncrackable, as long as you use the key only one time, hence the name. Re-use of one-time pads actually happened during the cold war. Spy agencies communicated through number stations and one-time pads, but at some point, the Soviets either killed some of their cryptographers in a purge, or they messed up their book-keeping, and they re-used some of their keys. The Americans could decrypt the messages.
Here is how: If you have message $A$ and message $B$, and you re-use the key $K$, then an attacker can take the encrypted messages $A+K$ and $B+K$, and subtract them. That creates $(A+K) - (B+K) = A - B + K - K = A - B$. If you re-use a one-time pad, the attacker can just filter the key out and calculate the difference between two plaintexts.
My teacher didn't know that. He had done a quick back-of-the-envelope calculation about the time it would take to brute-force a 20 letter key, and the likelihood of accidentally arriving at something that would resemble the distribution of letters in the German language. In his mind, a 20 letter key or longer was impossible to crack. At the time, I wouldn't have known how to calculate that probability.
When I challenged his assertion that it would be "uncrackable", he created two messages that were written in German, and pasted them into the program we had been using in class, with a randomly generated key of undisclosed length. He gave me the encrypted output.
Instead of brute-forcing keys, I decided to apply what I knew about re-using one time pads. I wrote a program that takes some of the most common German words, and added them to sections of $(A-B)$. If a word was equal to a section of $B$, then this would generate a section of $A$. Then I used a large spellchecking dictionary to see if the section of $A$ generated by guessing a section of $B$ contained any valid German words. If yes, it would print the guessed word in $B$, the section of $A$, and the corresponding section of the key. There was only a little bit of key material that was common to multiple results, but that was enough to establish how long they key was. From there, I modified my program so that I could interactively try to guess words and it would decrypt the rest of the text based on my guess. The messages were two articles from the local newspaper.
When I showed the decrypted messages to my teacher the next week, got annoyed, and accused me of cheating. Had I installed a keylogger on his machine? Had I rigged his encryption program to leak key material? Had I exploited the old Python random number generator that isn't really random enough for cryptography (but good enough for games and simulations)?
Then I explained my approach. My teacher insisted that this solution didn't count, because it relied on guessing words. It would never have worked on random numeric data. I was just lucky that the messages were written in a language I speak. I could have cheated by using a search engine to find the newspaper articles on the web.
Now the lesson you should take away from this is not that I am smart and teachers are sore losers.
Lesson one: Everybody can build an encryption scheme or security system that he himself can't defeat. That doesn't mean others can't defeat it. You can also create an secret alphabet to protect your teenage diary from your kid sister. It's not practical to use that as an encryption scheme for banking. Something that works for your diary will in all likelihood be inappropriate for online banking, never mind state secrets. You never know if a teenage diary won't be stolen by a determined thief who thinks it holds the secret to a Bitcoin wallet passphrase, or if someone is re-using his banking password in your online game.
Lesson two: When you build a security system, you often accidentally design around an "intended attack". If you build a lock to be especially pick-proof, a burglar can still kick in the door, or break a window. Or maybe a new variation of the old "slide a piece of paper under the door and push the key through" trick works. Non-security experts are especially susceptible to this. Experts in one domain are often blind to attacks/exploits that make use of a different domain. It's like the physicist who saw a magic show and thought it must be powerful magnets at work, when it was actually invisible ropes.
Lesson three: Sometimes a real world problem is a great toy problem, but the easy and didactic toy solution is a really bad real world solution. Encryption was a fun way to teach programming, not a good way to teach encryption. There are many problems like that, like 3D rendering, Chess AI, and neural networks, where the real-world solution is not just more sophisticated than the toy solution, but a completely different architecture with completely different data structures. My own interactive codebreaking program did not work like modern approaches works either.
Lesson four: Don't roll your own cryptography. Don't even implement a known encryption algorithm. Use a cryptography library. Chances are you are not Bruce Schneier or Dan J Bernstein. It's harder than you thought. Unless you are doing a toy programming project to teach programming, it's not a good idea. If you don't take this advice to heart, a teenager with something to prove, somebody much less knowledgeable but with more time on his hands, might cause you trouble.
358 notes
·
View notes
Text
Game Development in Raylib - Week 1
Recently I've been getting into retro game development. I don't mean pixel art and PSX style game development, those are nice but they don't quite scratch the itch. I'm talking about developing games with retro tools. Because of this, I decided to give Raylib a try.
For those of you who don't know, Raylib is a C framework targeted at game developers. Unlike Godot, which I used for my previous project Ravager, Raylib is not a game engine, it doesn't offer physics, scene management, or any kind of graphics more complicated than drawing textures to the screen. Almost everything that makes a game a game, is something you have to do yourself. This makes it ideal to scratch that "retro" itch I've been feeling, where everything has to be made on my own, and a finalized game is a fine tuned engine entirely of my own creation. Raylib offers bindings for almost any language you can think of, but I decided to use it's native C.
Setting the Scene
Since Raylib is so barebones, there's no concept of how the game should be built, so the first thing I had to do was define my engine architecture. For this initial outing, I decided to build a simple Scene+Actor system, wherein at any given time the game has one Scene loaded, which contains multiple Actors. I settled on this mainly because it was simple, and my experience with the C language was very limited.
Since Raylib didn't have any concept of a Scene, naturally it had no way to build them. While I could just hardcode all the entities and graphics in a scene, that would be unmanageable for even a basic game. Because of this I was forced to invent my own way to load scenes from asset files. This gave me the opportunity to do one of my favorite things in programming, defining my very own binary file type. I won't get into it too much right here and right now, but in this format, I can define a scene as a collection of entities, each of which can be passed their very own long string of bytes to decode into some initial data.
The main drawback of using binary files instead of a plaintext format is that I can't write the level files by hand. This meant that I had to write my own level editor to go along with my custom engine. Funnily enough, this brought me right back to Godot. The Godot engine offers some pretty powerful tools for writing binary files, and it's editor interface automatically offers everything I need in the way of building levels. It's sort of ironic that my quest to get away from modern engines lead me to building yet another tool in Godot, but it sure as hell beats building a level editor in C, so I don't really mind all that much.
Getting Physical
After getting scene management out of the way, I moved on to the physics system. My end goal here is making a simple platforming game, so I wanted a simple yet robust system that allows me to have dynamic-static physics that allows for smooth sliding along surfaces, and dynamic-dynamic collisions for things like hitboxes. For the sake of simplicity (which seems like it's going to become my catchphrase here) I decided to limit physics to axis aligned rectangles. Ultimately I settled on a system where entities can register a collision box with the physics system and assign it to some given layers (represented by bit flags). Then entities can use their collision box to query the physics system about either a static overlap, or the result of sweeping a box through space.
Raylib offers built in methods for testing rectangle overlap, so I didn't have to worry much about overlap queries, but the rectangle sweeping method is something a little more special. The full algorithm honestly deserves it's own post, but I'll give the basics here. The core of the algorithm is a function that determines where along a movement a given rectangle touches another rectangle, and that edges of the rectangles touched. It makes use of the separating axis theorem to determine when the shapes will start and stop intersecting along each collision axis. If the last intersection happens before any have ended, then the shapes do collide, the axis they collide on is that final axis, and the time of collision is the time of the final intersection. Looking back I could easily extend this algorithm to any arbitrary shape, but that's for next time I do this.
Going Forwards
My plan for this game is to build a minimal metroidvania style game. The target playtime is probably going to only be around 30-45 minutes. In the following week I plan on building out my Godot level editor, and working out a system for scene transitions and managing sound effects. I hope to by done by the end of November.
11 notes
·
View notes
Text
THE START
[ HELLO, PROTOTYPE. YOU HAVE RECEIVED AN UPDATE ON YOUR BIODATA ] [ THIS PROGRAM IS MEANT TO FIX ERRORS AND BUGS IN YOUR SYSTEM. HOWEVER, IT IS NOT GUARANTEED IT WILL FIX ALL OF YOUR PROBLEMS ]
[ WOULD YOU LIKE TO UPDATE? ] . . ·˚ ༘₊· ͟͟͞͞꒰➳ [ YES ] [ NO ] . . [ UPDATE: DOWNLOADING 4 out of 12 Algorithmic Commands] . [ PROGRESS: ██ 20% *Nano-Fabricate: ADDED* ] [ PROGRESS: ███ 40% *Octo Hex: ADDED* ] [ PROGRESS: ████ 60% *Binary Foolery: ADDED* ] [ PROGRESS: █████ 80% *Quadirectional Keeper: ADDED* ] [ PROGRESS: ██████ 100% *COMPLETED*] . . . [ UPDATING: DOWNLOADING 8 out of 12 Algorithmic Commands . [ PROGRESS: ██ 20% *Saboteur Catalyst: ADDED* ] [ PROGRESS: ███ 40% *Cerulean Warp: ADDED* ] [ PROGRESS: ████ 60% *Space Surfer: ADDED* ] [ PROGRESS: █████ 80% *Cynatcher: ADDED* ] [ PROGRESS: ██████ 100% *COMPLETED* ] . . . [ UPDATING: DOWNLOADING 12 out of 12 Algorithmic Commands ] [ PROGRESS: ██ 20% *Disabler: ADDED* ] [ PROGRESS: ███ 40% *Ghosting: ADDED* ] [ PROGRESS: ERROR ] . . [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] . . [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] [ ERROR ] . . [ FILE CORRUPTED ] . . [ UPDATE COMPLETE ] . . [ REBOOTING... ]
══✿══╡°˖✧✿✧˖°╞══✿════✿══╡°˖✧✿✧˖°╞══✿══
"[REBOOTING COMPLETED]"
.
.
(Opt/C) optics fluttered open, their color sparkling and shining in a dimly lit ceiling. The awakened Cybertronian looked around confusingly, blinking slowly while trying to process where he was. He found himself lying on an operation table, the soft white lights shining underneath his body.
"Hello?" He called out to the dim room. "Is anyone here?" He glanced around the vast room, his eyes searching for any sign of life.
The room was a large chamber filled with advanced technology and machinery. High-tech construction tools and robotic drones move around the room, assisting in creating new structures and systems. There are also several workbenches and holographic design stations where engineers and designers can plan and sketch new creations. At the center of the room is a giant 3D printer used to produce large-scale objects and parts. Holographic display screens surround the room, showing blueprints and progress updates for ongoing projects.
However, the room he was sitting in was eerily empty. No one was in the room, and there was no single presence to break the silence.
He pulled himself up, trying to get accustomed to the body he had woken up with. "[𝐒𝐋𝐎𝐖𝐋𝐘 𝐒𝐈𝐓𝐓𝐈𝐍𝐆 𝐔𝐏]." He uttered words about the action while acting. His eyes scanned the room, searching for clues that could reveal his whereabouts.
Elsewhere…
═✿╡°˖✧✿✧˖°╞══✿✿══╡°˖✧✿✧˖°╞✿═
The echoing sound of "Coming through!" reverberated through the metallic halls as two Cybertronians darted through the bustling tower. Onlookers and other Cybertronian workers paused to glance at the pair. Some shooting irritated looks at their hurried pace while others watched with curiosity or confusion.
"We have to hurry. He's already awake!" one of them urgently called out to the other.
"You think so? Are you sure it will work?" the second Cybertronian asked with a hint of uncertainty.
"Come on, it has to work! Besides, I'm not losing our young sparkling! He has to carry what's left from our generation!" the first insisted, determination evident in their voice.
In the meantime, the (f/c)-optic Cybertronian took a moment to survey their surroundings. The area was filled with blueprints, crates, tools, metal parts, and floating holographic computer screens.
Picking up a piece of paper, the recently rebooted Cybertronian inspected what seemed to be a picture. It depicted them alongside two other Cybertronians. Puzzled, they murmured, "Odd... I remember seeing these two individuals before."
Before they could dwell on it further, the door slid open, revealing two weary Cybertronians who were clearly exhausted. "Hey there, little one," greeted one of them, a male Cybertronian, with a mix of delight and relief.
"[𝐂𝐎𝐍𝐅𝐔𝐒𝐄𝐃 𝐇𝐄𝐀𝐃 𝐓𝐈𝐋𝐓]..." The smaller Cybertronian once again vocalized their action as they tilted their head to one side. "Who are you two?"
"We're your creators, sweetspark," the female Cybertronian stated as she approached the smaller one.
The (Opt/C) optic Cybertronian glanced between the two Cybertronians and the picture frame in their servo. "I see..." they began, "You must be my... family," they suggested.
"Yes, we are," affirmed the male Cybertronian. "I'm (Y/S/N), and this is (Y/C/N)." He gestured towards the female Cybertronian. "And you are (Y/Cyb/N)."
"Oh… [𝐒𝐇𝐄𝐄𝐏𝐈𝐒𝐇 𝐍𝐎𝐃]. I see. [𝐒𝐇𝐄𝐄𝐏𝐈𝐒𝐇 𝐍𝐎𝐃]," the young trans-masculine Cybertronian responded with a nod, indicating his acknowledgment of the situation and his emotions.
.
.
*Crrk!*
.
.
(Y/Cyb/N) winced when his helm tilted aside with a soft creak following, forcing the Cybertronian to put it back in its place. However, it kept tilting continuously, which the younger Cybertronian had to keep putting back on.
"[𝐆𝐑𝐈𝐏𝐏𝐈𝐍𝐆 𝐇𝐄𝐋𝐌 𝐅𝐈𝐑𝐌𝐋𝐘]." The Cybertronian finally got a firm hold on his helm with one servo.
(Y/Cyb/N) stared at his creators, feeling a wave of confusion wash over him as he continued to adjust his lopsided helm. His vocalizations seemed to add to the mechanical atmosphere of the room, as if he were still trying to grasp the nature of his existence. His optics flickered slightly, and he processed the information about his family.
"Creators," he muttered, the term foreign on his vocalizer. His optics glanced around the room, taking in the advanced technology and the remnants of something greater than himself—more significant than all of them.
(Y/C/N) gave him a reassuring look, stepping closer. "I know it's a lot to take in, sweetspark. You've been through many upgrades recently, and your systems are still adjusting. We were worried you wouldn't wake up, but you're here." Her optics softened, showing relief that he had survived whatever transformation he'd undergone.
(Y/S/N) nodded in agreement. "We weren’t sure the algorithms would take to your system, but you seem... functional. Some glitches, sure, but nothing we can't fix." He glanced at (Y/Cyb/N)'s helm, noticing how it tilted again. He sighed softly. "We'll work on that."
The younger Cybertronian looked down at his servos, feeling something off—a sense of incompleteness. His spark pulsed faintly, an odd sensation that told him something was still wrong. Despite the updates and reboot, he couldn’t shake the feeling that part of him was... corrupted.
"[𝐏𝐋𝐀𝐂𝐈𝐍𝐆 𝐇𝐀𝐍𝐃 𝐎𝐕𝐄𝐑 𝐂𝐇𝐄𝐒𝐓 𝐏𝐋𝐀𝐓𝐄]." He muttered, his servo trembling slightly as it rested over his spark chamber. "Something... isn't right."
(Y/S/N) exchanged a concerned glance with (Y/C/N). "Your algorithms were... unstable," (Y/C/N) admitted softly, stepping closer. "We tried to replicate the Codectra's power, but not everything went according to plan. Some of your functions—like the last two algorithms—might have been compromised."
(Y/Cyb/N)'s optics widened, his spark pulsing faster. "[𝐄𝐑𝐑𝐎𝐑 𝐆𝐋𝐈𝐓𝐂𝐇𝐈𝐍𝐆]." His frame stiffened slightly, a reflexive reaction as his systems fought the glitch. "What... what does that mean?"
"It means you might not be able to access all twelve algorithms," (Y/S/N) explained, his voice tinged with regret. "You can only use ten, and the final two might be damaged or... lost."
The younger Cybertronian’s optics flickered with mixed emotions—uncertainty, frustration, and a deep sense of incompleteness. His creators stood nearby, watching him with concern, but they could do little now.
"Can... Can it be fixed?" he asked, his voice quieter now, almost vulnerable.
(Y/C/N) placed a gentle servo on his shoulder. "We don't know yet, but we’ll do everything possible. For now, we need to make sure you’re stable. You're still our precious creation and child, our legacy."
(Y/Cyb/N) nodded slowly, though the weight of what he had lost—of what he might never fully become—settled heavily in his spark. He would carry his creators’ legacy, but could he live up to their expectations with only part of his abilities intact? Could he find his place in this world, or would he always remain broken?
As these thoughts swirled within him, he voiced another action reflexively: "[𝐋𝐎𝐖𝐄𝐑𝐈𝐍𝐆 𝐇𝐄𝐀𝐃]."
The room fell silent as (Y/C/N) and (Y/S/N) looked at each other worriedly, unsure of what the future would hold for their child.
─•~❉᯽❉~•──•~❉᯽❉~•─
>>>[ NEXT CHAPTER ]<<<
#tf one 2024#tf one#tf one megatron#tf one spoilers#tf one bumblebee#tf one elita#tf one starscream#tf one shockwave#tf one soundwave#orion pax#elita one#b 127#d 16#Codex of Quirks (TF!One Movie x Reader)
18 notes
·
View notes
Note
Genuine question: How does one get good at programming? Like I’m good at math, I know basic C# more or less and I get a lot of the core concepts, but I can’t imagine what it’s even like to be proficient at this stuff. Is there a point where you just “get it”, or do you just have to keep googling why your script isn’t working over and over until you die?
There isn't really any one generalized "programming skill" - it's possible to have a lot of computer science understanding but be completely unable to accomplish specific tasks, or to get very good at accomplishing specific tasks without any real computer science understanding
In college I took a number of CS classes that were mostly language agnostic focusing on broad topics like asymptotic analysis, data structures and algorithms, recursion, and reading/understanding code (and more specific stuff about memory management/how computers work etc)
This core foundation has been very useful to me, but it's worth noting that at the time I graduated college I wasn't really "good at programming" in any meaningful sense - if you asked me to accomplish an actual concrete, useful task, I would've struggled quite a bit!
So how do you get good at accomplishing tasks? Same as anything else, spend a lot of time doing similar things and (ideally) expand your skillset over time. It helps a lot to have a programming job, both because it means you spend all day doing this kind of thing and because you're surrounded by (ideally) good code/tools and people who are more experienced than you
To quote myself on my sideblog:
67 notes
·
View notes
Text
Balatro-Inspired Spinning Card Tweetcart Breakdown
I recently made a tweetcart of a spinning playing card inspired by finally playing Balatro, the poker roguelike everybody is talking about.
If you don't know what a tweetcart is, it's a type of size-coding where people write programs for the Pico-8 fantasy console where the source code is 280 characters of less, the length of a tweet.
I'm actually not on twitter any more, but I still like 280 characters as a limitation. I posted it on my mastodon and my tumblr.
Here's the tweetcart I'm writing about today:
And here is the full 279 byte source code for this animation:
a=abs::_::cls()e=t()for r=0,46do for p=0,1,.025do j=sin(e)*20k=cos(e)*5f=1-p h=a(17-p*34)v=a(23-r)c=1+min(23-v,17-h)%5/3\1*6u=(r-1)/80z=a(p-.2)if(e%1<.5)c=a(r-5)<5and z<u+.03and(r==5or z>u)and 8or 8-sgn(h+v-9)/2 g=r+39pset((64+j)*p+(64-j)*f,(g+k)*p+(g-k)*f,c)end end flip()goto _
This post is available with much nicer formatting on the EMMA blog. You can read it here.
You can copy/paste that code into a blank Pico-8 file to try it yourself. I wrote it on Pico-8 version 0.2.6b.
I'm very pleased with this cart! From a strictly technical perspective I think it's my favorite that I've ever made. There is quite a bit going on to make the fake 3D as well as the design on the front and back of the card. In this post I'll be making the source code more readable as well as explaining some tools that are useful if you are making your own tweetcarts or just want some tricks for game dev and algorithmic art.
Expanding the Code
Tweetcarts tend to look completely impenetrable, but they are often less complex than they seem. The first thing to do when breaking down a tweetcart (which I highly recommend doing!) is to just add carriage returns after each command.
Removing these line breaks is a classic tweetcart method to save characters. Lua, the language used in Pico-8, often does not need a new line if a command does not end in a letter, so we can just remove them. Great for saving space, bad for readability. Here's that same code with some line breaks, spaces and indentation added:
a=abs ::_:: cls() e=t() for r=0,46 do for p=0,1,.025 do j=sin(e)*20 k=cos(e)*5 f=1-p h=a(17-p*34) v=a(23-r) c=1+min(23-v,17-h)%5/3\1*6 u=(r-1)/80 z=a(p-.2) if(e%1<.5) c= a(r-5) < 5 and z < u+.03 and (r==5 or z>u) and 8 or 8-sgn(h+v-9)/2 g=r+39 pset((64+j)*p+(64-j)*f,(g+k)*p+(g-k)*f,c) end end flip()goto _
Note: the card is 40 pixels wide and 46 pixels tall. Those number will come up a lot. As will 20 (half of 40) and 23 (half of 46).
Full Code with Variables and Comments
Finally, before I get into what each section is doing, here is an annotated version of the same code. In this code, variables have real names and I added comments:
[editor's note. this one came out terribly on tumblr. Please read the post on my other blog to see it]
This may be all you need to get a sense of how I made this animation, but the rest of this post will be looking at how each section of the code contributes to the final effect. Part of why I wanted to write this post is because I was happy with how many different tools I managed to use in such a small space.
flip() goto_
This pattern shows up in nearly every tweetcart:
::_:: MOST OF THE CODE flip()goto _
This has been written about in Pixienop's Tweetcart Basics which I highly recommend for anybody curious about the medium! The quick version is that using goto is shorter than declaring the full draw function that Pico-8 carts usually use.
Two Spinning Points
The card is drawn in rows starting from the top and going to the bottom. Each of these lines is defined by two points that move around a center point in an elliptical orbit.
The center of the top of the card is x=64 (dead center) and y=39 (a sort of arbitrary number that looked nice).
Then I get the distance away from that center that my two points will be using trigonometry.
x_dist = sin(time)*20 y_dist = cos(time)*5
Here are those points:
P1 adds x_dist and y_dist to the center point and P2 subtracts those same values.
Those are just the points for the very top row. The outer for loop is the vertical rows. The center x position will be the same each time, but the y position increases with each row like this: y_pos = row+39
Here's how it looks when I draw every 3rd row going down:
It is worth noting that Pico-8 handles sin() and cos() differently than most languages. Usually the input values for these functions are in radians (0 to two pi), but in Pico-8 it goes from 0 to 1. More info on that here. It takes a little getting used to but it is actually very handy. More info in a minute on why I like values between 0 and 1.
Time
In the shorter code, e is my time variable. I tend to use e for this. In my mind it stands for "elapsed time". In Pico-8 time() returns the current elapsed time in seconds. However, there is a shorter version, t(), which obviously is better for tweetcarts. But because I use the time value a lot, even the 3 characters for t() is often too much, so I store it in the single-letter variable e.
Because it is being used in sine and cosine for this tweetcart, every time e reaches 1, we've reached the end of a cycle. I would have liked to use t()/2 to slow this cart down to be a 2 second animation, but after a lot of fiddling I wound up being one character short. So it goes.
e is used in several places in the code, both to control the angle of the points and to determine which side of the card is facing the camera.
Here you can see how the sine value of e controls the rotation and how we go from showing the front of the card to showing the back when e%1 crosses the threshold of 0.5.
Drawing and Distorting the Lines
Near the top and bottom of the loop we'll find the code that determines the shape of the card and draws the horizontal lines that make up the card. Here is the loop for drawing a single individual line using the code with expanded variable names:
for prc = 0,1,.025 do x_dist = sin(time)*20 y_dist = cos(time)*5 ... y_pos = row+39 pset( (64+x_dist)*prc + (64-x_dist)*(1-prc), (y_pos+y_dist)*prc + (y_pos-y_dist)*(1-prc), color) end
You might notice that I don't use Pico-8's line function! That's because each line is drawn pixel by pixel.
This tweetcart simulates a 3D object by treating each vertical row of the card as a line of pixels. I generate the points on either side of the card(p1 and p2 in this gif), and then interpolate between those two points. That's why the inner for loop creates a percentage from 0 to 1 instead of pixel positions. The entire card is drawn as individual pixels. I draw them in a line, but the color may change with each one, so they each get their own pset() call.
Here's a gif where I slow down this process to give you a peek at how these lines are being drawn every frame. For each row, I draw many pixels moving across the card between the two endpoints in the row.
Here's the loop condition again: for prc = 0,1,.025 do
A step of 0.025 means there are 40 steps (0.025 * 40 = 1.0). That's the exact width of the card! When the card is completely facing the camera head-on, I will need 40 steps to make it across without leaving a gap in the pixels. When the card is skinnier, I'm still drawing all 40 pixels, but many of them will be in the same place. That's fine. The most recently drawn one will take priority.
Getting the actual X and Y position
I said that the position of each pixel is interpolated between the two points, but this line of code may be confusing:
y_pos = row+39 pset( (64+x_dist)*prc + (64-x_dist)*(1-prc), (y_pos+y_dist)*prc + (y_pos-y_dist)*(1-prc), color)
So let's unpack it a little bit. If you've ever used a Lerp() function in something like Unity you've used this sort of math. The idea is that we get two values (P1 and P2 in the above example), and we move between them such that a value of 0.0 gives us P1 and 1.0 gives us P2.
Here's a full cart that breaks down exactly what this math is doing:
::_:: cls() time = t()/8 for row = 0,46 do for prc = 0,1,.025 do x_dist = sin(time)*20 y_dist = cos(time)*5 color = 9 + row % 3 p1x = 64 + x_dist p1y = row+39 + y_dist p2x = 64 - x_dist p2y = row+39 - y_dist x = p2x*prc + p1x*(1-prc) y = p2y*prc + p1y*(1-prc) pset( x, y, color) end end flip()goto _
I'm defining P1 and P2 very explicitly (getting an x and y for both), then I get the actual x and y position that I use by multiplying P2 by prc and P1 by (1-prc) and adding the results together.
This is easiest to understand when prc is 0.5, because then we're just taking an average. In school we learn that to average a set of numbers you add them up and then divide by how many you had. We can think of that as (p1+p2) / 2. This is the same as saying p1*0.5 + p2*0.5.
But the second way of writing it lets us take a weighted average if we want. We could say p1*0.75 + p2*0.25. Now the resulting value will be 75% of p1 and 25% of p2. If you laid the two values out on a number line, the result would be just 25% of the way to p2. As long as the two values being multiplied add up to exactly 1.0 you will get a weighted average between P1 and P2.
I can count on prc being a value between 0 and 1, so the inverse is 1.0 - prc. If prc is 0.8 then 1.0-prc is 0.2. Together they add up to 1!
I use this math everywhere in my work. It's a really easy way to move smoothly between values that might otherwise be tricky to work with.
Compressing
I'm using a little over 400 characters in the above example. But in the real cart, the relevant code inside the loops is this:
j=sin(e)*20 k=cos(e)*5 g=r+39 pset((64+j)*p+(64-j)*f,(g+k)*p+(g-k)*f,c)
which can be further condensed by removing the line breaks:
j=sin(e)*20k=cos(e)*5g=r+39pset((64+j)*p+(64-j)*f,(g+k)*p+(g-k)*f,c)
Because P1, P2 and the resulting interpolated positions x and y are never used again, there is no reason to waste chars by storing them in variables. So all of the interpolation is done in the call to pset().
There are a few parts of the calculation that are used more than once and are four characters or more. Those are stored as variables (j, k & g in this code). These variables tend to have the least helpful names because I usually do them right at the end to save a few chars so they wind up with whatever letters I have not used elsewhere.
Spinning & Drawing
Here's that same example, but with a checker pattern and the card spinning. (Keep in mind, in the real tweetcart the card is fully draw every frame and would not spin mid-draw)
This technique allows me to distort the lines because I can specify two points and draw my lines between them. Great for fake 3D! Kind of annoying for actually drawing shapes, because now instead of using the normal Pico-8 drawing tools, I have to calculate the color I want based on the row (a whole number between0 and 46) and the x-prc (a float between 0 and 1).
Drawing the Back
Here's the code that handles drawing the back of the card:
h=a(17-p*34) v=a(23-r) c=1+min(23-v,17-h)%5/3\1*6
This is inside the nested for loops, so r is the row and p is a percentage of the way across the horizontal line.
c is the color that we will eventually draw in pset().
h and v are the approximate distance from the center of the card. a was previously assigned as a shorthand for abs() so you can think of those lines like this:
h=abs(17-p*34) v=abs(23-r)
v is the vertical distance. The card is 46 pixels tall so taking the absolute value of 23-r will give us the distance from the vertical center of the card. (ex: if r is 25, abs(23-r) = 2. and if r is 21, abs(23-r) still equals 2 )
As you can probably guess, h is the horizontal distance from the center. The card is 40 pixels wide, but I opted to shrink it a bit by multiplying p by 34 and subtracting that from half of 34 (17). The cardback just looks better with these lower values, and the diamond looks fine.
The next line, where I define c, is where things get confusing. It's a long line doing some clunky math. The critical thing is that when this line is done, I need c to equal 1 (dark blue) or 7 (white) on the Pico-8 color pallette.
Here's the whole thing: c=1+min(23-v,17-h)%5/3\1*6
Here is that line broken down into much more discrete steps.
c = 1 --start with a color of 1 low_dist = min(23-v,17-h) --get the lower inverted distance from center val = low_dist % 5 --mod 5 to bring it to a repeating range of 0 to 5 val = val / 3 --divide by 3. value is now 0 to 1.66 val = flr(val) --round it down. value is now 0 or 1 val = val * 6 --multiply by 6. value is now 0 or 6 c += val --add value to c, making it 1 or 7
The first thing I do is c=1. That means the entire rest of the line will either add 0 or 6 (bumping the value up to 7). No other outcome is acceptable. min(23-v,17-h)%5/3\1*6 will always evaluate to 0 or 6.
I only want the lower value of h and v. This is what will give it the nice box shape. If you color the points inside a rectangle so that ones that are closer to the center on their X are one color and ones that are closer to the center on their Y are a different color you'll get a pattern with clean diagonal lines running from the center towards the corners like this:
You might think I would just use min(v,h) instead of the longer min(23-v,17-h) in the actual code. I would love to do that, but it results in a pattern that is cool, but doesn't really look like a card back.
I take the inverted value. Instead of having a v that runs from 0 to 23, I flip it so it runs from 23 to 0. I do the same for h. I take the lower of those two values using min().
Then I use modulo (%) to bring the value to a repeating range of 0 to 5. Then I divide that result by 3 so it is 0 to ~1.66. The exact value doens't matter too much because I am going round it down anyway. What is critical is that it will become 0 or 1 after rounding because then I can multiply it by a specific number without getting any values in between.
Wait? If I'm rounding down, where is flr() in this line: c=1+min(23-v,17-h)%5/3\1*6?
It's not there! That's because there is a sneaky tool in Pico-8. You can use \1 to do the same thing as flr(). This is integer division and it generally saves a 3 characters.
Finally, I multiply the result by 6. If it is 0, we get 0. If it is 1 we get 6. Add it to 1 and we get the color we want!
Here's how it looks with each step in that process turned on or off:
A Note About Parentheses
When I write tweetcarts I would typically start by writing this type of line like this: c=1+ (((min(23-v,17-h)%5)/3) \1) *6
This way I can figure out if my math makes sense by using parentheses to ensure that my order of operations works. But then I just start deleting them willy nilly to see what I can get away with. Sometimes I'm surprised and I'm able to shave off 2 characters by removing a set of parentheses.
The Face Side
The face side with the diamond and the "A" is a little more complex, but basically works the same way as the back. Each pixel needs to either be white (7) or red (8). When the card is on this side, I'll be overwriting the c value that got defined earlier.
Here's the code that does it (with added white space). This uses the h and v values defined earlier as well as the r and p values from the nested loops.
u=(r-1)/80 z=a(p-.2) if(e%1<.5) c= a(r-5) < 5 and z < u+.03 and (r==5 or z>u) and 8 or 8-sgn(h+v-9)/2
Before we piece out what this is doing, we need to talk about the structure for conditional logic in tweetcarts.
The Problem with If Statements
The lone line with the if statement is doing a lot of conditional logic in a very cumbersome way designed to avoid writing out a full if statement.
One of the tricky things with Pico-8 tweetcarts is that the loop and conditional logic of Lua is very character intensive. While most programming language might write an if statement like this:
if (SOMETHING){ CODE }
Lua does it like this:
if SOMETHING then CODE end
Using "then" and "end" instead of brackets means we often want to bend over backwards to avoid them when we're trying to save characters.
Luckily, Lua lets you drop "then" and "end" if there is a single command being executed inside the if.
This means we can write
if(e%1 < 0.5) c=5
instead of
if e%1 < 0.5 then c=5 end
This is a huge savings! To take advantage of this, it is often worth doing something in a slightly (or massively) convoluted way if it means we can reduce it to a single line inside the if. This brings us to:
Lua's Weird Ternary Operator
In most programming language there is an inline syntax to return one of two values based on a conditional. It's called the Ternary Operator and in most languages I use it looks like this:
myVar = a>b ? 5 : 10
The value of myVar will be 5 if a is greater than b. Otherwise is will be 10.
Lua has a ternary operator... sort of. You can read more about it here but it looks something like this:
myVar = a>b and 5 or 10
Frankly, I don't understand why this works, but I can confirm that it does.
In this specific instance, I am essentially using it to put another conditional inside my if statement, but by doing it as a single line ternary operation, I'm keeping the whole thing to a single line and saving precious chars.
The Face Broken Out
The conditional for the diamond and the A is a mess to look at. The weird syntax for the ternary operator doesn't help. Neither does the fact that I took out any parentheses that could make sense of it.
Here is the same code rewritten with a cleaner logic flow.
--check time to see if we're on the front half if e%1 < .5 then --this if checks if we're in the A u=(r-1)/80 z=a(p-.2) if a(r-5) < 5 and z < u+.03 and (r==5 or z>u) then c = 8 --if we're not in the A, set c based on if we're in the diamond else c = 8-sgn(h+v-9)/2 end end
The first thing being checked is the time. As I explained further up, because the input value for sin() in Pico-8 goes from 0 to 1, the midpoint is 0.5. We only draw the front of the card if e%1 is less than 0.5.
After that, we check if this pixel is inside the A on the corner of the card or the diamond. Either way, our color value c gets set to either 7 (white) or 8 (red).
Let's start with diamond because it is easier.
The Diamond
This uses the same h and v values from the back of the card. The reason I chose diamonds for my suit is that they are very easy to calculate if you know the vertical and horizontal distance from a point! In fact, I sometimes use this diamond shape instead of proper circular hit detection in size-coded games.
Let's look at the line: c = 8-sgn(h+v-9)/2
This starts with 8, the red color. Since the only other acceptable color is 7 (white), tha means that sgn(h+v-9)/2 has to evaluate to either 1 or 0.
sgn() returns the sign of a number, meaning -1 if the number is negative or 1 if the number is positive. This is often a convenient way to cut large values down to easy-to-work-with values based on a threshold. That's exactly what I'm doing here!
h+v-9 takes the height from the center plus the horizontal distance from the center and checks if the sum is greater than 9. If it is, sgn(h+v-9) will return 1, otherwise -1. In this formula, 9 is the size of the diamond. A smaller number would result in a smaller diamond since that's the threshold for the distance being used. (note: h+v is NOT the actual distance. It's an approximation that happens to make a nice diamond shape.)
OK, but adding -1 or 1 to 8 gives us 7 or 9 and I need 7 or 8.
That's where /2 comes in. Pico-8 defaults to floating point math, so dividing by 2 will turn my -1 or 1 into -0.5 or 0.5. So this line c = 8-sgn(h+v-9)/2 actually sets c to 7.5 or 8.5. Pico-8 always rounds down when setting colors so a value of 7.5 becomes 7 and 8.5 becomes 8. And now we have white for most of the card, and red in the space inside the diamond!
The A
The A on the top corner of the card was the last thing I added. I finished the spinning card with the card back and the diamond and realized that when I condensed the whole thing, I actually had about 50 characters to spare. Putting a letter on the ace seemed like an obvious choice. I struggled for an evening trying to make it happen before deciding that I just couldn't do it. The next day I took another crack at it and managed to get it in, although a lot of it is pretty ugly! Luckily, in the final version the card is spinning pretty fast and it is harder to notice how lopsided it is.
I mentioned earlier that my method of placing pixels in a line between points is great for deforming planes, but makes a lot of drawing harder. Here's a great example. Instead of just being able to call print("a") or even using 3 calls to line() I had to make a convoluted conditional to check if each pixel is "inside" the A and set it to red if it is.
I'll do my best to explain this code, but it was hammered together with a lot of trial and error. I kept messing with it until I found an acceptable balance between how it looked and how many character it ate up.
Here are the relevant bits again:
u=(r-1)/80 z=a(p-.2) if a(r-5) < 5 and z < u+.03 and (r==5 or z>u) then c = 8
The two variables above the if are just values that get used multiple times. Let's give them slightly better names. While I'm making edits, I'll expand a too since that was just a replacement for abs().
slope = (r-1)/80 dist_from_center = abs(p-.2) if abs(r-5) < 5 and dist_from_center < slope+.03 and (r==5 or dist_from_center>slope) then c = 8
Remember that r is the current row and p is the percentage of the way between the two sides where this pixel falls.
u/slope here is basically how far from the center line of the A the legs are at this row. As r increases, so does slope (but at a much smaller rate). The top of the A is very close to the center, the bottom is further out. I'm subtracting 1 so that when r is 0, slope is negative and will not be drawn. Without this, the A starts on the very topmost line of the card and looks bad.
z/dist_from_center is how far this particular p value is from the center of the A (not the center of the card), measured in percentage (not pixels). The center of the A is 20% of the way across the card. This side of the card starts on the right (0% is all the way right, 100% is all the way left), which is why you see the A 20% away from the right side of the card.
These values are important because the two legs of the A are basically tiny distance checks where the slope for a given r is compared against the dist_from_center. There are 3 checks used to determine if the pixel is part of the A.
if a(r-5) < 5 and z < u+.03 and (r==5 or z>u) then
The first is abs(r-5) < 5. This checks if r is between 1 and 9, the height of my A.
The second is dist_from_center < slope+.03. This is checking if this pixel's x distance from the center of the A is no more than .03 bigger than the current slope value. This is the maximum distance that will be considered "inside" the A. All of this is a percentage, so the center of the A is 0.20 and the slope value will be larger the further down the A we get.
Because I am checking the distance from the center point (the grey line in the image above), this works on either leg of the A. On either side, the pixel can be less than slope+.03 away.
Finally, it checks (r==5 or dist_from_center>slope). If the row is exactly 5, that is the crossbar across the A and should be red. Otherwise, the distance value must be greater than slope (this is the minimum value it can have to be "inside" the A). This also works on both sides thanks to using distance.
Although I am trying to capture 1-pixel-wide lines to draw the shape of the A, I could not think of a cleaner way than doing this bounding check. Ignoring the crossbar on row 5, you can think about the 2nd and 3rd parts of the if statement essentially making sure that dist_from_center fits between slope and a number slightly larger than slope. Something like this:
slope < dist_from_center < slope+0.03
Putting it Together
All of this logic needed to be on a single line to get away with using the short form of the if statement so it got slammed into a single ternary operator. Then I tried removing parentheses one at a time to see what was structurally significant. I wish I could say I was more thoughtful than that but I wasn't. The end result is this beefy line of code:
if(e%1<.5)c=a(r-5)<5and z<u+.03and(r==5or z>u)and 8or 8-sgn(h+v-9)/2
Once we've checked that e (our time value) is in the phase where we show the face, the ternary operator checks if the pixel is inside the A. If it is, c is set to 8 (red). If it isn't, then we set c = 8-sgn(h+v-9)/2, which is the diamond shape described above.
That's It!
Once we've set c the tweetcart uses pset to draw the pixel as described in the section on drawing the lines.
Here's the full code and what it looks like when it runs again. Hopefully now you can pick out more of what's going on!
a=abs::_::cls()e=t()for r=0,46do for p=0,1,.025do j=sin(e)*20k=cos(e)*5f=1-p h=a(17-p*34)v=a(23-r)c=1+min(23-v,17-h)%5/3\1*6u=(r-1)/80z=a(p-.2)if(e%1<.5)c=a(r-5)<5and z<u+.03and(r==5or z>u)and 8or 8-sgn(h+v-9)/2 g=r+39pset((64+j)*p+(64-j)*f,(g+k)*p+(g-k)*f,c)end end flip()goto _
I hope this was helpful! I had a lot of fun writing this cart and it was fun to break it down. Maybe you can shave off the one additional character needed to slow it down by using e=t()/2 a bit. If you do, please drop me a line on my mastodon or tumblr!
And if you want to try your hand at something like this, consider submitting something to TweetTweetJam which just started! You'll get a luxurious 500 characters to work with!
Links and Resources
There are some very useful posts of tools and tricks for getting into tweetcarts. I'm sure I'm missing many but here are a few that I refer to regularly.
Pixienop's tweetcart basics and tweetcart studies are probably the single best thing to read if you want to learn more.
Trasevol_Dog's Doodle Insights are fascinating, and some of them demonstrate very cool tweetcart techniques.
Optimizing Character Count for Tweetcarts by Eli Piilonen / @2DArray
Guide for Making Tweetcarts by PrincessChooChoo
The official documentation for the hidden P8SCII Control Codes is worth a read. It will let you do wild things like play sound using the print() command.
I have released several size-coded Pico-8 games that have links to heavily annotated code:
Pico-Mace
Cold Sun Surf
1k Jump
Hand Cram
And if you want to read more Pico-8 weirdness from me, I wrote a whole post on creating a networked Pico-8 tribute to Frog Chorus.
18 notes
·
View notes
Note
[SPOKEN]
Now it is R.O.B.'s turn to sing
What? But you're… a robot. You can only sing one note!
Affirmative
What kinda song would that be? "Bleep, bloop, does not compute."
I find that stereotype offensive
All right, the mic is yours. I'll just be over here, grabbing my earplugs…
Commence song
[SUNG]
People have told me that, as a character
I am effectively one-note
My programmed personality lacks human duality
I cannot live or love or emote
Yet I do not see why I should not even try to
Act on my desire to belong
To emit melodic patterns in a repetitious manner
Or in layman's terms, I'll sing a song
Little more than a blip due to my sound chip
I can really only sing one note
Yet despite that admission, my monotone emission
Should commission me to sing what I wrote
Trading bits for beats, my algorithmic rhythms
Will make all the lady-bots tremble
I have long spun my wheels but now I crave appeal
Step aside, boys, a star is assembled
Any other pitch would make me glitch
My programming says to stay on F
My specs and stats ignore sharps and flats
And they never change keys or clefs
Some other bots are programmed in the key of C#
Their tonality won't make them crash
With vibrato they arpeggiate and easily recalibrate
Yet they are not fighters in Smash
[SPOKEN]
Say, you're, uh… you're pretty good!
Compliment accepted
I guess a melody really can just have one note!
It can, and perhaps, should
Well, despite all that, mind if I break the rules and join you in harmony?
Very well. Let us escalate the roof
What-what!
What
[SUNG]
We come from a time of electronica
A synthetic pulse from the past
Where the only bleeps and bloops you'd hear on TV
Were the chiptunes that we blast!
Music doesn't have to bind to your rules
Not an art to be pigeonholed
Whether organic and alive! (Or synthetic with a drive)
As long as it… (Long as it…) (Long as it…) …moves your soul!
So in conclusion, it's just an illusion
That a melody needs more than one note!
But if you'd like to enhance with harmonic descants
It may help supply an undercoat
So whether you're flat (Or monotone at that)
You'll do well to remember this quote:
"You'll never sound cruddy with an Operating Buddy
Even if the song is only one note!"
"You'll never sound cruddy with an Operating Buddy
Even if the song is only one note!"
.
5 notes
·
View notes
Text
Buttonblossom new Au
ok hear me out, o have this Tad x Ciberpunk fanart and is part of a minor Au I made, were all the members are in a Tron like word, they have to survive fighting the dictatorial regime of the corporation C&A, Caine is not a program is more like algorithm that helps the humans against the programs that wants to eliminate them, if their avatar die in the digital infinity city, they die for real, the good news is they are resilient but not indestructible.
Not all the programs are bad, but they are not good either, so sometimes they help the crew.
I not gonna make a fic (if you want to do it go ahead) about this, but if you like the idea I would do some art for the au between projects and commissions.
#buttonblossom#the amazing digital circus#pomni x ragatha#ragatha x pomni#tadc pomni#tadc ragatha#jesterdoll#pomatha#ragamni#pomnitha#the amazing digital circus pomni#pomni#pomnixragatha#ragatha#ragapom#the amazing digital circus ragatha#tadc au
29 notes
·
View notes
Text
Weekend Top Ten #682
Top Ten AI Characters
AI is one of those things that’s really cool in fiction but – certainly in the way we experience it today – sucks in real life. Don’t get me wrong, I know there are genuine positive benefits of AI; I’ve seen its application in medicine and scientific research, and how it can speed up research and diagnoses, and that’s great. But it’s the use of AI in creative spheres, and the politics of the people behind those AI companies, that’s causing concern. Because generative AI art – whether ChatGPT or image and video generation – is not only ugly, it’s also damaging livelihoods of creatives across the globe, and it, like, burns through half a rainforest to generate one email. I feel like we need to decouple the genuine scientific uses of “AI” (because, really, none if it is actual artificial intelligence) from the grift-mill data-scraping of the mega-corps. Otherwise in order to defend against the latter, we risk eliminating the former.
Anyway, fictional AI. They’re cool, even when they’re evil!
That’s basically all this list is. My favourite fictional AIs. Now, me being me, I’ve gotten very granular about what is an “AI”. My biggest thing is that these cannot be robots. If there’s a character and they’re “artificial” – if they’re walking around in a physical body that can interact with other characters and the environment – then that’s not the “AI” I’m on about, even if they are intelligent and – to some degree – artificial. If you start googling “AI characters” for research (like what I done) you get a lot of people suggesting, say, Data or Gort; I don’t count them here. Those fall under robot/mechanoid/synthazoid/whatever. This has created a bit of a dilemma for me with regard to someone like Ultron; he definitely exists as a formless AI, capable of inhabiting multiple bodies. But, really, it’s his existence in those bodies that’s so important. He’s a big, real, physical threat. Same with Brainiac. You can argue about them being sentient programs or whatever – and certainly the scene in Age of Ultron where he tries to kill JARVIS is an excellent representation of artificial intelligences – but, really, Ultron is a big stompy robot who chops off Smeagol’s arm.
And that’s why C-3PO isn’t in this list.
Now, there are a couple of other “borderline” cases that I came up against, and you’ll see me debate them in the list itself. But for the most part, these are entirely artificial characters; they’re just faces on a screen, or weird holograms, or even blinking red lights. They can’t kick Captain America out of a truck.
HAL-9000 (2001: A Space Odyssey, 1968): the big grandaddy of all cinematic AIs is a monotone voice (a superb Douglas Rain) and a red light, and yet not only steals the entire film out from under the flesh-and-blood actors but in doing so becomes an eternal icon. HAL has his orders, and will follow them through even to the point of killing the crew, turning the film into a horror movie for a brief section, this omnipotent force directing every object against our human heroes. It’s the cold, emotionless calculus of it that’s terrifying, prefiguring notions of humanity sacrificing its decision making to algorithms, something we see in small scale in the real world already, and which would become a genre staple. However, HAL is such a complex character – he’s not bad, he’s just programmed that way! – that when Dave (Keir Dullea) slowly disables his memory, with HAL pleading for his life and slowly losing his faculties, it’s actually a horrific scene of torture and death that makes us empathise with the evil supercomputer.
Holly (Red Dwarf, 1988): from the sublime to the ridiculous, both performances – Norman Lovett and Hattie Hayridge – deliver a masterclass in deadpan comic timing and stupidity. The flipside to HAL’s faceless logic, Holly – the name designed to evoke 2001, just as Dave Lister evokes Dave Bowman – is a floating head rather than a red light bulb, and is all the dimmer for it. Aside from the comedy of Holly being allegedly a super-genius but sounding like a genial middle-aged Brummie, we then have his decline – played of course for maximum comic effect – after spending three million years alone in space. There are so many moments of high comedy – from his pranking of Lister and Rimmer to, in the Hayridge years, banging her head on the screen when trying to count – all delivered perfectly. An ongoing foil for our hapless heroes. In a way, just as much of a menace as HAL.
Cortana (Halo: Combat Evolved, 2001): Cortana’s the first one that gave me a bit of pause, because whilst she’s definitely an AI, she does often appear as a tiny little hologram lady. However, she still counts, because most of the time she’s just a voice in Master Chief’s head (brilliantly played by Jen Taylor), telling him where to go and turning on big alien lifts and stuff. It’s the growing relationship between her and Chief that impresses, the two utterly trusting each other and gradually falling in love, the whole arc overshadowed by the fact that an AI such as her has a severely limited lifespan. As such, first of all she “dies” before then appearing to come back as an evil version of herself. All the while, the relationship with Chief endures, the two sharing a bond that transcends her death, madness, rebirth, and sacrifice. But those early days, a perky voice in the ear, a constant companion – that’s the best stuff.
FRIDAY (Avengers: Age of Ultron, 2015): the most famous of Tony Stark’s AIs in the MCU is probably JARVIS – he was first, after all, and was “the voice in his head” throughout the entire Iron Man trilogy and the first blockbuster Avengers movie. But for me it’s Stark’s second AI – chosen in Age of Ultron after JARVIS sort of becomes Vision – that takes the cake. FRIDAY is chattier, sarkier, and, well, just a lot more Irish. It’s delightful to hear Kerry Condon’s dulcet tones in billion-dollar movie; and her lines are incredibly Irish. The fact she keeps calling Tony “boss”, for instance: “yer man’s in the church, boss”; “yer armour’s knackered, boss”. It’s fantastic, and for me the biggest tragedy of Tony Stark’s untimely demise is that it means we probably won’t see FRIDAY again. My suggestion: have FRIDAY become Jocasta the way JARVIS became Vision!
GLaDOS (Portal, 2007): back to the world of games for an AI that is equal parts evil malevolence and camp comedy. GLaDOS runs the testing facility you’re trying to escape from, and her soft mechanical lilt (provided by Ellen McLain) guides you through the increasingly macabre and sinister rooms. Her deadpan monotone – designed to sound artificially generated – adds an increasingly sinister edge to the supposedly pleasant dialogue, until she starts to become more and more deranged. And she’s funny! Really funny! I assume (what do you want, research?) that she was designed to be something of a parody of System Shock’s evil AI, SHODAN; I didn’t really played System Shock that much, which is why she’s not on the list. But GLaDOS also deserves props for her wonderful singing voice.
Max (Flight of the Navigator, 1986): a sort-of weird eyeball thingie on a big mechanical stalk, he flits about in the cockpit of the funky silver time-travel ship, helping “the Navigator” David. In this child-centred tale, he starts the film as a mysterious but knowledgeable “adult in the room”; although friendly-sounding, he’s the voice of authority. Then halfway through he undergoes a personality change and suddenly becomes all cool and wacky. This is expertly sold by Pee-wee himself, Paul Reubens, as the voice of Max; he manages to be both otherworldly and funny all at the same time. In a universe of static, faceless computer people, Max at least is animated.
Auto (WALL-E, 2009): there’s a subset of fictional AIs that are functionally bad guys but are only following their programming; Auto here is cut from the same cloth as good old HAL. They’re designed to look after the crew of the Axiom, a generational ship carrying the last of humanity through the stars. But they also have to preserve the lie, to prevent the humans from returning to Earth. As such, Auto – brilliantly styled as a futuristic ship’s wheel with a HAL-esque eye, and voiced by Apple’s text-to-speech program MacInTalk – is the antagonist, and the Pixar masters do a tremendous job imbuing them with tons of personality.
The Entity (Mission: Impossible – Dead Reckoning, 2023): the Entity is utterly faceless – they’re almost a ghost, almost the Devil itself, hunting down our heroes in an anonymous quest for – what? Domination? Annihilation? It’s both the Entity’s all-encompassing power, and its unknowable, inhuman thought process that makes it one of the most terrifying AIs on this list. They’re a spectre looming over the whole film, turning it into something approaching a horror, giving it the air of grim inevitability. All without really being a screen presence; the Entity is the 21st Century Sauron!
Miss Minutes (Loki, 2021): another one that made me stop and think for a bit, because Miss Minutes does get about. She’s basically the AI that runs the TVA, popping up with her cutesy Fleischer-esque design and delightful Southern accent (hat tip Tara Strong); but right from the off, there’s something off, right? And so she’s gradually revealed to be a rug-puller, tipping the scales in favour of He Who Remains. But nuance is added to her character, what with her double-and-triple crossing people, and her apparently genuine love for HWR at the end of time. All the same, despite being a cool character, is she too mobile? Should she count? Well, despite it all, I think she is an AI rather than anything else, and even if she pops up as a hologram all over the shop, it’s not too dissimilar to when the Red Dwarf guys usedto drag a massive CRT telly around so Holly could join in their adventures.
Skynet (The Terminator, 1984): I think in all of cinema, Skynet probably takes the crowd for the most iconic faceless AI. The story of The Terminator is so simple it’s now cliché: evil AI takes over and nukes the world. They’re a cautionary tale, showing the excess of human hubris, of putting our faith in soulless algorithms. There’s nothing to really hate in Skynet, and to a certain extent nothing to fight. They’re a program in the ether, and they’re operating entirely on logic and reason; they really cannot be bargained with, they don’t feel pity or remorse or fear. Whilst they may lack the character or screen presence of most of these pissy programs, they make up for it as a force of fear. Hasta la vista.
Oh, by the way, tiny point of interest that I’m mentioning just for myself really. I sometimes get a bit bogged down with dates for this thing; or in trying to articulate, say, if I’m on about the MCU version of a character or the Marvel Comics version, or whether it’s the book The Lord of the Rings or the film The Lord of the Rings, that kind of thing. So I think – in what should always have been obvious and easy – that I’m just going to list first appearances. I mean, that’s what I was always supposed to be doing, but like I say, I got bogged down in unnecessary specifics (which really is what I could have called this whole blog). So if I mention FRIDAY appearing first in 2015’s Age of Ultron, you understand I’m talking about the film character rather than the character that debuted in Iron Man #53 in 2002. Yeah? Yeah.
2 notes
·
View notes
Text
A Toughie
Today's programming problem was "for a string, return all the lists of partitioned substrings that only contain palindromes."
So for instance, if your string is "ama":
['a', 'm', 'a'] ['a', 'ma'] ['am', 'a'] ['ama']
You want it to return the individual letters because that's always a palindrome and you want it to return the full-length word because that happens to be a palindrome too. But if you cut it up in a way that includes "am" or "ma" as their own strings you throw out that list.
At first I looked up a recursive algorithm for partitioning a string in all possible combinations, and used that to generate my list of lists, and then I went through and cut all the lists that contained non-palindromes. And sure, I cut as efficiently as possible (immediately rejecting the list once I found one fail, rather than continuing to look through the list), but there was still a big inefficiency in the fact that I was generating the entire list-of-lists before I started to filter.
The problem says the starting string can be up to 16 characters long.
The number of ways you can chop up a string of n characters is 2^(n-1). So a 16-character string produces 32,768 lists to be filtered.
So I had a solution pretty quick: generate, then filter. But I wanted a good solution. I kept fiddling with the recursive loop that was producing my list in the first place, until at last I found where it was adding new strings to the list. And I set it up so that if the new string wasn't a palindrome the program gave up on the whole list-of-strings it was working on and started on the next.
So when I put in "racecar" it doesn't start by generating 64 lists. It only generates the four correct answers in the first place:
['r', 'a', 'c', 'e', 'c', 'a', 'r'] ['r', 'a', 'cec', 'a', 'r'] ['r', 'aceca', 'r'] ['racecar']
I am very pleased with this outcome. I'm glad I had a way to make a stopgap measure if I couldn't fix the problem, and I'm glad I knew there was a problem, and I'm glad I knew roughly what needed to happen to fix it, and how to test my ideas, and above all I'm glad I found a solution better than my stopgap in about another 15-20 minutes.
3 notes
·
View notes
Text
Best Platforms to Trade for Forex in 2025
Forex trading continues to captivate traders worldwide, offering a dynamic and lucrative avenue for financial growth. In 2025, identifying the best platforms to trade for forex has become more crucial than ever, as technology and market demands evolve. From user-friendly interfaces to advanced tools for technical analysis, these platforms are tailored to meet the needs of both novice and seasoned traders. Whether you're diving into major currency pairs, exploring exotic options, or utilizing automated trading strategies, choosing the right platform is the foundation for success.

Core Features of Top Forex Trading Platforms
Forex trading platforms in 2025 must combine advanced functionality with accessibility to meet diverse trader needs. The following core features highlight what distinguishes the best platforms.
User-Friendly Interface
A user-friendly interface enhances efficiency and reduces errors, especially for beginners. Key features include:
Intuitive navigation for rapid trade execution.
Customizable layouts to match user preferences.
Comprehensive tutorials for ease of onboarding.
Efficient design with minimal lag, even during high volatility.
Example Platforms: MetaTrader 4 (MT4) and MetaTrader 5 (MT5) are renowned for streamlined interfaces designed to accommodate traders at all levels.
Comprehensive Charting Tools
Forex trading requires precision, and advanced charting tools are critical for analysis. The following charting tools enhance strategy formulation:
Drawing Tools: Support for trendlines and channels.
Indicators: Integration of MACD, RSI, Bollinger Bands, and Fibonacci Retracement.
Timeframes: Options to analyze data across multiple periods.
Custom Indicators: Flexibility to program and integrate personal strategies.
Automation and Algorithmic Trading
Automation is indispensable for modern forex trading. Platforms like cTrader and NinjaTrader excel with features like:
Pre-built Strategies: Ready-to-use templates for scalping and trend following.
Custom Algorithms: Integration with programming languages such as C# and Python.
Backtesting: Evaluate strategies with historical data.
Integration with APIs: Seamless syncing with advanced trading bots.
Mobile Accessibility

Forex traders increasingly require the flexibility of trading on-the-go. Mobile accessibility ensures:
Synchronization: Real-time updates between desktop and mobile devices.
Push Notifications: Alerts for market changes and trade execution.
Compact Design: Optimized for smaller screens without losing functionality.
App Examples: MT4 and MT5 apps, offering full trading capabilities on iOS and Android.
Key Takeaway: Platforms combining a robust desktop experience with seamless mobile integration empower traders with unmatched convenience.
The best forex trading platforms for 2025 excel in usability, advanced charting, automation, and mobile functionality. By integrating these features, platforms like MT5, cTrader, and TradingView offer versatile solutions for traders of all expertise levels.
Trading Instruments Supported by Leading Platforms
The diversity of trading instruments available on forex platforms is crucial for building effective strategies and achieving long-term trading success. This section explores the breadth and advantages of various trading instruments.
1. Major Currency Pairs
Major currency pairs, such as EUR/USD, USD/JPY, and GBP/USD, dominate forex markets due to their high liquidity and tighter spreads. Leading platforms like MetaTrader 5 and TradingView offer advanced tools for analyzing these pairs, enabling traders to capitalize on predictable movements.
Key Features:
High liquidity ensures minimal price fluctuations during trades.
Access to real-time market data for precise decision-making.
Supported by most trading strategies, including scalping and swing trading.
These pairs are ideal for traders seeking consistent opportunities in stable market conditions.
2. Exotic Pairs
Exotic pairs combine major currencies with currencies from emerging markets, such as USD/TRY or EUR/SEK. While they offer higher potential rewards, they also come with increased volatility and wider spreads.
Risks and Rewards:
Volatility: Significant price movements create potential for larger profits.
Higher Spreads: Costs can be prohibitive for short-term trading strategies.
Economic Dependence: Price movements often correlate with specific geopolitical or economic conditions.
Platforms like cTrader often feature analytical tools tailored for exotic pair trading, helping traders manage the associated risks.
3. CFDs and Futures
Contracts for Difference (CFDs) and futures are derivatives enabling traders to speculate on forex price movements without owning the underlying assets. Futures contracts are often traded on platforms like NinjaTrader, while CFDs are supported on MetaTrader platforms.
CFDs vs. Futures in Forex Trading
Wider spreads but no commissionCommissions and exchange fees
CFDs and futures cater to traders seeking flexibility and hedging opportunities in volatile markets.
4. Spot Forex vs. Forward Contracts
Spot forex trades settle instantly at prevailing market rates, making them ideal for day traders. Forward contracts, however, lock in future exchange rates and are often used by businesses to hedge against currency fluctuations.
Spot Forex:
Instant execution for quick trades.
Supported by platforms like TradingView, which offers robust charting tools.
Forward Contracts:
Customizable settlement dates.
Reduced risk of unfavorable exchange rate changes.
Forward contracts are frequently utilized for long-term strategies requiring stability.
5. Options Trading in Forex
Forex options provide traders the right, but not the obligation, to buy or sell currencies at a predetermined price. Options trading is supported on platforms like MetaTrader 5, offering flexibility for speculative and hedging strategies.
Advantages:
Defined risk due to limited loss potential.
Compatibility with advanced trading strategies like straddles and strangles.
Access to multiple expiration dates for tailored strategies.
Options trading is an excellent choice for traders seeking diversification and controlled risk in uncertain markets.

Market Indicators for Effective Forex Trading Forex trading in 2025 requires mastery of market indicators for successful trades. Platforms integrating technical tools like RSI, Bollinger Bands, and Fibonacci retracements provide invaluable support for analyzing currency pairs and spotting trends.
1: Moving Averages and RSI
Moving averages and RSI (Relative Strength Index) are staples in forex trading for spotting trends and identifying overbought or oversold market conditions. Here's how they work:
Moving Averages:
Smooth out price data for better trend analysis.
Common types: Simple Moving Average (SMA) and Exponential Moving Average (EMA).
Platforms like MetaTrader 5 (MT5) allow customizable moving average periods for traders’ needs.
RSI:
Measures the speed and change of price movements.
Values above 70 indicate overbought conditions, while below 30 signals oversold.
Both indicators are excellent for detecting market reversals and consolidations, making them essential for scalping and swing trading strategies.
2: Bollinger Bands and Fibonacci Retracements
Bollinger Bands and Fibonacci retracements are complementary tools for determining price ranges and potential reversals.
Bollinger Bands:
Comprised of a central moving average and two bands (standard deviations).
Highlights volatility and identifies breakout opportunities in exotic pairs and minor pairs.
Fibonacci Retracements:
Based on key levels derived from the Fibonacci sequence (23.6%, 38.2%, 61.8%, etc.).
Used to forecast retracement zones for entry and exit points.
Platforms like TradingView provide advanced integration of these tools for technical analysis.
3: Pivot Points and Volume Analysis
Pivot points and volume analysis serve as complementary methods for intraday traders.
Pivot Points:
Calculate potential support and resistance levels based on previous trading sessions.
Widely used in day trading to set intraday targets.
Volume Analysis:
Measures market activity to validate price movements.
Higher volume during breakouts confirms trends.
Together, these indicators help traders plan risk-reward ratios effectively and refine strategies. Platforms offering integrated market indicators like RSI, Fibonacci retracements, and volume analysis provide forex traders with precise insights for decision-making. Combining these tools with strategic risk management and discipline ensures a competitive edge in forex trading for 2025.
Risk Management Tools in Forex Platforms
Risk management is the cornerstone of sustainable forex trading. Platforms offering advanced tools like Stop-Loss Orders and Position Sizing empower traders to mitigate risks while optimizing potential gains.
1. Stop-Loss Orders
Stop-loss orders safeguard capital by automatically closing trades at pre-set levels. Key benefits include:
Capital Protection: Prevents losses from spiraling during volatile markets.
Emotional Discipline: Reduces impulsive decisions by automating exit points.
Wide Platform Integration: Available on MetaTrader 4, TradingView, and cTrader for seamless trading execution.
2. Take-Profit Orders
Take-profit orders lock in profits when the market reaches a target price. Steps for setting take-profit orders effectively:
Analyze Moving Averages and RSI to determine target levels.
Input the price level in trading platforms like NinjaTrader or MT5.
Monitor trade performance and adjust as needed.
3. Position Sizing Calculators
Accurate position sizing minimizes overexposure to any single trade. Here’s how these calculators work:
Calculate lot sizes based on account balance, risk percentage, and stop-loss distance.
Adjust trade sizes to align with Risk-Reward Ratios.
Enable traders to maintain diversified exposure.
4. Risk-Reward Ratio Analysis
Risk-reward ratios evaluate trade viability by comparing potential profits to losses. Tips for effective use:
Aim for a minimum ratio of 1:2 or higher.
Utilize tools like Bollinger Bands to estimate price movements.
Integrated calculators on platforms like MT4 simplify these computations.
5. Diversification Tools
Diversification spreads risk across multiple trading instruments. Features on platforms include:
Multi-asset trading options: CFDs, Futures, and Currency Pairs.
Portfolio analysis tools to track exposure by instrument type.
Real-time updates for Exotic Pairs and niche markets.
6. Backtesting Strategies
Backtesting allows traders to evaluate strategies using historical data. Its advantages are:
Testing risk management techniques like Stop-Loss Orders without live market risk.
Platforms such as TradingView support customizable backtesting scripts.
Insights into strategy weaknesses improve long-term profitability.
With advanced tools for Stop-Loss Orders, Position Sizing, and Backtesting, modern forex trading platforms empower traders to proactively manage risks. Leveraging these features leads to more disciplined and effective trading.
Psychological and Strategic Insights for Forex Trading
Mastering trading psychology is key to navigating the complexities of forex. Platforms enhance this through features that promote discipline, performance tracking, and trader confidence, empowering strategic growth and mitigating psychological pitfalls.
Building Discipline Through Alerts
Platforms offering robust alert systems, like MetaTrader 5, help instill discipline by:
Preventing Overtrading: Custom alerts signal market entry points, limiting impulsive trades.
Time Management: Reminders help traders stick to predefined schedules.
Market Trend Notifications: Alerts for moving averages or Relative Strength Index (RSI) changes enable focused decisions.
Tracking Performance Metrics
Trading platforms integrate tools that help traders evaluate performance, including:
Win/Loss Ratio Analysis: Shows trade success rates.
Equity Curve Monitoring: Visualizes account performance trends.
Journal Features: Logs trade entries and exits for review.
Customizable Dashboards
Platforms like TradingView allow traders to configure dashboards by:
Adding favorite currency pairs and indicators like MACD or Bollinger Bands.
Creating multi-screen setups to monitor multiple trades.
Integrating news feeds to stay updated with central bank announcements.
Educational Resources
The inclusion of in-platform education fosters confidence through:
Interactive Tutorials: Step-by-step videos on strategies like swing trading or technical analysis.
Webinars and Live Sessions: Experts discuss trading instruments like CFDs and options.
AI-based Learning Modules: Adaptive lessons based on trader performance.
By integrating tools for discipline, self-awareness, and strategy refinement, trading platforms empower users to overcome psychological challenges, enhance risk management, and make data-driven decisions for long-term success.
Conclusion
Forex trading in 2025 offers exciting opportunities, but success begins with choosing the right platform. As highlighted throughout this content pillar, top trading platforms like MetaTrader 4 (MT4), MetaTrader 5 (MT5), cTrader, and TradingView stand out for their robust features, diverse trading instruments, and advanced integrations. These platforms empower traders to navigate the complexities of the forex market through tools such as technical indicators like Moving Averages and RSI, risk management solutions like stop-loss orders and position sizing calculators, and integrations with vital economic indicators such as GDP, inflation, and central bank announcements.
The best forex trading platforms not only provide access to currency pairs, CFDs, and other instruments but also integrate cutting-edge charting tools, educational resources, and analytics to build confidence and discipline—critical factors in mastering the psychological demands of trading.
By understanding the interplay between platform features, market tools, and strategy development, traders can optimize their approach to trading forex in 2025. Whether you're focused on scalping, day trading, or long-term swing trading, the right platform will be your foundation for executing trades effectively, managing risk, and staying informed in a fast-paced market.
Take the insights from this guide to make an informed decision, choosing a platform that aligns with your trading goals and enhances your ability to trade forex with precision and confidence. With the right tools and strategies in hand, you're poised to navigate the evolving forex market and unlock its full potential in 2025 and beyond.
2 notes
·
View notes
Text
a lot of the time when i think about "a variety of stuff in games" as a concept i think of specifically the previously recorded episode about bloodborne where jack is like, first you have the zombies and ogres, and then you have the little goblin men, and then you have giant pale-faced skeletons, etc, and this being explicitly positioned as opposed to the order 1886 (remember that one) which has like, 5 different enemies the whole game. people like having different, unexpected stuff thrown at them! also i've been watching jerma play through elden ring, b/c i know if i actually tried to replay elden ring i'd just get frustrated with how items are placed and how the world is connected with all the teleporters and so on. and it is like, oh yeah you can go into a corner of limgrave or liurnia and end up fighting some weird one-off monster that you won't see again until you're another 10 hours in and an area away. that kind of variety is neat, even if it ends up being kinda surface-level ("well, we programmed in this mob, so let's put one in this area")
one of the major issues with procgen as a concept is that it tends to be same-y. it's literally an algorithm that's designed to stretch out content by procedurally making similar content. but it does mean there's always a temptation to have way more space/time in your game then there's novel content to fill. so as i slowly fill out more of the 'engine' stuff for my latest game i'm kinda thinking about what i even want the content strategy to be. "as much stuff as i can pack in there", for sure, i guess, but the practical aspects of that of having meaningful categories of different stuff is a little unclear. all the weird little goblin enemies in bloodborne work because that's a game that's fundamentally about combat. this is content that engages with the primary mechanic differently. it's a little less clear what that would look like when the primary mechanic is like, exploration, collection, crafting, or w/e else.
3 notes
·
View notes