commit 6f47e63edea4e5bae246e7459cc7dc4a5bb03fed
parent 894eb5ee0608e6f151268144f7b8058f09b1aeb2
Author: Samdal <samdal@protonmail.com>
Date: Mon, 24 Feb 2025 21:40:26 +0100
Grammarly updates
Diffstat:
3 files changed, 171 insertions(+), 173 deletions(-)
diff --git a/_posts/2025-02-22-implications-of-OOP.md b/_posts/2025-02-22-implications-of-OOP.md
@@ -6,16 +6,15 @@ comments: true
tags: [writing, programming, C]
---
-Although the main premise of Object Oriented Programming may be simple, it forces certain design decisions which you otherwise wouldn't do.
-Structuring your program with an OOP mindset already restricts your thinking, but these extra implications make thinking outside the ~~object~~ box a lot harder.
+Although the primary premise of Object-Oriented Programming may be simple, it forces certain design decisions that you otherwise wouldn't make.
+Structuring your program with an OOP mindset already restricts your thinking, but these extra implications make thinking outside the ~~object~~ box much harder.
-Modern programming languages which "support" OOP **forces** you to use these restrictions all throughout your program.
+Modern programming languages that "support" OOP **force** you to use their restrictions throughout your program.
## What is OOP?
-OOP, in the modern sense, is a software strategy where *functions* and *data* are tied together.
-
-I don't have a problem with that, but if that was all that OOP did, then it would basically be an alternative syntax for doing this:
+In the everyday sense, OOP is a software strategy where *functions* and *data* are tied together.
+I don't have an issue with that. If that's all that OOP did, then it would merely be an alternative syntax for accomplishing this:
```
// not OOP (?)
struct my_struct {
@@ -47,21 +46,21 @@ my_class object = {1, 2, 3};
int res = object.calculate_sum();
```
-So this isn't the whole story, something being "OOP" implies other things, mainly **inheritance**.
+So this isn't the whole story. A program being "OOP" implies other things, mainly **inheritance**.
### What is inheritance?
-Inheritance is the ability for a class to extend one classes.
-This allows you to have some "generic base class", and then add new methods and members on top of it.
+Inheritance is the ability of a class to extend other classes.
+It allows you to add methods and members on top of a generic base class.
-It looks something like this
+It looks something like this.
```
// OOP
class my_base_class {
int a, b;
}
class my_class : my_base_class {
- // int a, b; are automatically included from the base class
+ // int a, b; are automatically imported from the base class
int c;
}
```
@@ -76,12 +75,12 @@ struct my_struct {
int c;
}
```
-The only difference here is that you have to explicitly type `object.base.a + object.base.b`, but you could add a language feature to make it identical.
+The difference is that you explicitly type `object.base.a + object.base.b`, but a language feature could make it identical.
The "non-OOP" way is so far superior:
- Control over memory layout
-- More explicit without being cumbersome
-- Allows composability (although some languages allow for "multiple-inheritance")
+- Explicit without being cumbersome
+- Allows composability (although some languages have "multiple-inheritance")
## So what's the catch
@@ -94,12 +93,12 @@ class my_base_class {
}
}
class my_class : my_base_class {
- string to_string() { // overrided function
+ string to_string() { // overridden function
return "my_class"
}
}
```
-The "magic" part about OOP is that when you *override* a method with an inherited class, when you cast the object to parent class, it retains the overridden functionality.
+The "magic" part about OOP is that casting an object to its parent class retains the overridden methods in the parent class.
```
void print_string(my_base_class obj) {
print(obj.to_string());
@@ -111,19 +110,19 @@ print_string(object); // prints "my_class"
```
Did you notice something?\
-In order for this functionality to work, we have to create `object` with a constructor, which is called through `new my_class();`.
+For this functionality to work, we created the `object` with a constructor called via `new my_class();`.
-So RAII, *Resource acquisition is initialisation*, that's the catch that makes OOP unique.
+So RAII, *Resource acquisition is initialization*, that's the catch that makes OOP unique.
-## Other ways which don't use RAII
+## Other ways that don't use RAII
### 1. Function pointers
-This will essentially manually do what the RAII and virtual methods does "automatically" for us.
+Function pointers manually do what the RAII and virtual methods do "automatically" for us.
```
typedef string to_string_function_pointer_t(void* self);
//////////////////////////////////////////////////
-// replace virtual function with function pointer defined above
+// Replace virtual function with function pointer defined above
struct my_base_struct {
to_string_function_pointer_t* to_string;
@@ -133,7 +132,7 @@ struct my_struct {
}
//////////////////////////////////////////////////
-// make the to_string functions
+// Make the to_string functions
string to_string_base_struct(void* self_void) {
my_base_struct* self = self_void;
@@ -160,7 +159,7 @@ my_struct* make_my_struct() {
return res;
}
```
-Usage then remains the same
+Usage then remains the same.
```
void print_string(my_base_struct base) {
print(base.to_string());
@@ -169,8 +168,8 @@ void print_string(my_base_struct base) {
my_struct object = make_my_struct();
print_string(object.base); // prints "my_class"
```
-So this goes to show how much work the OOP language is doing for us.
-C makes it clear how complicated of a solution this is.
+This example shows how much work the OOP language is doing for us.
+C makes it apparent how intricate of a solution this is.
### 2. Enums
```
enum struct_type {
@@ -203,28 +202,28 @@ print_string(object.base); // prints "my_class"
## Why I think the non-RAII ways are better
### 1. Function pointers
-As you saw, the function pointer strategy was pretty painful. However it's very explicit, in the cases where we geniuenly need a fully obfuscated API, this is perfcet.
+As you saw, the function pointer strategy was pretty painful. However, it's very explicit. In the cases where we genuinely need a fully obfuscated API, this is perfect.
-Because it's just functions, you can easily re-use them. The `to_string_my_struct()` function could easily compose with similar functions
+Functions are a fundamental concept and are easy to reuse. The `to_string_my_struct()` can be used by any other function, which many OOP languages will not let you do.
```
string to_string_my_struct(my_struct* obj) {
return to_string_my_base_struct(obj.base) + int_to_string(obj.c)
}
```
-which many OOP languages will not let you do.\
-Many child-structs can re-use and compose multiple different function pointers as they want. Something which is impossible with typical OOP syntax.
+\
+Many child structs can compose multiple different function pointers. Typical OOP syntax does not allow this.
-I personally only find function pointers useful with dynamically loaded code. Something an OOP mindset fails to make obvious.
+I personally only find function pointers useful with dynamically loaded code. The OOP mindset fails to make this obvious.
-Through ease composability and lack of required language features—I would argue that for dynamic cases, even without having gotten to the thick part of why RAII is bad, function pointers are superior.
+Through ease of composability and lack of required language features—I would argue that for dynamic cases, even without having gotten to the thick part of why RAII is bad, function pointers are superior.
### 2. Enums
-The enum example was roughly the same amount of code as the OOP example, maybe slightly more.
-Because the enum solution doesn't use any language features, this should drive home that the enum solution is a lot simpler.
+The enum example has roughly the same amount of code as the OOP example, maybe slightly more.
+The enum solution states its intent clearly, as it doesn't use advanced language features.
-If you looked closely, you might also have noticed that I never created a `my_struct` in the enum example. This is because we simply don't need multiple types anymore.
+You might have noticed I never created the `my_struct` in the enum example. This happened because we don't need multiple types anymore.
-The enums let us compose all our behaviour in a single type!
+The enums let us compose all our behavior in a single type!
```
struct entity {
entity_type type;
@@ -240,14 +239,13 @@ struct entity {
} common_enemy;
}
```
-If you have never done this before, it is **incredibly** useful. Now everything is one function, the different data members simply toggle the branches which are related.
-
-This also allows us to exploit all the benefits of the *non-OOP* strategies above, namely composing as opposed to "multiple-inheritance".
+If you have never done this before, it is **incredibly** useful. All functions collapse into one, and the different data members toggle the related branches.
-You have no idea how much more obvious the code becomes with this.
-All the struct members are clearly laid out. All the branches and composed behaviour get placed next to each-other.
+The code becomes a lot more uniform.
+All the struct members are directly visible, and all the branches and composed behavior get placed next to each other.
+In extreme cases, multiple files with tens of classes and functions become a single large function. Utilizing a centralized vs decentralized approach might be a personal preference, but performance and code sharing are objectively better with the latter approach.
-Additionally, if you're concerned about memory usage of having one large struct, you can use a "tagged union".
+Additionally, if you're concerned about the memory usage of having one large struct, you can use a "tagged union".
### 3. You can combine the two above
```
@@ -271,16 +269,15 @@ struct entity {
}
```
-If you wish to dynamically register entities in an "enum based" type, you can combine the function pointer without removing anything.
+You can incorporate the function pointer approach without removing anything in an enum-based type. Doing this lets static code remain straightforward while providing dynamic functionality.
## Finally: Problems with RAII
-OOP and RAII in general suffers from a problematic thinking pattern where each and every object needs to be constructed, destroyed and handled individually.
-This is almost *never* the case in the real world.
-Often when I talk to people who are tainted by the stains of OOP, they end up with a bunch of boiler plate and scattered types and functions. When in reality it could be much simpler.
+OOP and RAII bot suffer from a problematic thinking pattern where every object needs to be constructed, destroyed, and handled individually.
+In reality, this is almost *never* the case.
+When I talk to people tainted by the stains of OOP, they often end up with scattered types and functions and useless boilerplate.
-Not yet having learned how to chunk lifetimes together is the largest reasons why manual memory management seems so daunting to people.
-I almost never think about memory management, and when I do, it's a core part of the logic behind my program.
+Learning to chunk elements with the same lifetime together makes memory management a breeze.
<iframe style="width: 80%; aspect-ratio:16/9; height: auto; margin: 10px auto;"
frameborder="0" allowfullscreen
@@ -288,16 +285,15 @@ src="https://www.youtube.com/embed/xt1KNDmOYqA" title="HMH N+2">
</iframe>
Want more videos like the one above? [My list of software rants worth watching]({% post_url 2025-02-21-Software-Rants %}).
-Just because OOP languages want to support one single feature, namely poor automation of function pointers, they force your entire program to be written in a suboptimal way.
-Some languages like C++ allow a hybrid approach, due to it's history as an extension of C, but this has some problems of it's own.
-Most OOP languages are not like this.
+Due to OOP languages supporting this single feature—namely poor automation of function pointers—they force your entire program to be written in a sub-optimal way.
+Languages like C++ allow a hybrid approach due to its history as an extension of C. Most OOP languages are not like this.
-When I use a language with native OOP features, I find myself searching "How to do struct literal in X". Only to realise I have to write a constructor, despite not even using virtual functions.
+When I use a language with native OOP features, I find myself searching "How to do struct literal in X". Only to realize I have to write a constructor, despite not even using virtual functions.
### What about encapsulation
You might have noticed that I didn't mention encapsulation.
-That's because encapsulation is stupid, and it should never be used.
+That's because encapsulation is stupid, and abusing it is harmful.
-If you truly need encapsulation, you should use an opaque type.
+If you **need** encapsulation, you should use an opaque type.
-If you need to make sure only some individual data member is used correctly, then prefix the member name with `_` or `_INTERNAL_`.
+Ensuring individual members are only used internally can be done by prefixing the name with `_` or `_INTERNAL_`.
diff --git a/_posts/2025-02-22-making-generic-data-structures-in-C.md b/_posts/2025-02-22-making-generic-data-structures-in-C.md
@@ -7,15 +7,15 @@ comments: true
tags: [writing, programming, C]
---
-Static typing is amazing, it reduces a lot of bugs. However, having too many types hinders the uniformity of your code.
+Static typing is a great tool. It reduces a lot of bugs. However, having too many types hinders the uniformity of your code.
-Modern languages have tooling to automatically do generic types, C does not.
-I don't always agree that creating and using generics is a good idea, but I do use generics in C as well.
+Modern languages have tooling that does generic types automatically, but C does not.
+I don't always agree that creating and using generics is a good idea, but I use generics in C.
-## How it's normally done in C
+## How C programmers normally do it
-Usually C programmers just use `void*` and then wrap functions around the operations.
-This has many issues, mainly that it is hard to work with. It also has no type safety.
+Usually, C programmers use `void*` and wrap functions around the operations.
+Doing this creates friction, and it has no type safety.
> Note that in cases where you don't need type safety or easy top-level operations, `void*` may be an excellent tool.
@@ -45,7 +45,7 @@ void llist_stack_push(generic_linked_list** first_node, void *data, size_t data_
## The simple way
-Instead of using `void*`, just create macros that assume member names.
+Instead of plastering `void*` everywhere, create macros that assume member names.
```
#define llist_queue_push(f,l,n) ((f)==0) ? (f)=(l)=(n) : ((l)->next=(n), (l)=(n), (n)->next=0)
#define llist_queue_pop(f,l) ((f)==(l)) ? ((f)=(l)=0) : ((f)=(f)->next)
@@ -54,7 +54,7 @@ Instead of using `void*`, just create macros that assume member names.
#define llist_stack_pop(f) ((f)==0) ? 0 : ((f)=(f->next))
```
-This requires defining the structures yourself.
+Having generic *operations* encourages defining the structures yourself.
```
typedef struct llist_int llist_int;
struct llist_int {
@@ -63,7 +63,7 @@ struct llist_int {
}
```
-Then you just use it like this:
+Then you use it like below.
```
llist_int* list_first;
@@ -72,11 +72,11 @@ n->val = 10;
llist_stack_push(list_first, n);
```
-It's a lot simpler, it's type safe and it gives the user control of memory management.
+It's a lot simpler. It's type safe and gives the user control of memory management.
-Meanwhile, with the `void*` method, you have to do `*(int*)list_first->data` just to read the memory.
+Meanwhile, with the `void*` method, merely reading the list requires typing `*(int*)list_first->data`.
-Having more control over datatypes also makes it easier to compose larger structures.
+Retaining control over data types also makes it straightforward to compose large structures.
```
typedef struct tree_node tree_node;
struct tree_node {
@@ -91,11 +91,11 @@ struct tree_node {
int val;
}
```
-We can use this struct as is, we don't need all of the boiler plate that comes with a different solution.
+We can use this structure as is. We don't need the boilerplate that comes with a different solution.
## The "hide away" method
-You can also hide away your header information, and then provide the type in a nicer way to the user.
+You can also conceal the header information and provide the type in a friendlier way.
```
typedef struct {
int sz;
@@ -117,15 +117,14 @@ dyn_arr_push(my_arr, 20.0f);
assert(my_arr[1] == 20.0f);;
```
-I don't really use dynamic arrays anymore, and that's mostly where this technique is useful.
-This technique creates more obfuscated and harder to use code than if your types are exposed.
+I don't use dynamic arrays anymore, and that's mostly where this technique is helpful.
+This approach creates more obfuscated and harder-to-read code than exposing types.
## Going a bit crazy
-Although just the fact that using generic operations rather than types is the main takeaway from this post, I figiured I should show how you can take this to the extreme.
-So let's make a hash-table.
+Although using generic operations rather than types is the takeaway from this post, I figured I should demonstrate an extreme example. Let's make a hash table.
-To make it easier to use, we can provide macros that generate the correct structures.
+To ease use, we can provide macros that generate the correct structures.
```
#define htable_def_ex(_htable_entry_T) \
struct { \
@@ -133,10 +132,10 @@ To make it easier to use, we can provide macros that generate the correct struct
_htable_entry_T** table; \
}
-// if you don't care about having anonymous types, you can use this:
+// If you don't care about having anonymous types, you can use this:
#define htable_def(_T) htable_def_ex(struct {u64 hash; void* next; _T val;})
```
-Then we make our operations wrapped in generic macros like before. This time we make use of internal functions, and process the input and output of them.
+We wrap our operations in generic macros like before. This time, using internal functions and processing the input and output of them.
```
typedef struct {u64 hash; void* next;} null_htable_entry_t;
typedef htable_def_ex(null_htable_entry_t) _null_htable_t;
@@ -198,7 +197,7 @@ int_htable id_table = {
}
```
-If you wish to avoid using `typeof`, you can make another struct member which is used as the "return" value, like this:
+If you wish to avoid using `typeof`, you can make another struct member to use as the "return" value. Like this:
```
#define htable_def_ex(_htable_entry_T) \
struct { \
@@ -214,10 +213,10 @@ If you wish to avoid using `typeof`, you can make another struct member which is
```
## What you should remember
-The best generic data structure is no generic data structure. Nowadays I pretty much exclusively use linked lists. This is because they are flexible, pointer stable and thereby play nicely with Arenas. The hash-table we made also plays well with Arenas.
+The best generic data structure is no generic data structure. Nowadays, I almost exclusively use linked lists. They are flexible, pointer stable, and thereby play nicely with arenas. The hash table we made also plays well with Arenas.
-I very rarely find myself longing for a dynamic array, a hash-table or other more complicated data structures.
-In the cases where you actually would benefit from having a re-usable generic data structure, don't do it the `void*` way.
+I rarely long for a dynamic array, a hash table, or other more complicated data structures.
+In the cases where you actually would benefit from having a reusable generic data structure, don't do it the `void*` way.
Try doing the types raw and focus on making the operations "generic".
You will be surprised at how much it reduces friction and boilerplate.
@@ -225,4 +224,4 @@ You will be surprised at how much it reduces friction and boilerplate.
<br>
For the non-C people reading, you might have become thankful that your tooling does generics automatically.
-I think of it differently, one of the beauties of C is that complicated things are hard to do. Experiencing that hardship steers you away from those solutions, and directs you towards simplicity.
+I think of it differently. One of the beauties of C is that complicated things are hard to do. Experiencing that hardship steers you away and directs you toward simplicity.
diff --git a/_posts/2025-02-23-my-old-projects.md b/_posts/2025-02-23-my-old-projects.md
@@ -7,114 +7,118 @@ comments: true
tags: [writing, programming, electronics, C]
---
-I mostly developed as a programmer through personal projects, reading good code I've found and watching YouTube.
+## Preface
+
+I primarily developed as a programmer through personal projects, reading good code I've found, and watching YouTube.
When it comes to other people's code, the [Gunslinger graphics framework](https://github.com/MrFrenik/gunslinger) and later the [RAD Debugger project](https://github.com/EpicGamesExt/raddebugger) have taught me the most.
-As for videos, at first I actually watched YouTubers like [The Cherno](https://www.youtube.com/@TheCherno), [Bisqwit](https://www.youtube.com/@Bisqwit) and [javidx9](https://www.youtube.com/@javidx9).
+As for videos, at first, I watched YouTubers like [The Cherno](https://www.youtube.com/@TheCherno), [Bisqwit](https://www.youtube.com/@Bisqwit) and [javidx9](https://www.youtube.com/@javidx9).
I have also watched a lot of different electronics channels, but I won't be mentioning them here.
-Later i started watching the people you can see in [this post]({% post_url 2025-02-21-Software-Rants %}), but I don't spend much time watching programming YouTubers anymore.
+Later on, I started watching the people you can see in [this post]({% post_url 2025-02-21-Software-Rants %}), but I don't spend much time watching programming YouTubers anymore.
+
+# The projects (in order)
-It's harder to concisely say the projects I've done, so I have some of them listed here.
+It's hard to mention my completed projects concisely, but I have some of them listed here.
## Unreal Engine
I started my programming journey during the first summer break of secondary school. I used a [Udemy course](https://www.udemy.com/course/unrealcourse) to learn C++ for the Unreal engine.
-Initially I was really overwhelmed. I couldn't solve anything on my own, but I got a large stream of info. It set me up for further learning.
+Initially, it was overwhelming. I couldn't solve anything by myself.
+On the bright side, I got a large stream of information. It set me up for further learning.
I started getting bored after working through a good chunk of the course.
-This made me attempt making a game on my own. Instead of C++ I used Blueprint, but I still got stuck at rudimentary logic and math.
+I decided to attempt creating a game on my own. Instead of C++, I used Blueprint, but I still got stuck at rudimentary logic and math.
<a name="weeb-bot"> <a/>
## Weeb Bot
-As cringe as it may be, "[Weeb boot](https://github.com/Samdal/WeebBot)" was my first real independent project. It was a discord bot written in Golang.
+As cringe as it may be, "[Weeb boot](https://github.com/Samdal/WeebBot)" was my first successful independent project. It was a discord bot written in Golang.
-This project was made in 2018-2019 during secondary school (I was like 14-15 years old).
-I didn't really know anything about programming practices, but I could read examples and write if statements.
+I made the bot in 2018-2019 during secondary school (I was around 14-15 years old).
+I still didn't know much programming. I could only read examples and write if statements.
-The bot mostly provided storage retrieval, automated responses, string transformations and web scraping.\
-I later added the [Anilist GraphQL API](https://anilist.co/graphiql) to it.
+The bot mostly provided storage retrieval, automated responses, string transformations, and web scraping.\
+I later added the [Anilist GraphQL API](https://anilist.co/graphiql).

{: style="text-align: center;"}
## Drones
-I have been involved in making two drones so far.
+To date, I've been involved in making two drones.
-The first one was mostly made by my dad. He made the main structure using wood and a plastic box for the electronics housing.
-It was then fitted it with a commercial flight-controller and motors. It never flew that great when we tested it, which is why we decided to buy a ready-made kit for a drone frame.
+My dad mostly made the first one. He made the structure using wood and a plastic box to house the electronics.
+The drone had a commercial flight controller and motors. Sadly, it never flew that great when we tested it.
-This time I assembled and solder it together, I never got far enough to fly it or test it properly.
-Partially because the configuration tool for the new flight-controller was really hard to work with, and I was unsure if I had some broken connections.
-I didn't really make it in a repairable manner, so it was hard to check.
+The second time, my dad decided to buy a ready-made kit for a drone frame. I assembled and soldered it together. However, I never got far enough to fly and test it properly.
+Partially because the configuration tool for the new flight controller was hard to work with, and I was unsure if I had some broken connections.
+I didn't assemble it in a repairable manner, so it was hard to debug.
-## Snow-plower
+## Snow plower
-The snow-plower was a project I made during roughly the same time as [Weeb Bot](#weeb-bot), maybe slightly later.
-It was made with a raspberry PI running [ROS](https://www.ros.org/). The main navigation and mapping were done with a lidar.
+The snow plower is a project I made during roughly the same time as [Weeb Bot](#weeb-bot), maybe slightly later.
+It utilized a Raspberry PI running [ROS](https://www.ros.org/), and the navigation and mapping information came from a lidar.

{: style="text-align: center;"}
-It was then going to use it's sensor information to autonomously plow the snow, a bit like a robot vacuum.
+It would then navigate and plow the snow autonomously, like a robot vacuum.
-The snow-plower's hull was an old defective snow blower (it had tracks, so it looked cool).
-The plan was to fit it with electro motors to replace the gasoline engine that I removed.
+The snow plower's hull reused an old defective snow blower (it had tracks, so it looked cool).
+The plan was to fit it with electro motors to substitute the removed gasoline engine.
-The project never got further than very rudimentary mappings with the lidar and half-working simulations.
-It would be cool to complete it sometime though now that I'm more experienced.
+The project never got further than rudimentary mappings with the lidar and half-working simulations.
+It would be cool to complete it now that I'm more experienced.
<a name="traffic-light"></a>
## Traffic light
-I made a traffic light simulation with an Arduino. This project was the first time I properly tried to use OOP, which I never ended up liking.
+I made a traffic light simulation with an Arduino. It marked the first time I properly tried to use OOP.
Read my [post about OOP]({ % post_url 2025-02-22-implications-of-OOP }), or [my list of software rants worth watching]({% post_url 2025-02-21-Software-Rants %}) if you want to know more about my stance about it now.
-This was actually a school project. It never really ended up counting towards my grade, since there was such a low completion rate.
+The traffic light was a school assignment, but it never counted towards my grade since there was such a low completion rate.

{: style="text-align: center;"}
## Anders Tale (Godot)
-This is the proper "game" I've been working on. Originally I started working on it in early 2021, right after I did the [Traffic Light](#traffic-light).
+Anders Tale is the proper "game" I've been working on. I started working on it in early 2021, right after I did the [Traffic Light](#traffic-light).
-I've been mostly programming on the game alone, but it's a "group" project.
-The original idea for the game wasn't mine, it was a friend who came up with it. The concept of the game has been a running joke in my friend group for many years.
+I've mostly been programming the game independently, but it's a "group" project.
+The original vision for the game wasn't mine. It was a friend who came up with it. The concept has been a joke in my friend group for many years.
-Programming on the game has been an on-and off effort from me. The main source code is not something I have public, but there is a [joke website](https://stelaug.github.io/) you can check out (not made by me).
+Programming on the game has been an on-and-off effort for me. The main source code is not something I have public, but there is a [joke website](https://stelaug.github.io/) you can check out (not made by me).
-
+
{: style="text-align: center;"}
-The game was made with Co-Op in mind. The campaign was supposed to be the highlight of the game, but the PvP mode ended up seeing the most development.
-The free-for-all was actually very fun, and we genuinely played it.
+As a Co-Op roguelike, the campaign was supposed to be the highlight, but the PvP mode ended up seeing the most development.
+The free-for-all was very fun, and we genuinely played it.
-
+
{: style="text-align: center;"}
-The game was made using GDScript and started development in Godot 3.
-One of the biggest stop-points was that lighting wasn't anywhere near performant, so the game looked pretty bad.
+The game was made using GDScript and began development in Godot 3.
+One of the biggest stop-points was that lighting wasn't performant, so the game looked pretty bad.
-I actually picked the project up again during the end of summer break in 2024. I started fresh from a clean slate in Godot 4, and it was surprising how far I've come as a programmer.
-The stopper that time was that I have gotten so used to working without game engines that it almost felt in the way.
+I picked the project up again during the end of summer break in 2024. I started fresh from a clean slate in Godot 4, and it was surprising how far I've come as a programmer.
+The stopper at that time was that I had become so used to working without game engines that it almost felt in the way.
-I should try to have a go at it again though.
+I should try to have a go at it again.
<a name="rnm"></a>
## Rick & Morty Portal Gun
-I made a [Rick & Morty portal gun](https://github.com/Samdal/r-and-m-portal-gun) together with a friend from primary school. He led the physical design, while I did the electronics.
+I made a [Rick & Morty portal gun](https://github.com/Samdal/r-and-m-portal-gun) with a friend from primary school. He led the physical design while I did the electronics.
-The project was made in a pretty short time during late May to early June of 2021. The portal gun was meant as a parting gift my friend was going to give to someone.
+The project had a small time frame from late May to early June 2021. The portal gun was a parting gift my friend gave someone.
-It was made using an Arduino, an mp3 player, a rotary encoder, and a three wide 7-segment display.\
-It had a boot-up sequence, and allowed you to "select" different world coordinates, with a bias towards C137.
+It housed an Arduino, an mp3 player, a rotary encoder, a couple of AA batteries, and a three-wide 7-segment display.\
+It had a boot-up sequence and allowed you to "select" different world coordinates, with a bias towards C137.
Depressing the rotary encoder fired the gun, enabling the front lights and playing a sound effect.
-It was powered with AA batteries.


@@ -123,7 +127,7 @@ It was powered with AA batteries.
## Minesweeper
-[Minesweeper](https://github.com/Samdal/minesweeper) was my first C project, and it marked the beginning of a new era for me. It was made during the end of April in 2021, and used Raylib to do the graphics.
+[Minesweeper](https://github.com/Samdal/minesweeper) was my first C project, and it marked the beginning of a new era for me. I completed it at the end of April 2021 and used Raylib to do the graphics.

{: style="text-align: center;"}
@@ -133,10 +137,10 @@ It was powered with AA batteries.
[gs_snake](https://github.com/Samdal/gs_snake) was a snake clone I made with [Gunsligner](https://github.com/MrFrenik/gunslinger).
-I have since then programmed a lot with gunslinger, and I am active in it's discord server.
+I have since programmed a lot with Gunslinger. I am active in its discord server.
-Discovering gunslinger was a critical part for my development as an early programmer.
-It made me discover new ways to program. I learned a lot from reading John's code. Through it's community, I also learned about Jonathan Blow, Casey Muratory, Handmade Hero and Ryan Fleury.
+Discovering Gunslinger was a critical part of my development as an early programmer.
+It made me discover new ways to program. I learned a lot from reading John's code. I learned about Jonathan Blow, Casey Muratory, Handmade Hero, and Ryan Fleury.

{: style="text-align: center;"}
@@ -144,10 +148,10 @@ It made me discover new ways to program. I learned a lot from reading John's cod
<a name="HS"></a>
## HS
-[HS](https://github.com/Samdal/hs) is an OpenGL wrapper. It mostly simplifies resource creation and usage.
+[HS](https://github.com/Samdal/hs) is an OpenGL wrapper. It simplifies resource creation and usage.
-It was a project I always wanted to make while I was following along [Learn OpenGL](https://learnopengl.com/).
-The project is very incomplete, as I never made anything proper with it.
+While following along [Learn OpenGL](https://learnopengl.com/), I always wanted to try making a library.
+The project is incomplete, and I never made anything proper with it.

{: style="text-align: center;"}
@@ -155,34 +159,36 @@ The project is very incomplete, as I never made anything proper with it.
## Anders Tale (C version)
-I figured I could use [HS](#HS) to make something, and re-making anders tale seemed like fun. I thought it would be a nice way to have some focus.
+I figured I could use [HS](#HS) to make something, and re-making Anders Tale seemed fun. I thought it would be a nice way to have some focus.
-The only notable part about the game was it's tile-map system and a AABB collision. It also supported "allowed-areas", which forced the player to stay inside a room, instead of mapping each wall as large collision shapes.
+The only notable part about the game was its tile-map system and an AABB collision. It also supported "allowed-areas". Instead of mapping each wall as large collision shapes, they forced the player to stay inside a room.
-I never got that far with this version of anders tale though.
+I never got far with this version of Anders Tale.
## Anders Tale Room editor
[Anders Tale Room editor](https://github.com/Samdal/anders_tale_room_editor) was the tile-map editor for the C version of Anders Tale.
-The project was made with [HS](#HS) and [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) for the Gui.
+It was another project made with [HS](#HS), and it used [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) for the Gui.
-This project was my first real introduction to serialisation and de-serialisation, and I made a custom file-format for the tile-maps.
-During the project I also added font rendering through STB TrueType, which taught me a lot.
+This project was my first real introduction to serialization and de-serialization, and I made a custom file format for the tile maps.
+I also added font rendering through STB TrueType, which taught me a lot.

{: style="text-align: center;"}
## Ghostbusters Costume
-The [Ghostbusters Costume](https://github.com/Samdal/ProtonPack) is another project I made together with my friend from primary. This is the main project we've had together.
+The [Ghostbusters Costume](https://github.com/Samdal/ProtonPack) is another undertaking with my friend from primary school. The proton pack is the main project we've had together.
+
+We are both avid Ghostbusters fans. Our first plan came to life during fourth grade.
+We made many revisions over the years. Naturally, all the early attempts were awful, as we were very young.
-We are both avid Ghostbusters fans. During primary school we decided that one day we were going to make a ghostbusters costume.
-As with the [Rick & Morty Portal Gun](#rnm), my friend did most of the physical design, while I did the electronics.
+As with the [Rick & Morty Portal Gun](#rnm), my friend did most of the physical design, and I did the electronics.
-We made many revisions over the years, naturally all of the early ones were awful attempts as we were very young.
-The final project used an arduino mega connected to an mp3 player, neopixels, normal leds, audio amplifier, a lithium drill battery, both a 12V and 5V supply, vibrator motor in the gun, a bunch of buttons and switches and a rotary encoder. All the lights, sounds and effects were made to be awesome and movie accurate.
+The final project used an Arduino mega connected to an mp3 player, neopixels, LEDs of different colors, an audio amplifier, a lithium drill battery, both a 12V and 5V supply, a vibrator motor in the gun, a bunch of buttons and switches and a rotary encoder.
+The realistic exterior, lights, sounds, and effects made it even more awesome and movie-accurate than I ever imagined.


@@ -193,17 +199,17 @@ The final project used an arduino mega connected to an mp3 player, neopixels, no
[SE](https://github.com/Samdal/se), the *Simple Editor*
-This project was actually a fairly decently sized project. I mostly made it during December 2021 and early 2022.
+SE was a decently sized project I mainly worked on during December 2021 and early 2022.
-My main editor was (and still is) Doom Emacs. Emacs is extremely slow, and I envisioned an editor with the features that I used without the bloat.
+My editor was (and still is) Doom Emacs. Emacs is extremely slow, and I envisioned an editor with features I used without the bloat.
-I started off with the code base of [ST, the Suckless Terminal](https://st.suckless.org/). I ripped out the "terminal" part and was left with a minimal X11/Xft monospace text renderer.
+I started with the code base of [ST, the Suckless Terminal](https://st.suckless.org/). Ripping out the terminal part left me with a minimal X11/Xft monospace text renderer.
-SE continued in a simple and Suckless fashion. It was configured through changing the `config.c` file, and it had a callback interface which allowed you to register extensions without inserting code into any core files.
+SE continued in a simple and Suckless fashion. You configured it by changing `config.c`. It had a callback interface where you registered extensions without inserting code into core files.
-The syntax highlighting and auto-indents were done with a custom state-machine-like rule system.
+The syntax highlighting and auto-indents employed a custom state-machine-like rule system.
-I started implementing a fairly complete vim support, which was a larger undertaking than I expected. The main missing features were only macros and markers.
+I started implementing a fairly complete Vim support. It was a big undertaking, but I got quite far. The main missing features were only macros and markers.


@@ -212,12 +218,12 @@ I started implementing a fairly complete vim support, which was a larger underta
## ArduinoNative
-[ArduinoNative](https://github.com/Samdal/ArduinoNative) was a header-only C++ project which implemented the same top-level features as the Arduino library.
+[ArduinoNative](https://github.com/Samdal/ArduinoNative) was a header-only C++ project implementing the same top-level features as the Arduino library.
It used the console to expose a virtual board interface and monitoring functionality.
-ArduinoNative is probably the most usable of my projects. I don't really think the code is that great, but the interface is pretty clean.
-Compared to other ways of simulating an arduino, using ArduinoNative is very simple.
+ArduinoNative is probably the most usable of my projects. I don't think the code is that great, but the interface is clean.
+Compared to other ways of simulating an Arduino, using ArduinoNative is very simple.
Serial and AnalogRead Example
```
@@ -273,20 +279,17 @@ nisse __
|____)_)
```
-I made this project during an evening in November of 2022, but I did some cleanup and additions during the following week.
-
-It's basically just an S expression parser with some helper macros.
-Like my previous parsing projects, it's made raw without a tokenzier.
-If i were to make it again I would use a slice based string, an arena allocator and made it with a tokenizer.
-
-It doesn't support escaped characters, which is probably the main feature it lacks.
+During an evening in November of 2022, I got inspired to make a simpler version of JSON. It's essentially an S expression parser with some helper macros.
+Like my previous parsing projects, it's made raw without a tokenizer.
+It doesn't support escaped characters, which is probably the primary feature it lacks.
-This project would've been a good exercise in making a proper parser, so I might re-do it.
+I have considered creating a new version with slice-based strings, an arena allocator, and a tokenizer.
+It would be a good exercise in writing a proper parser.
## gs_ddt
[Gunsligner Drop-Down Terminal](https://github.com/Samdal/gs_ddt) was a simple debug terminal I decided to write when I started college.
-It was made for invoking custom commands inside your game. It's actually been very useful, and I've had it in all my gunslinger projects since.
+It allowed you to invoke custom commands inside your game. It's been a helpful tool, and I've had it in all my Gunslinger projects since.
I also made an [example program](https://github.com/Samdal/gs_ddt_ex) for it.
@@ -295,22 +298,22 @@ I also made an [example program](https://github.com/Samdal/gs_ddt_ex) for it.
## gs_avdecode
-[gs_avdecode](https://github.com/Samdal/gs_avdecode) was media decoder for playing videos in gunslinger using the avcodec API from ffmpeg.
+[gs_avdecode](https://github.com/Samdal/gs_avdecode) was a media decoder for playing videos in Gunslinger using the avcodec API from ffmpeg.
-I made an [example program](https://github.com/Samdal/gs_avdecode_ex) for this utility too.
+I created an [example program](https://github.com/Samdal/gs_avdecode_ex) for this utility as well.
-The latest revision of the program isn't the one github, as I decided to keep it private (it's a bit more integrated into work code now).
+The latest revision of the program isn't the one GitHub, as I decided to keep it private (it's a bit more integrated into work code now).
I still think `gs_avdecode` is an alright reference if you wish to learn avcodec.
## gs_bucket_array
-[gs_bucket_array](https://github.com/Samdal/gs_bucket_array) was a generic data structure I made for gunslinger.
+[gs_bucket_array](https://github.com/Samdal/gs_bucket_array) was a generic data structure I made for Gunslinger.
-It operates similar to `std::deque`. Essentially it's a dynamic array which contains pointers to *chunks* or *buckets*. The array grows by adding a new bucket, which gives a good compromise between size and insert/delete/iteration times while retaining pointer stability.
+It operates similarly to `std::deque`. It's a dynamic array that contains pointers to *chunks* or *buckets*. The array grows by adding a new bucket, which gives a good compromise between size and insert/delete/iterate times while retaining pointer stability.
The implementation additionally came with an optional packed free-list.
-I don't use this project anymore as I would rather use a linked lists or static allocation.
+I don't use this project anymore. I would rather use a linked list or static allocation.
```
gs_bucket_array(float) ba = gs_bucket_array_new(float, 100); // Bucket array with internal 'float' data, where each bucket is 100 floats
@@ -323,22 +326,22 @@ uint32_t bs = gs_bucket_array_bucket_size(ba) // Returns initi
uint32_t bc = gs_bucket_array_bucket_count(ba) // Returns the amount of buckets allocated
uint32_t ba_cap = gs_bucket_array_capacity(ba) // Returns bucket_size * bucket_count
uint32_t ba_size = gs_bucket_array_size(ba) // returns index+1 of the last element
-gs_bucket_array_free(ba) // Free's the entire array, make sure your own elements are free'd first
+gs_bucket_array_free(ba) // Free's the entire array, make sure your elements are free'd first
```
## awaC
-[AWA5.0](https://github.com/TempTempai/AWA5.0) is a stack-based [esoteric programming language](https://en.wikipedia.org/wiki/Esoteric_programming_language) where you manually write the bits with "wa" or " awa".
+[AWA5.0](https://github.com/TempTempai/AWA5.0) is a stack-based [esoteric programming language](https://en.wikipedia.org/wiki/Esoteric_programming_language) where you manually write the bits with `wa` or `awa`.

{: style="text-align: center;"}
-The original implementation was done in JavaScript. Others have also made their own interpreters and compilers for it. I made mine in C and called it [awaC](https://github.com/Samdal/awaC?tab=readme-ov-file)
+JavaScript was the chosen language for the original implementation. Others have also made their interpreters and compilers for it. I made mine in C and called it [awaC](https://github.com/Samdal/awaC?tab=readme-ov-file)
-Originally the plan was to use this project to make a graphical debugger, but I never got to that part.
-The only debug functionality the interpreter provides is printing the stack and program counter.
+I originally planned to use awaC as an excuse to make a graphical debugger, but I never got to that part.
+The interpreter only provided debug printing of the stack and program counter.
- After watching a Tsoding stream about making a web server in fasm, I knew I wanted to do that with AWA5.0. All I needed was to extend the byte-code with a `syscall` operation, and painstakingly write over a kilobyte of `awa awawaw awawaw awawa`.
+After watching a Tsoding stream about making a web server in the flat assembler, I knew I wanted to do that with AWA5.0. All I needed was to extend the instruction set with `syscall`, and painstakingly write over a kilobyte of `awa awawaw awawaw awawa`.
The website I ended up hosting was a JavaScript interpreter of AWA5.0.
