Jump to content

_Rocket_

Member
  • Posts

    540
  • Joined

  • Last visited

  • Days Won

    29
  • SteamID

    76561198147511354

Posts posted by _Rocket_

  1. Hey everyone. So here's the deal. Right now I am practicing for my language arts GED. I have passed my science one which is quite the big wew gotta say.

     

    During the English GED, I will have a critical review essay portion. In a critical review, there are no opinions given. I am tasked to write an essay analyzing two points of view on one subject. I am also tasked to use what I have analyzed to critique each argument that both parties give, and use these arguments to share factual evidence and provide what I have gathered. It all will come together as an essay that gives an answer to the question of: "Who defended their case the strongest?"

     

    The test comes up on the 12th for me. I would like someone in here to possibly provide an example of two points of view arguing on a single topic. Things like press release articles vs letter to the editor articles, political party arguments, etc. Anything that would perfectly fit the format of a critical review essay. I will choose one of the examples given to me in the responses below and write a full essay here. This will serve as my practice to prepare myself for the GED. Thanks guys.

     

    (I should mention, I will choose a topic to write about sometime tomorrow. So that'll hopefully give people time to give a couple examples for me to use as practice.)

  2. 52 minutes ago, Joshy said:

    Good luck.

     

    Will you go for a community college degree afterwards?  Maybe?  I personally recommend it because it sounds like you're very interested in programming.  I don't think a lot of programmers need higher education because a lot of their skills come from practicing the language, but you learn the fundamentals to advanced stuff; also: HR people usually have no idea what they are doing (they have little to no technical background) and so they will aim for someone with a degree as a good measure rather than someone with years of experience.

    Yeah I know about all that. The only way to get a job as a programmer is if you have a degree. It's a necessity. Because it's very true. Yeah, I plan on having a lifelong career as a programmer. Being a developer is pretty much a good way for me to gain a little more experience as I'm working on various projects.

  3. So, my activity might slow down a little bit because of my GED testing. My first GED test comes tomorrow, which will start a wave of studying and other stuff. So my activity in TTT rotation and GFL forums may slow down a considerable amount until late this month/next month. But it will pick back up after I finish my GED testing and get my GED done and out of the way. No more school hecc ye bois

  4. 13 hours ago, Akris said:

    Just thought of this but if people have the free time we have people that know how to code kinda have mini classes to teach coding to people interested or managers that need some coding skills.

    I love teaching people programming. If you or anyone else needs help with programming I'm more than happy to help (provided I have the time lol, this month is busy for me). The languages I know the most are C++ and Java, so if you want to learn either of those I could most definitely help you get started 😄

     

  5. So far I have only seen you through the forums. But all I have seen has just been nothing but the indicators of a nice person. Seriously, I have still seen you around in the forums despite how busy you are. I'm sure the people who are in GFL appreciate all you have done for the community.

     

    I am still rather new to GFL. I hate that I wasn't able to be here to meet you. You seem like a really nice person to be around. All those memories you spoke of sound so wonderful. And man, those are memories you get to keep.

     

    Good luck with school. You are gonna be going to College soon. And we are all excited for you. Keep on going man, you'll go far.

     

    From Rocket, a person who may not have had a chance to meet you, but still has respect for you nonetheless. Have fun miboi, and good luck.

  6. Here lately I have noticed something.

     

    My mentality during writing feels very different from when I'm speaking. I haven't really experienced this before. But as I have written more and more in GFL, I have noticed that my attitude is different when I'm writing compared to when I'm speaking.

     

    I have a hard time translating what I would normally say vocally and how I speak to text. And I honestly don't really like it. On a couple of posts I have tried voice to text. And I feel as if it does a better job at showing my personality and how I actually speak.

     

    To show what I mean I am going to start using voice to text right now. This paragraph is currently being written by voice to text. I will probably use it for the rest of us forum post. Now besides a few grammar errors along with a few misunderstandings with the technology involved with voice to text, it seems to work okay for me. when I am writing instead of using my voice, I tend to be a lot more direct than how I normally am. Don't get me wrong I am known to be a pretty direct person who speaks his mind, but when I write I seem to be extra direct. More direct than I really care to be. Because when I write, I don't like how direct I come across. It makes me seem more like a dick then my intentions are trying to show.

     

    I am honestly curious if anyone else deals with this. Because I have been noticing this here lately and quite frankly I really don't like it. I have already been told by a couple of people that I come across in a way that they don't... Well, they seem to say I I appear to be showing authority when I speak. I guess what they mean is I appear to be talking down to them when I am trying to explain what I am saying. Believe me when I say this is far from my intentions, very far. just like I just said, I am known to be a very blunt person. But I think when I am writing, this bluntness is enhanced in a way that I am not fully sure on. At the same time I am already a little tired the few small errors that voice to text does. I really don't know what I should do. Because I don't want my intentions to be misunderstood, because from what I have seen heard they seem to be misunderstood already. Maybe I will use voice to text more often I am unsure. let me know what you guys think because I am a little unsure how to go about this oh, because I don't want my intentions to be misunderstood in the way they already have.

     

    It makes me kind of curious on the psychology of this. If you know me already, I am very interested on the human psyche. And this really intrigues me. I wonder if there has been any studies ran on this, because I highly doubt I am the only one who has this issue. this might just give me something to think about as I'm developing my stuff. I mean he'll, this is the kind of thing I talk to myself about at night because I just enjoy talking about various topics involving human psyche. I might make a reply to this post if I come up with anything I might think is the answer. Thanks for reading.

  7. As I've said before, I don't have any experience in the breach community. However, getting hate from players means nothing if you're just doing your job.

     

    I strongly stand by standing your ground despite backlash. It shows you have a strong backbone. And if you are able to manage a server despite knowing how much backlash you're going to likely get, then that shows you're worthy of a position like this.

     

    In the end, you have a job you want to get done. Managing a server isn't easy work. If people get pissed at you just for doing your job, this is where leadership skills come in. A good leader is someone who uses reason and logic, and doesn't let emotion get the best of them. There is going to be moments when someone probably pisses you off a little. Just power through it and don't let your anger cloud your judgement and create bias. I don't know you personally, but Xy seems like the kind of guy who would make genuinely smart decisions. If he put you in this spot, it's obvious he trusts you have those leadership skills. You can do this.

     

    And about the whole furry thing, if you're a furry, don't worry about it. There's always going to be someone on the internet who wants to roast you alive just because you like something. You'll be alright haha.

  8. Introduction

    Allocating memory in RAM for variables is something that on the surface sounds simple. But like most other things in both software and hardware, there are very small details that make huge differences.

    If you have ever branched off from any high level languages like Java, Python, or Lua, you've likely ran into a single topic that might even confuse you to this day. Stacks and heaps. These two things are the names for procedures. Procedures used to allocate memory in RAM to store variables and instructions. But what is the stack? What's a heap? How do they work?

     

    You have already learned about why things are stored in RAM, and what stores it there. But unless you have done research on this topic yourself, you may not know exactly how that memory is allocated. Some would think the CPU would start at memory address 0 and work its way up... but we all know how inefficient that is. If you are truly curious about how these processes work, then hopefully this will clear some of your questions.

     

    What is the "Stack"?

    The Stack is something that you surprisingly don't see in too many languages. This is because for many languages, the stack is overkill. The Stack is a fast way of allocating memory in RAM. The process that the stack follows goes like this:

     

    The initialization:
    When a program is launched, a very interesting thing takes place. In the stack, memory in RAM is pre-allocated before any instructions that you have written are ran. What this means is, the program finds a section in RAM large enough to allocate memory that the program will use later. To this day I have not gotten a consistent answer to how much memory is allocated for the stack, but the range is usually 1-8 Mb.

     

    The Allocation of Variables:
    To be able to visualize this properly, I should elaborate what "pre-allocated" meant. What the stack does is essentially "claim" a chunk of memory in your RAM. If you have a few GB of RAM, 8 mb is absolutely nothing. This means that as soon as you run your program, 1-8 mb of RAM is already "in-use". I like to visualize it as RAM that is inside RAM. The actual RAM stick pretty much shares a very small chunk of it's memory to the software, and now the stack can use that shared memory as its very own RAM stick.

     

    When you declare a variable using the stack, an instruction called "push" is executed. This newly created variable will then be placed at the very top of the stack. This memory is now been claimed by a variable, so to the stack, this memory is no longer claimable by any new variables.

     

    The Lifespan of Variables:
    Lifespans of variables and how scopes work will be covered in the next tutorial. But for now, just know that stack variables only last as long as the scope lasts. If you do not know what a scope is, a tutorial will cover this topic very soon.

     

    The Management of Variables:
    The Stack has its name for a reason. Imagine the stack as being a stack of plates. Each plate has a different material and design to it, and they are all stacked on top of each other. When you want to add a new plate, you place it on top of that stack. If you want to grab a plate and use it, you take a plate from the top of the stack. This is known as a LIFO, or a "Last in-First out" operation. Whatever was last added to the stack, it will be the first object popped out when you go to grab that plate.

     

    This is how memory is managed with the stack. The memory as stated before is already pre-allocated by the compiler upon launch. But this pre-allocated memory can be overwritten by data given to it, almost as if it's a micro-sized RAM stick.

     

    The way the CPU accesses this memory is through an instruction named "pop". Pop is the only way to get data from the stacks memory. And this instruction tells RAM to pop out the object at the very top of its stack. Much like how you grab a plate from a plate stack. Once this is popped out from the stack, it gets stored in a high-speed pointer that the CPU can quickly use. This process is automated and handled by the stack itself. This is why creating pointers to stack variables can be dangerous if they aren't made globally.

     

    What is the "Heap"?

    The heap is the most common way of storing variables in RAM. A lot of languages use the heap for its storage, mainly because they aren't designed in a way that gives the stack any use.

    The heap isn't unique like the stack. Your entire RAM stick is available to the Heap. This means that all allocation is done through the RAM stick itself, though the process of finding that memory is a little complicated and will be covered in a second.

     

    The Allocation of Variables:
    The allocation of variables is rather compiler-dependent. But the most common way (from what I know at least) of finding memory to allocate variables to goes something like this: Imagine a revolver. The revolver is named due to the thing that holds the ammo, which is also named the revolver. You could imagine the heap as a revolver with a bunch of different avaliable addresses in RAM. It has all of this in standby, and once the heap is called upon, it will give out the necessary storage needed... Please note that this is heavily boiled down. In all reality, the way the heap works is very complicated. I might cover it more in depth at a future time because the way the heap actually works would require an entire topic post to explain.

     

    The Lifespan of Variables:
    The lifespan of a variable stored in RAM through the Heap process is actually pretty dependent on what language you are using. For most languages, the language itself handles heap variables. Specifically mid to high level languages. In these languages, a Heap variable will act a lot like a stack variable in regards to its lifespan. So if you tried to use a pointer to point to a variable when the scope its located in was already removed, it will likely crash your program.

     

    The Management of Variables:

    The way Heap variables are managed are the main reason to why it's uncommon to see them used in low level languages. All the variables currently stored in the heap must be on a list for the program to access. Of course the way this "list" works is also pretty complicated, just know this information has to be stored. Unlike the stack, where all variables are in one place and accessed through a pointer, the variables stored through the heap are accessed dynamically. They are stored dynamically. That's really the main difference between the stack and heap process. The stack is more static. The heap is more dynamic.

     

    Due to how the heap works, allocating and accessing these variables take longer. This difference in speed does not really matter for high level languages, but languages like C++ are impacted. Anyone who uses low level languages use them for efficiency and performance. Otherwise it's usually just overkill. So a low level language may use the stack by default, while high level languages use the heap by default.

     

    High Level Languages

    A high level language does not mean what some may think it means. It does not mean "level of difficulty". If anything, lower level languages are the more complicated languages to program with. What the phrase "high level" actually talks about is its level of optimization. High level languages are incredibly optimized. These optimizations range from how variables are handled, how objects are handled, how compilers compile code, etc. Typically, the higher the level, the more complex and advanced the compilers are. This is why Python can look so different from Java, for example. Python compilers are vastly different in how it reads your hand written code, and how it translates it into code that the computer can read. In fact, Python's compilers are so advanced they can handle datatypes for you.

     

    The Stack and How its Used

    For almost all high level languages, the programmer is not given the option to use the stack as a means to store variables in memory. Any use of the stack is done through the compiler or the language itself. Something that programmers have zero control over.

     

    The Heap and How its Used

    The heap tends to be the default method of storing variables into memory for mid to high level languages. Unlike low level languages, the compilers of high level languages are designed to handle heap variables for you. This is why some newer programmers who start with high level languages do not learn about the heap or the stack until later on. The reason why the heap is so automated is due to how advanced the compilers are. These compilers are very precise and well-crafted. And they are designed to handle a lot of things so you don't have to. This is what makes a high level language "high level". This is also why high level languages tend to be easier to write programs with.

     

    Low Level Languages

    A low level language is the polar opposite of high level languages, go figure. These languages tend to be older ones. Ones designed in an era where a lot of the work was done by the programmer. Due to this, compilers are usually "simple" (when compared to high level language compilers). Compiler designers tend to start with low level languages when they are beginning to learn about how designing a compiler works. This also means some of the work is reliant on the programmer.

     

    The Stack and How its Used

    The stack is very often the default method for storing things into memory. In fact, assembly code is so low level, you are the one responsible for managing the stack. Though, besides assembly, stack variables are usually completely automated. You can use pointers to point to stack variables. But it is very suggested you only do this to global variables/objects and not local ones.

     

    The Heap and How its Used

    The heap is... very different in low level languages. In high level languages, a lot of what happens with the heap is managed by the language and the compiler itself. You don't have to worry about a thing. Again, high level languages have high level compilers. But in low level compilers? Using the heap is pure hell and agony.

     

    Even in C++, which is a borderline low-level language (imo), nearly everything that happens with a heap variable is in your hands. First of all, the only way to use the heap is usually done through the "new" keyword. The funny thing is, you actually have to have a pointer variable to use it.

     

    The reason why using the heap is bad isn't just due to its slower performance. Constantly de-allocating and re-allocating a single heap variable can lead to inconsistent memory leaks and bugs. These have the potential of crashing your program. Just... don't use the heap in low level languages. Unless you want to go through the hell of managing these damn things, I suggest you stick with the stack.

     

    If you need a little more on how these things work, here's a video I linked before you can use for review on stacks. The heap is very weird and I quite frankly am not for sure what I could link here. I personally need to do more research on how the heap works because there are a lot of areas I am unsure on or completely uneducated on. The heap is weird, man.

     

  9. 44 minutes ago, Joshy said:

    I am mystified.

     

    
    #include<stdio.h>
    
    int main()
    {
    
    	char someCharacter = 'A';
    
    	
    	for(int i=0; i<26; i+=true)
    	{
    	
    		printf("%c\n", someCharacter+i);
    		
    	}
    	
    	
    	return 0;
    	
    }
    

     

    Z6YzVaA.png

     

    Even if the smallest register size is 1 byte, then why don't they just concatenate or shift the registers?  It's not uncommon in the real world to have small information slices sit between two registers.  In fact: If you look at the instruction format, then you'll see that some fields are 5 and 6 bits.  Do they waste the other 2-3 bits because the smallest register size is 1 byte?  I don't think so.

    That is honestly crazy. Never knew you could do it like that. Then again it makes sense, true and false is kind of like a macro, 1 and 0. It's why you can do while(1) and it still work just fine.

     

    I believe there are different syntaxes just for the sake of code readability. It makes code much easier to understand.

     

    And to be frank, I can't really give a solid answer to the second question. That is something that requires an extensive knowledge on assembly code and/or compilers. I may know a little on assembly and understand what compilers are, but I'm far from an expert. I could imagine this question has been asked somewhere in stack overflow.

     

    The one thing I do know is: The fact that it is a byte doesn't really impact performance at all. If booleans were 1 bit long, the performance would actually for the most part stay the same. So yeah, it is wasteful, but at the same time it doesn't impact performance in the slightest. Because in the end, the CPU is still looking for a single memory address, regardless of it's actual size.

  10. Introduction

    The compiler is an essential part of why programming languages exist. Without the compiler, most of what we do as programmers wouldn't be possible.

     

    The language the computer speaks is something that no human can efficiently read. With time you could learn how to read very small portions of code that is made entirely of 1's and 0's, but there would be no possible way to read it as fast as you would a normal programming language. This is where a compiler comes in. Because the lack of understanding between human and computer is a two way street. A computer cannot understand the programming languages we use. An if statement means absolutely nothing to a computer, much like how an incredibly long line of bits means nothing to us. So in order for programs to exist, there had to be a way to translate human-written code into something the computer could understand.

     

    What are Compilers?

    A compiler is responsible for turning your hand written code into something the computer can understand. It acts like a translator. Whatever you write in your code, the compiler is responsible for translating that written code into bits that a computer can use to run your program.

     

    This is why compilers can be very strict about what you do and how you do it. During compile time, the compiler is going through every single word of your code and translating it into a language your PC can use. This is a very specific and unforgiving process. Every single line has to make sense to the compiler, at least to the point of it being translatable. If even one thing doesn't make sense, the compiler will instantly refuse to continue. This prevents anything extremely weird happening. If the compiler just continued to compile your code despite it confusing something, your program would undoubtedly crash. There are a lot of moving parts in your PC, and everything has to flow without error. This is why even making a single mistake when writing code will always upset your compiler. It confuses it, so it stops before trying to finish a broken application. Luckily, over the many years of programming being around, compilers have become smart enough to tell you what the error is and where it is located. Be glad you live in a time when that kind of technology exists, because back in the day... One error would completely mess up a program, and you would not be given a single hint as to why it is failing to function.

     

    Why are there so many compilers?

    Compilers are very complicated. You would think compilers could be exactly the same... But no. Compilers are very different from one another for many reasons. Your operating system, hardware, and especially your programming language are factors you have to consider when designing a compiler. Due to how precise compilers have to be, this can lead to compilers failing on certain hardware or operating systems. Remember, there always has to be a smooth flowing operation going on in your PC. And the way a PC is designed can heavily change how that "flow" operates. A mac is very different from a windows PC. On the surface they appear very similar. But their hardware has very specific differences that change everything. Compilers have to factor in these small differences. This is why a single programming language can have multiple compilers to choose from.

     

    This is also why software or games can have different release dates for different operating systems. Code HAS to be written differently for different operating systems (depending on the language). Compilers always have a set of rules for the programmer to follow to ensure everything works properly during compile time. These rules can change depending on what operating system the program is being made for. This can force programmers to finish writing code, compile for one operating system, then make a copy of that code and edit it until it follows the rules for a different compiling procedure.

     

    How Pointers Break Compilers

    If you do not know what a pointer is, this section may not concern you. However, if you do have experience dealing with pointers, you probably know what I am already going to say.

     

    For the most part, everything memory related is handled by the compiler itself, along with the instructions the CPU is given. This is because the compiler is designed to make these procedures automated to ensure the program works properly. So having bad memory allocations that result in a crash is next to impossible. However... some languages have a nifty little thing called a pointer.

     

    Pointers are used to point to addresses in memory as you should already know. The problem is, compilers have no way of regulating your uses of pointers. Usually languages try to prevent programmers from doing really stupid stuff by forcing you to at least provide a datatype or an object to a pointer. Like ObjectEntity* e; And for many cases, this works. But a compiler cannot monitor anything besides that. Pointers are the ONLY thing in any language that allows you to do one of the compilers jobs. This can be incredibly powerful, but also incredibly dangerous. If you have used C++, you are bound to have had a memory allocation error. You know the one. The one that has a very large negative number? Yeah, that lovely one.

     

    Compilers are automated and handle memory without error. But when you give a human the ability to manage memory, even if it's a very limited control, it's still giving a lot of power. And since we are all human... mistakes happen often. And those mistakes can lead to very inconsistent crashes. Allow me to provide an example.

     

    When you create an array, you are required to provide a base element size so the program can properly find a memory block to hold all the elements. Like this:

    int array[100];

     

    //If you tried to call:

    array[100];

    //You would get an array out of bounds exception. Same with doing array[343]; or any other number larger than 99.

     

    The compiler can recognize this error because it is responsible for managing the memory addresses of this block. It has full control over what happens to the memory address. However, making an array of pointers is a little different.

     

    //The compiler finds the memory address for this array for you, but the memory management is officially in your hands from this point on

    int* array[100];

    //The compiler cannot touch the memory addresses of these pointers until you instruct it to do so. This memory is up to you. All the compiler understands is there is an array of pointers. It cannot recognize where the array begins or ends. All you have done is told the compiler "Hey, conserve this block of memory in RAM for me".

     

    //Due to this, you can be really stupid and go out of the arrays boundaries. Remember, all the compiler CAN know is there's an array of pointers. That's it. Everything else memory address related is up to you.

    array[100];

    //This will not result in an error, same with array[13341]; This is incredibly dangerous.

     

    If you name off an element that is outside of a pointer arrays boundaries, a couple things can happen.

     

    1. Everything will be fine. In this situation, you officially have pointed to a memory address that is not in use. The really cool thing about this is the fact that you can now do anything you want with this memory address. You can even see the last value that was stored in it. But...

     

    2. You can instantly crash. If a memory address is currently in use by a different program, a bunch of crap goes wrong. Very wrong. Very very wrong. And it guarantees a crash.

     

    So messing with pointers in this way is dangerous because you can potentially crash. The funny thing is, you could very well do this without having to worry. Because in the end, you only sometimes crash. But when a crash is inconsistent, you aren't a very good programmer if you don't try to fix it.

     

    Assembly Code and its Relation to Compilers

    Assembly code is the closest thing we have to actual machine language. Learning assembly code is a really good way to better understand how compilers work. You are essentially telling the computer how to do every single step with assembly. To be frank it's awesome. Explaining the details of assembly is something that would take multiple tutorials. Because you have to factor in things like how the stack and the heap works, different operating systems, different hardware, etc. It's crazy.

     

    If you would like to learn a little on assembly, here's a nifty video for you to watch.

     

    Assembly is incredibly interesting because you are writing code that the computer can almost understand.

     

     

    Making a compiler is possible. If you are truly interested in how a compiler works, look for some tutorials on designing a compiler for a language. "Low level languages" like C (and assembly, which is one of the lowest levels) are much easier to write compilers for due to how the language is designed. Making a compiler for higher level languages like Java and Python is very complicated. So maybe start with C.

  11. If all those buildings aren't just boxes and you can enter them, this map could possibly work. I don't have a ton of experience with hide and seek, but this map could work. Idk how well it would work if the server was full though. There is an abundance of buildings so, as long as every building is hallow and actually has an interior, this could function as a pretty decent hide and seek map.

     

    I would still probably run some tests and see how it plays out. That's something for the server manager to decide. Have you played hide and seek in this map before? What was your experience with it?

  12. 1 hour ago, Joshy said:

    Why are datatypes degenerate in terms of its size?  Why not just be efficient and have four different datatypes?  We'll convert the bool and char into one datatype that is 1 byte; the int, long, and float into another that is 4 bytes, and lastly double and long long into one more 8 bytes.

     

    Another question is why is bool so wasteful?  It would be better if it were just 1 bit instead of a whole byte.

     

    I enjoy your guides.  Keep up the great work.

    If you read closely, these questions are actually answered in the text. But like I said, it can be easy to miss things upon first reading.

     

    When it comes to RAM, you would be correct. The difference between a char and a boolean is absolutely nothing to RAM. They might as well be identical. However, this is where a compiler comes in.

     

    When you write programs, you are essentially writing the instructions that your computer will follow when running your program. The compiler is responsible for turning your human-readable code into something that the computer can understand. Due to how compilers work, you have to be very specific when you write your code. Otherwise, the compiler would become easily confused and make really weird programs that easily crash.

     

    This is why there are different datatypes. For instance, if you tried to do:

     

    int var = 'c' + false;

     

    How would the compiler properly compile instructions for this? To your RAM, it wouldn't care what is stored inside it's memory. It's job is to just store whatever it is given. But for a program to properly function, these clashes of datatypes could cause very problematic inconsistencies in instructions. This is why different datatypes are essential for programs to run properly.

     

    I also explain why bools are 1 byte long. As of right now, we cannot make variables that are smaller than 1 byte.

     

    This is due to how the CPU handles instructions. When the CPU accesses RAM, it does it through memory addresses. A single memory address is 1 byte long. If you watch the YouTube video I linked, you'll see what a CPU does. It does its instructions through accessing memory addresses.

     

    Since a memory address is pretty much a "label" for 1 byte in RAM, any variable HAS to be at least 1 byte. That's the only way the CPU would be able to access that variable. Otherwise, variables would begin to share memory addresses, which would lead to horrible inconsistent bugs and memory leaks.

     

  13. Introduction

    Hello, and welcome. This is the first of likely a series of posts about basics in programming. Now, just because this is named "The basics", this post is going to cover datatypes in a much more in-depth level. If you are just starting to learn programming, the contents in this post will likely overwhelm you. I suggest you study a little more on languages like Java or any C language because these languages use datatypes often. This post is more geared towards those who have a little experience with programming and know what a datatype is, but doesn't fully understand why a datatype works and why different datatypes are essential to a computer.

     

    This is going to go step by step in explaining what datatypes are and how they operate. Every bit of information is crucial to understanding what these things are, so read carefully. You may even have to read over this a couple times, because I can guarantee you, you might miss a couple things your first time reading.

     

    The Hardware

     

    The CPU

    Understanding how software communicates with your computer requires you to understand the hardware the computer operates with. The Central Processing Unit is the most essential part of your computer in regards to preforming calculations and instructions. 

     

    The RAM

    Random Access Memory is constantly communicating with your CPU. This piece of hardware is responsible for holding every single thing that makes a CPU work. A RAM's job consists of storing variables, instructions, and other things that can be used to tell the CPU what to do, how to do it, and where to find the tools responsible for preforming what it is told.

     

    The Relationship of RAM and CPU

    One thing that some people may not know about RAM is how instructions are stored. When you run a .exe file on your system, all the code that is compiled into that .exe file is transferred into RAM as instructions. Uh huh, that's right. The instructions in your code is stored inside RAM as well as variables and other things. This is why really large programs with millions of lines of code may take a second to actually launch when you run them (Like GTA V, which tends to have a few seconds of nothing before it actually does anything). In that moment when you click the .exe application, all those instructions are being loaded into RAM. Once they are all loaded, the CPU begins to access the memory addresses that hold these instructions and performs them.

     

    If you have any experience, or have at least looked into assembly code, you will know how the RAM stores these instructions. If this at all confuses you, feel free to consult the following video by Tom Scott.

     

     

    What is a Datatype?

    A datatype is a way to both identify the size of data that RAM needs to store, and a way for the compiler to know how the variable is meant to be used. Datatypes are essential to the functionality of your computer for quite a few reasons that I will get to in a moment. Chances are, if you are only experienced with Python or any language that does not allow the programmer to name datatypes, you may be wondering why you never have to use them.

     

    Python and other languages that don't show datatypes are typically heavily object-oriented languages. A lot of the memory, scopes, etc. are handled by the language itself and the compiler that comes with it. This allows programmers who use these languages to completely forget about datatypes and just deal with the code. However, with languages like C++ where efficiency is the most important part of the code, being able to choose the datatype for each variable is important and essential.

     

    Why Your Compiler Needs Datatypes

    When a variable is stored into a memory address in RAM, it becomes nothing but a binary number. There are no characters involved, just binary. A base 2 number system. This can be a huge problem for a number of reasons. When everything in RAM is represented in binary, the compiler has no way of telling the difference between a 1 byte bool variable and a 1 byte char variable. When the compiler has a way to identify what datatype a variable is, it can't properly compile the instructions in a way that allows the CPU to handle the information accordingly.

     

    Why Your RAM Needs Datatypes

    When a program is launched, all the instructions and variables MUST be stored in RAM. And as the program is running, variables are constantly being altered and created, so there is non-stop communication between your CPU and your RAM. When a variable is declared, it is now crucial to find a memory block that can hold the size of the variable. This is where datatypes come in. Without datatypes, there is not a consistent way of telling the size needed to store a variable. If you took a moment to think "How could variables be stored without datatypes", you could probably come up with a few ideas... But you would know how inefficient they would be. A datatype has a distinct memory block size, and when a variable is declared, it will find a memory block that is free in RAM that matches the space required. Without it, am integer could wind up taking up much less or much more space than it is supposed to.

     

    The Datatypes

    These are the datatypes you will find in code. Some datatypes are used more than others, especially depending on what language you use.

     

    bool & boolean - 1 Byte

    char - 1 Byte

    short - 2 Bytes

    int - 4 Bytes

    long - 4 Bytes

    float - 4 Bytes

    double - 8 Bytes

    long long - 8 Bytes

     

    Boolean

    Boolean is a true or false variable. In RAM, a boolean will only use a single bit to store its value. It must take up a full byte for one reason, memory addresses. Memory addresses in RAM are always a single Byte. This means no matter what, any variable MUST be at least a byte long, no matter what they store. You will see booleans often. Even in a simple if statement like this:

     

    if(6 == 12) runMethod();

     

    The if statement is actually taking in a boolean argument. == is a boolean operator, and it compares the constants you see in the brackets. The result of that boolean operator is... a boolean variable haha. And of course, you can even make your own boolean variables. The name of boolean differs between languages.

     

    Char

    A char variable does need a byte to store its information, unlike boolean. Due to how char works, it acts a lot like any typical number variable. You can increment chars, do math with them, etc. So in all reality, the CPU doesn't really need to tell the difference between a char variable and an integer variable. The compiler does. Some languages do not allow the programmer to use char. It only allows them to operate with strings. So doing things like this:

     

    char b = 'b';

    b++;

     

    or

     

    if(varChar < 'A') runMethod();

     

    is not possible in some languages.

     

    Short

    You will see shorts in languages like C++, but not so often in languages like Java. This is because shorts are essentially an integer that takes up less space in RAM. Using shorts in java is pretty uncommon because Java isn't built for high-tier efficiency. It's a heavily object oriented language. Efficiency wasn't in mind when it was designed. But in languages like C and C++, you may see shorts quite often.

     

    Int

    Integers are one of the first datatypes you will use when you begin learning a language. It is an okay-sized variable that doesn't take up too much space, and it has enough space to hold large numbers. Quite useful.

     

    float and double

    Floats and doubles are similar to the relationship between shorts and integers. However, a float is NOT just a double that takes up less space. Floating point numbers are very different in how they are handled, much like how longs are handled differently from integers despite the fact that longs take up the same memory size in RAM. You will see floats incredibly often in C++, and will rarely see doubles. But you will see doubles quite often in Java, while not seeing very many floats.

     

    All the other datatypes are a little more self-explanatory. You can do more research on these if you need to.

     

    The Difference Between a Signed and Unsigned Variable

    Understanding the difference between signed and unsigned variables require you to understand how RAM and CPU identifies negative numbers. When a variable is signed, it means it can hold either a positive or a negative number.

     

    When a variable is signed, the first bit inside the first byte of the variable in RAM is used to represent if it is positive or negative.

     

    So, say for instance: 0000 0101 represents the number 5. The first bit is 0, so it is actually -5. To get positive 5, you would need RAM to look like this: 1000 0101. This is positive 5.

     

    The downside of signed variables is the highest number you can store. Since a single bit is used to identify if the number is positive or negative, the highest number you can have is greatly reduced. Let's go back to that variable we talked about.

     

    1111 1111 is the signed representation of positive 127. You cannot go higher than this. If you tried to increment this number by one, the number would overflow to 0000 0000. However, an unsigned variable is different.

     

    In an unsigned variable, no bits are used to represent if a number is positive or negative. This means 1111 1111 actually represents the number 255. The good thing about that is the fact that your number can be larger now. The bad news is, you can no longer have negative numbers. If you tried to subtract 1 from 0000 0000, the number would underflow into 1111 1111 which is 255.

     

    So, if your number will never be negative, use an unsigned variable to be safe. That way, the variable can count higher without overflowing. (Btw, if I accidentally reversed 0 and 1 representing positive and negative, sorry about that lol)

     

    How RAM Locates Memory...

    ... is a little too complicated for this tutorial. When you ask that question, you have to learn about stacks and heaps, and how memory is allocated into RAM, how memory blocks are found, etc. What I CAN say is, memory is not found the way you may think it is found. It doesn't start from memory address 0 and work its way up to memory address FFFFFFF or whatever. I might cover that in a later time when I learn a little more about it myself.

     

  14. Introduction

    So, allow me to introduce you to a problem. Because as a programmer, your job is that of a problem solver. You will be spending a ton of time fixing bugs and working out kinks in your code, and in the workplace you might even be fixing other people's code. A good problem solver is someone who can fix these problems quickly but efficiently. Because in the end, all the libraries you have access to are just tools in a toolbox that you can utilize to do problem solving.

     

    Improving your skills as a problem solver isn't something that you can truly practice. It's moreso something that comes from experience of making your own projects. The harder the project, the more problems you'll encounter, leading to more experience you'll gain.

     

    Before The Problem

    This problem actually comes from something I had to deal with as I was developing my game. And I am going to use this problem to help you gain some insight into the mindset you can inherit to fix your own optimization issues. Don't worry, because this is heavily boiled down for ease of digestion. In my actual code for the game, fixing the problem required pointers and pairs and vectors and an entirely separate function, etc. Something I couldn't possibly teach you in this forum post alone without making it incredibly long. So I'll show you a very watered down version of the problem I faced and had to fix using my own problem solving skills alone.

     

    Basically, there is a block in the game that acts as a switch. When touched, it switches a bunch of different blocks into their opposite state. Again, for the sake of watering this down, true means you can stand on the platforms, false means you can't.

     

    When the player touched one of these switch blocks, the game would then analyze the entire map to find pixels that have the switchable platform color. It worked like this:

     

    Green was the switch block.

    Magenta was the "true" platform.

    Dark magenta was the "false" platform.

     

    When a green block is touched, the game would analyze each pixel and find any pixels that have the colors of either magenta or dark magenta. If it found any, it would switch that block color to the opposite color.

     

    Why is This a Problem?

    When you are making something like a video game, if your game is going to lag, make it consistent and make it happen when it makes perfect sense. (Like a checkpoint being touched, a loading point being reached, etc.) However, when lag spikes are sudden and inconsistent, players of your game will NOT be happy. I was faced with this problem when during my playtesting I noticed a very big issue.

     

    Map sizes are not always the same. Map sizes could range from 800x600, up to 1500x1200. This... This is a problem. Think about it, the larger the image is, the more pixels that need to be analyzed.

     

    When analyzing a pixel, the game engine will return the exact pixel color. The thing is, it actually returns a class. Every time the method x.getPixel(); is called, it returns an sf::Color object. Even if a map is 600x600, that means the game will need to analyze 360,000 pixels! Which means it will return the sf::Color class well over a quarter of a million times every frame. On a map that is 1200x1200... That's 1200 squared. That's... 1,440,000 pixels... Per. Frame.

     

    There's a very clear problem here. Because as you could imagine, if the map was any larger than 1000x800, the game would have lag frames. In a precision platformer, lag frames are dangerous and infuriating. Especially when the lag frames last for 20 frames just because the map is 1500x1200. So, how can we fix this? Well, before I continue, let me show you a watered down version of the code I originally had.

     

    class Green : public ObjectEntity

    {

      //Yata yata

     

    public:

      void process() override

      {

        for(//for loop for x)

          for(//for y)

           {

             if(color == map.getPixel(x,y)) doThings();

           }

      }

        

    }

     

    The logic is simple. There's a for loop that covers all the x coordinates.

    for(unsigned int x=0;x < m.getXsize();x++)

     

    Then there's a nested for loop that runs through all the y coordinates.

     

    Now, how do we optimize this?

     

    To make it easier on you, I'm going to tell you about what you could use to fix this problem. I will give you a few hints.

     

    When you die, everything is re-loaded before you respawn.

    Blocks never move.

     

    Now, let me tell you the tool you would use to fix this problem.

     

    The Tool: Vectors

    Let me educate you on what a vector is in C++. A vector is in the standard library, aka the std:: part. If you know what an array is, well prepare to be amazed by the new and improved dynamic array. A vector is a dynamic array. What that means is, the elements in the array can be added and removed at any given time... Dynamically.

     

    The two methods you need to use here are these two here:

     

    push_back();

    clear();

     

    Push back is a method that adds an element to the top of the array. Clear is a method that clears the entire array.

     

    Vectors are a template class. This means you initialize them using angle brackets. You do this to tell the compiler what datatype the vector is going to store. This is very flexible. You can even store vectors within vectors to make a multi-dimensional array. Like this:

     

    std::vector<std:: vector<unsigned int>> vecTOR();

     

    So, you know your tools and you have your hints. Try to figure out how to fix this problem. And seriously, give it a shot. If you get stumped don't worry. Still try, you'll never learn if you don't make mistakes.

     

     

     

    Okay, either you figured it out and feel pretty proud, or you're stumped. Either way, let me explain.

     

     

    The Solution

    Let me break this down.

     

    One way to be efficient in problem solving is analyzing what you already know, and what you are currently trying to accomplish. If you are paying attention, you would know that the game is analyzing every coordinate in the map and getting it's pixel color. It then checks this pixel color to find out if it matches the platform color.

     

    Still nothing? Pay close attention to "coordinates". Remember the hint about how "blocks never move".

     

    Still nothing?

     

    Don't worry, this is why I made this forum post. You'll learn through time and experience.

     

    The solution is to analyze every pixel once to store all the coordinate locations where the platform blocks are located. That way, the for loops can loop through the arrays of coordinates instead of cycling through the entire map.

     

    Firstly, remember. When you die/load in the map for the first time, you can still analyze the entire map during that loading period. That way, the lag frames do not matter. During that loading period, you can dynamically add pixel coordinates that share the correct color. Once the loading is complete and the gameplay begins as normal, once you come in contact with a green block, instead of cycling through 10 million pixels and constantly having to preform boolean expressions using classes, you just have to loop through your vector, take the coordinates saved, and use the coordinates to access the specific pixel that has the platform blocks and preform the process normally.

     

    So this way, instead of doing 10 million instructions, you do at the very most 50,000 if you have a HUGE map. But most of the time, you should barely even crack 500 elements to cycle through.

     

    This is FAR from the actual way the code looks in the game. The code in my game is far more complex and complicated. So I'll just provide my solution to the code I've written for this example.

     

    class Green : bla bla

    {

      struct Ye

      {

        unsigned int x;

        unsigned int y;

        Ye(unsigned int x, unsigned int y)

          :x(x),y(y)

         {}

       }

     

    std::vector<Ye> pixelCoords();

     

    public

     

      methodWew()

      {

        for(Ye e:pixelCoords)

        {

          if(color == m.getPixel(e.x,e.y) doThing();

        }

      }

    }

      

     

    Wew bois. We did some big brain hours right there. Anyways, the logic here is, I made a struct that can hold the x and y coordinates. The vector stores all the coordinates that get loaded in during load time when the entire map gets analyzed for pixels with magenta or dark magenta. Now, each frame the game will check that vector and use those coordinates to get the pixel colors, check if they match a specific color, and do the things they need to do.

     

     

    Hopefully this opened your eye to the concepts of problem solving to optimize performance.

     

    Thanks for reading!

     

     

×
×
  • Create New...