Friday 15 December 2023

Dev Log // Fun Times With Github Copilot, GPT and Solitaire

So I had this idea to build Solitaire using as much AI as I could. This was after reading a quote from an engineer in a github article who said that he tried to use Copilot to build the entire app. I found that concept interesting.

I started using Copilot in October and at first found it fascinating. The way it could almost read my mind and provide me the exact code I was about to type makes me feel like I'm in the future.

I started off by having ChatGPT generate the class declarations for the game (but specifically no code). I would then paste these declarations into Visual Studio as comments and wait for Copilot to generate the code based on the comment. Then, I would create the functions, place my cursor in the blank function and wait for it to generate that code as well.

Dev Log // Fun Times With Github Copilot, GPT and Solitaire

It quickly got old and tedious. The code was not great. Copilot struggled on the more intricate parts of the game where classes started to really intertwine with each other and it would start making up variables or functions (even with all the relevant files open as tabs). It also struggled to create the graphical side of things, often suggesting code for SDL instead of SFML.

But most importantly; I had no idea what was going on. At all times, I felt like an engineer who had been hired to finish the game as the previous one who implemented everything had left abruptly. The further I got into the making the game, the harder it became to debug.

I ended up scrapping that version of the game and instead took the class declarations provided by GPT and started implementing them myself. I had a clear goal of what the finished game would look like and what I wanted to accomplish in each submit.


This is the way to use Copilot. I've never completed a game so quickly. When you know what you want to write and Copilot suggests it for you (or something very similar), it can shave hours off dev time. And that's not a hyperbole. The key though, is knowing what Copilot is suggesting you. If you can't read C++ or you're relying on it to know what it's suggesting is the right code for that particular section then you will quickly be led astray.

It's not the silver bullet, but it's pretty damn close and I highly recommend adding Copilot to your toolbelt.

As for Solitaire, I'm very happy to have finally created my version of it. It's one of those classic games I've dreamed of implementing since I started programming.

I used ChatGPT and Dall-e 3 to create the initial card designs and then edited them in PhotoShop to create a full deck spritesheet.

My favourite part of the whole process was figuring out how to do the classic "win animation" where the cards bounce down from the top of the screen, leaving a trail of the card behind them. This was the hardest part of the game and even GPT 4 couldn't help. Eventually, I asked some of the rendering wizards at work and they said the original solitaire used the mechanic of simply not clearing the screen after drawing so the previous frame was still there. This took some doing to get working in SFML as it has things in place to update the buffers anyway, even if you don't call explicitly call window.clear().

I ended up creating my own buffers when displaying the win animation, so only one buffer was ever drawn to and not cleared. Then that buffer would be turned into a render texture and displayed on the screen.

Solitaire Win Screen Classic Animation - C++ and SFML

This was also my first time using the command pattern to implement the undo feature. 

And that's my adventure with AI and Solitaire! It's pretty much got everything that I wanted to implement; undo, right click add to foundation, drag and drop single and multiple, selected card highlight and a status bar.


Solitaire Win Screen Classic Animation - C++ and SFML

What's wrong with it? A lot of hardcoded values. Good luck changing those card sizes or resizing the window and still expecting it to work...

Thursday 2 November 2023

Chapter 27 // Exercise 16 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022 and ISO C11 Standard.

Chapter 27 // Exercise 16

Use macros to obscure (simplify the notation for) the implementation in the previous exercise.


Of course the final exercise had to be creating some disgusting macros. And with that


I can't believe that was the final exercise. It's been 7 years. I bought this book back in January 2016 with no knowledge of programming (apart from some brief HTML back in '98) and now I've been programming in C++ for 7 years, 4 and half of them professionally; I get paid to make video games, it's crazy.

I'm going to spend a bit of time collecting my thoughts and then come back with a full review of the book. I think my title is going to be "Why you should learn C++ as your first language". I honestly don't think I would've wanted to learn C++ any other way now.

I've been feeling a bit nostalgic lately and going back over books I bought way back in 2016 and 2017 as well as reading my green text on the early exercises of P&P posted on here. I read a chapter 4 post and the memories of that night came flooding back to me. It took me 6 hours to write a function comparing the size of two ints. It was 3am and I was so frustrated I started crying. I developed a fear of bools. Its absolutely hilarious to me now as I sit here reading a random book, silently ripping apart the authors code because they stored an pointer to an enum.

My mantra at work is "git gud". I can relax a bit when I've "gitten gud", then I can "git gudder". I honestly believed I hadn't really changed at all but lately I've started to realise that I can "just do stuff now". 6 years ago I bought Programming Game AI by Example by Mat Buckland. I tried to read it and follow along with the code but it went completely over my head as I had no experience with inheritance and I was convinced OOP was evil (because I didn't want to understand it). Recently, I picked the book back up and not only implemented the code from snippets with no problem but changed it as I was going along, grumbling about the authors use of singletons and lack of interfaces.

2 years ago I read the online book Ray Tracing in one Weekend and attempted to multi-thread it. It was a disaster and no matter how many times I read MSDN or StackOverflow I just couldn't get my attempts to work. Earlier this year I had another go and got a hacky version working in an afternoon. It's not perfect but it worked and I just "knew" how to do it.

3 months after starting as an intern at Rare, I asked a senior in a catch-up "when do you stop feeling like shit?" and his response was "you don't, but over time it won't be as bad". I pressed him for an actual time for "over time" and he just laughed and said "3 years". It's been 4 years since I asked him that.

It took me a very long time to stop feeling like a waitress/receptionist and start thinking of myself as a programmer. 

Thank you Bjarne for giving me the tools to change my life. 

Wednesday 1 November 2023

Chapter 27 // Exercise 15 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022 and ISO C11 Standard.

Chapter 27 // Exercise 15

Simulate single inheritance in C. let each "base class" contain a pointer to an array of pointers to functions (to simulate virtual functions as freestanding functions taking a pointer to a "base class" object as their first argument); see section 27.2.3. Implement "derivation" by making the "base class" the type of the first member of the derived class. For each class, initialise the array of "virtual functions" appropriately. To test the ideas, implement a version of "the old shape example" with the base and derived draw() just printing out the name of their class. Use only language features and library facilities available in standard C.

Jesus christ, I had to get ChatGPT in for this one because I had no idea how start. What a load of faffing about. I used to think inheritance in C++ was confusing, well get a load of inheritance in C! It all kind of seems a bit pointless in C. 

I didn't go too far into this exercise, literally just creating the draw() functions for a shape and a circle. Shape can also be created, it's not abstract.

Tuesday 31 October 2023

Chapter 27 // Exercise 14 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022 and ISO C11 Standard.

Chapter 27 // Exercise 14

Write a function that takes an array of ints as its input and finds the smallest and the largest elements. It should also compute the median and mean. Use a struct holding the results as the return value.

Ah finally, a nicer "easy" one. This reminded me a lot of the exercises we did way back in chapter 4. God, that feels like a lifetime ago.

Monday 30 October 2023

Chapter 27 // Exercise 13 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022 and ISO C11 Standard.

Chapter 27 // Exercise 13

Write a program that does the equivalent of strings; cin >> s; in C; that is, define an input operation that reads an arbitrarily long sequence of whitespace-terminated characters into a zero-terminated array of chars.

I was a bit confused on this one as cin stop reading in characters when it encounters whitespace; have to use getline() to include the whitespace. So with the statement "define an input operation that reads an arbitrarily long sequence of whitespace-terminated characters" I decided instead he meant more of a getline() so we include whitespace characters. So if you were to type "this is a sentence", it captures the entire sentence and prints "this is a sentence". Maybe that's not what he meant though.

Sunday 29 October 2023

Chapter 27 // Exercise 12 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022 and ISO C11 Standard.

Chapter 27 // Exercise 12

Implement a (C-Style string, int) lookup table with operations such as find(struct table*, const char*), insert(struct table*, const char*, int) and remove(struct table*, const char*). The representation of the table could be and array of a struct pair or pair of arrays (const char*[] and int*); you choose. Also choose return types for your functions. Document your design decisions.

I originally did a really simple hash function however ended up with collision in the table quickly. I did some searching around and came across the terms "linear probing" where we keep going through slots to find a new one, wrapping round to beginning if needed.

The implementation isn't perfect but it'll do. For my design decisions:

Representation: I chose an array of struct pairs because it keeps the key-value pairs together, which makes it more intuitive.

Return Types: For find(), I return the int value associated with the key. If the key isn't found, I' return a special value, like -1.
For insert(), I return 0 if the insertion was successful and -1 if not (for example, if the table is full).
For remove(), I return 0 if the key was successfully removed and -1 if the key was not found.

Handling Collisions: For simplicity, I handled simple collisions only. This means the table has a fixed size, and if it's full, you can't insert more items.

Capacity: The table has a fixed size, which for this example, is set to 100. it will wrap round to find free slots but after that it won't insert any more.

Saturday 28 October 2023

Chapter 27 // Exercise 10, 11 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022.

Chapter 27 // Exercise 10

Make a list of C language features adopted from C++ or C with Classes (section 27.1).

Github: N/A

  1. Inline Functions: Initially a C++ thing, it lets you suggest to the compiler that a function should be inlined for performance.
  2. Single-line Comments: I believe // was first used in B, then brought back in C++ because /**/ is tedious.
  3. Variable Declaration Anywhere: Instead of only at the beginning of blocks, you can now declare variables anywhere in C, much like in C++.
  4. Mixed Declarations and Code: Kinda related to the previous one. You can intermix variable declarations with executable code.
  5. Boolean Type (_Bool or bool with stdbool.h): I was shocked the first time I tried to use a bool in C and found out it had to be added to the language in C89.
  6. Compound Literals: Lets you create temporary structures or arrays in the middle of an expression, similar to how you'd do in C++.
  7. Designated Initializers: A more expressive way to initialize struct or array members.
  8. Static Assertions (_Static_assert): Helps catch errors at compile-time based on constant expressions.

Chapter 27 // Exercise 11

Make a list of C language features not adopted by C++.

Github: N/A

Had to look these ones up. It was actually very interesting.
  1. Complex Number Support (_Complex and _Imaginary): C has built-in support for complex numbers, while C++ relies on the std::complex template class.
  2. Different Treatment of inline Functions: In C, an inline function's definition can be present in multiple translation units. In C++, inline functions have external linkage by default, but in C they have internal linkage.
  3. Allowing Implicit Function Declarations: Older versions of C allowed functions to be called without a previous declaration (not recommended, though!). C++ never allowed this.
  4. Named Address Spaces: Some C compilers for specific platforms (like embedded systems) support this feature, but it's not a part of C++.
  5. Non-constant Aggregate Initializers: In C, global and static aggregates can be initialized with non-constant values. C++ doesn't allow this.

Friday 27 October 2023

Chapter 27 // Exercise 9 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022.

Chapter 27 // Exercise 9

Using only C facilities, including the C standard library, read a sequence of words from stdin and write them to stdout in lexicographical order. Hint: The C sort function is called qsort(); look it up somewhere. Alternatively, insert the words into an ordered list as you read them. There is no C standard library list.

I could not get EOF to work in the slightest with scanf and ctrl+z. I decided to go with the qsort approach because no thank you to the list, so you have to enter the max amount of words to get it to quite the loop. Sometimes it would register the EOF, sometimes it wouldn't, sometimes I had to spam it on the keyboard and it would eventually register it.

Thursday 26 October 2023

Chapter 27 // Exercise 8 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022.

Chapter 27 // Exercise 8

What is the lexicographical order on your machine? Write out every character on your keyboard together with its integer value; then, write the characters out in the order determined by their integer value.

Ah finally, a nice "easy" one. Although I kind of cheated. I basically just looped through the ascii table from 0 to 255 and printed everything. I think maybe he wanted us to actually write a string and fill it with the actual characters on our keyboard but I have no idea how to get special characters out of my keyboard so I just left it to the for loop.

Wednesday 25 October 2023

Chapter 27 // Exercise 6, 7 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022.

Chapter 27 // Exercise 6

Change the representation of Link and List from section 27.9 without changing the user interface provided by the functions. Allocate Links in an array of links and have the members first, last, pre, and suc be ints (indices into the array).

I honestly had no idea what he meant when I read this so I asked ChatGPT to explain it to me like I'm 5. It was very helpful and I realised that what he wanted us to do was kind of create a vector where you can traverse the list via an index and then access the data at that index.

I had a stab at it for a couple of hours but honestly, my head just wasn't in it. I cannot stand anything to do with linked lists, never mind linked lists in C. So I left it half finished. The code I linked above kind of works but it also kinda doesn't.

Chapter 27 // Exercise 7

What are the advantages and disadvantages of intrusive containers compared to C++ standard (non-intrusive) containers? Make a list of pros and cons.

Github: N/A

I won't write an entire essay but from what I've seen intrusive containers would've been very normal back when C ruled the land. They're extremely lightweight versions of C++ templated containers, only you don't get the flexibility/generic-ness of the templated container but you get better performance. 

I suppose they would be useful in embedded systems where you know exactly what you're working with and have specific memory constraints. 

Tuesday 24 October 2023

Chapter 27 // Exercise 4, 5 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2022.

Chapter 27 // Exercise 4

If you didn't already, write a C++ version of the intrusive List example in section 27.9 and test it using every function.

This took me a good hour. I still hate linked lists. For this one I decided to make the list templated instead of Name storing a linked list. All the functions are now part of the list and I considered having it use a std::unique_ptr but in the end decided to just go with new and delete as the whole point of an intrusive list is to be as efficient as possible.

Chapter 27 // Exercise 5

Compare results of exercises 3 and 4.

Github: N/A

I think it's obvious that I much prefer exercise 4. I don't like having all the functions on their own, the classes aren't managing their own memory and the syntax to create new ones of different types is just hideous. 

Wednesday 27 September 2023

Chapter 27 // Exercise 2, 3 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and ISO C11 Standard.

Chapter 27 // Exercise 2

Complete the intrusive List example in section 27.9 and test it using every function.

This was quite a painful exercise. Mainly because I hate linked lists and they confuse me with their mPrev->mNext->mPrev malarky but this time I had to do it in C! C also just has so many parenthesis.

Chapter 27 // Exercise 3

"Pretty up" the intrusive List example in section 27.9 as best you can to make it convenient to use. Do catch/handle as many errors as you can. it is fair game to change the details of the struct definitions, to use macros, whatever.

So I turned the code into my usual style and found a bug? I'm not sure but I couldn't get it to run using the code in the book. In the main() function it needs to be struct Link* curr. I think he did that on purpose though as the for loop doesn't work otherwise because a List doesn't have suc as a member variable.

Apart from that, I didn't really bother with the other things.

Chapter 27 // Exercise 2 - Principles & Practice Using C++


Friday 22 September 2023

Unreal Free For The Month Jam // September 2023 - Escape The Palace Hall

What is Free For The Month Jam?? I explain it all here in great detail:

Basically, it's a game jam I made up where you have to use the current Unreal Free For The Month Assets to do, something.

It's called a jam instead of a game jam because you don't have to make a game. It can just be a simple mechanic. Whatever floats your boat.

This month I sat down and was actually able to complete my own jam for the first time since I started it almost year ago.

My entry this month came from ChatGPT which told me to create:

So that's what I did. And I made it into a video:


It's very basic, but I really struggle with finishing projects so I was proud I managed to get this to a packaged state and was happy to call it finished.

I ended up creating a very small game that requires you to find 2 items, pick them up and place them on pedestals to unlock the doors. If you don't do it within 60 seconds, you lose. It features a grab mechanic and a simple interact mechanic with the doors, as well as two trigger box events that cause spooky things to happen. I then added some sounds and music for ambience.

Keeping the scope small was really difficult and hopefully I'll be able to complete next months faster.

Monday 28 August 2023

Chapter 27 // Exercise 1 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and ISO C11 Standard.

Chapter 27 // Exercise 1

Implement versions of strlen(), strcmp(), strcpy().

I feel like I'm being punished. Please let me go back to C++, I swear I'll be good. 




Monday 24 July 2023

Dev Diary // FLTK & Tetris Part 2

A little while ago I had fun making Tetris in FLTK; a library not meant for games.

It worked perfectly except for the bad flickering that I thought was down to the fact that FLTK just wasn't designed to handle games.

Then today I was working (as usual), and I saw a some code in Unreal Engine called double buffer and a light bulb went off in my head. When using something like Direct X, you usually set up a swap chain, and a buffer and a second buffer and all that jazz because the whole point is to draw your next frame to an unseen buffer, then you swap the unseen buffer with the one currently being displayed; ad infinitum. 

I wondered if this was the actual issue and the flickering was being caused by screen tearing. Turns out, it was. I had a look at the FLTK documentation and they have a solution for this!

Fl_Double_Window is a type of Fl_Window, so seeing as how my Window wrapper is a wrapper around Fl_Window, I just inherited from Fl_Double_Window instead and voila! No more flickering; it just works™.

FLTK and Tetris using C++ - Using FL Double Window to prevent screen tearing

This made me very happy. It's very smooth now and it's actually got me excited for my planned Game Engine: Blink. What can I create now? I could do anything.

Thursday 20 July 2023

Chapter 27 // Drill 1, 2, 3 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and ISO C11 Standard.

Chapter 27 // Drill 1

Write a "Hello, World!" program in C, compile it, and run it.

The last time I did this, I used Visual Studio Code and had to set up my own build script and call it on the command line. I'm much lazier now and I'm just using Visual Studio Community.


Chapter 27 // Drill 2

Define two variables holding "Hello" and "World!" respectively; concatenate them with a space in between; and output them as Hello World!

I was a bit embarrassed that it took me a good 25 minutes to do this exercise lol. I got to "define 2 variables" and was like "how do string again??" I also got caught out by the missing terminating nulls and using strcpy instead of strncpy.


Chapter 27 // Drill 3

Define a C function that takes a char* parameter p and an int parameter x and print out their values in this format: p is "foo" and x is 7. Call it with a few argument pairs.

A little bit more what I'm used to. I absolutely despise that Unreal Engine uses printf so prolifically. I love cout << and I'm not afraid to say it.





Wednesday 19 July 2023

Chapter 26 // Exercise 12, 13, 14 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 12

Write a program that generates random floating-point numbers and sort them using std::sort. Measure the time used to sort 500,000 doubles and 5,000,000 doubles.

This was a fun little task and taught me how to create a function to create random doubles.


Chapter 26 // Exercise 13

Repeat the experiment in the previous exercise, but with random strings of lengths in the [0:100) range.

I'd already created a randString function many exercises earlier and added it to std_lib_facilities. So you can find that in the link at the top of the post. Creating the vectors took almost as much time as sorting them. Especially the second one. I watched the memory used jump to 1.1GB and it took a good 120 seconds to create the strings.


Chapter 26 // Exercise 14

Repeat the previous exercise, except using a map rather than a vector so that we don't need to sort.

I had to add an arbitrary value for each map entry. As its added sorted though, I timed creating the map. I found it weird though that sometimes, my strings would all start with a number; especially with 500000 strings created.

I also found it interesting that the map.size() was reporting 487,784 elements added when 500,000 were inserted. This meant that randString() created almost 13,000 duplicate strings; which is wild.

I could've used a container like Set, which only stores keys but the exercise said map. I also could've stored the strings as value and then sorted by value but then that defeats the purpose of a map.


This was much faster than the vector though, as it took 120 seconds to create the vector then the extra 80 to sort. However, I am missing a chunk of data due to keys being the same.

...

And with that, I'm done with Chapter 26! I honestly can't believe there's only 1 chapter left. It feels like a chapter of my life is coming to an end and I don't think I'm ready.

Tuesday 18 July 2023

Chapter 26 // Exercise 11 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 11

Time the sum example from section 26.6 with m being square matrices with dimensions 100, 10,000, 1,000,000, and 10,000,000. Use random element values in the range [-10:10). Rewrite the calculation of v to use a more efficient (not O(N2)) algorithm and compare the timings.

I literally had no memory of how to use the matrix code from Chapter 24 at all. It was practically a year ago for me at this point. It took me a while to figure out how to use it again and what to do.

row_sum needs to be implemented. After that I had trouble creating the random matrices of certain values as I kept getting bad memory allocations and I was only at a matrix of size 10,000. I'm pretty sure Bjarne did this intentionally, or he was using a super computer, as mine kept running out of memory trying to allocate values into the matrices. I did some quick calculations and realised this is because a matrix of size 10,000 x 10,000 is trying to allocate memory for 100,000,000 doubles. A double is 8 bytes, so we're roughly trying to allocate memory for 762 MB of memory in one go. For the next size up of 1,000,000 that would equate to 7.45 terabytes!

Yeah, Bjarne definitely did this on purpose. So instead of creating these large matrices, I decided to "simulate" the large matrix by just computing the sum. However, this is still very slow and will take forever past 10,000. 

Ultimately I don't believe there is a way to use a more efficient algorithm because summing all the elements in a matrix is O(N^2). All we can do is try and make the code more efficient like passing by reference or using multithreading.


Monday 17 July 2023

Chapter 26 // Exercise 9, 10 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 9

Add a text-based output format for the graphics interface library. For example, when a call Circle{Point{0,1},15} is executed, a string like Circle{Point{0,1},15} should be produced on an output stream.

For this, I didn't know if he meant output to the window (so a cout stream of sorts) or output it to a file (so ostream). So I decided on an output file based on the next exercise.

I used my "FLTK Engine" for this exercise again:

And added a simple call to output to a text file called DebugCommandsCalled. You can find this change in Window.cpp Blink::Window::onTextEnteredInCommandConsole().

Chapter 26 // Exercise 10

Use the text-based interface from exercise 9 to write a better test for the graphical interface library.

Github:  N/A

So we don't have any tests to start with for the FLTK code and I can't really imagine how using text files would be useful in the long run. I'd be much more inclined to add google tests to the project and start using that instead.

Sunday 16 July 2023

Chapter 26 // Exercise 8 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 8

Add a text-based interface to the graphics interface library from Chapters 12-15. For example, the string Circle{Point{0,1},15} should generate a call Circle{Point{0,1},15}. Use this interface to make a "kid's drawing" of a two-dimensional house with a roof, two windows, and a door.

So I cheated on that first graphics exercise back in Chapter 12 Exercise 7 and drew it in paint. Then loaded it as an image.

I had recently though, re-written the helper code from Bjarne into my own library of sorts (Adventures With Tetris) so going back to that messy, all over the place code from 2020 was jarring. Graph is so big now, if you make a change to it, compilation time is actually noticeable as everything includes Graph.h.

The re-write was the start of a planned FLTK Game Engine I named "Blink". You can find it here:
Apparently Blink is already the name of a HTML engine, however it's developed by Google, so it'll probably be dead in a few years.
(EDIT 09/10/2023 - I've now renamed the engine BLNK)

For this exercise I thought it would be useful to open a "console command" box when you hit a button on the keyboard. Like in Unreal Engine when backtick is pressed you can enter console commands.

This also seemed like a useful thing to add to the engine, so using UE for inspiration, I created a BasicInputBox which is a widget that takes in text and you can grab the contents of the box in various formats (int, string, double etc). I then added an instance of a BasicInputBox to a Window calling it a "CommandConsole". 

I then overrode Fl_Window::handle() to listen for keyboard events. When backtick is pressed it simply shows the widget, making it look like the console window has been opened. You can type text into it. Then with the focus still in that widget, you press enter and the callback function associated with the widget is triggered. The callback grabs what's in the box and uses it in someway. So for example, if you pass "r.drawCircle 100 100 50" to the Command Console, it draws a Circle at x100, y100 with a radius of 50.

Chapter 26 // Exercise 8 - Principles & Practice Using C++

I then got bored of the task as I really want to get this book finished...someday. And so I added a quick method for Images. "r.drawImage 100 100 house.png" draws the image specified in the last parameter at x100, y100. Mirroring what I did in chapter 12 exercise 7 all those years ago.

Chapter 26 // Exercise 8 - Principles & Practice Using C++

It's not perfect. I'd prefer to not have the window control what the command console does. A future task would be to send the info to a Console Manager along with the window. Using callbacks it can then call the appropriate callback, send the window in and the type can draw to the window. Or you can do something else, like change the colour of the background.

Saturday 1 July 2023

Chapter 26 // Exercise 7 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 7

Test the "simple text editor" from section 20.6.

I can't believe I did Chapter 20 almost 2 years ago now...I'm really slacking trying to get my way through this book.

Anyway, I went and got my code from exercise 6, chapter 20 and it no longer compiles for some reason. I had done nothing to it and I'm still using VS2019. It would appear that in the past 2 years, custom iterator classes need more definitions and I couldn't be bothered doing that. So I just re-wrote find_text to not use std::find.

I did a fair amount of testing. I didn't want to spend too much time on it though.

Friday 30 June 2023

Chapter 26 // Exercise 6 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 6

Modify the calculator from Chapter 7 minimally to let it take input from a file and produce output to a file (or use your operating systems facilities for redirecting I/O). Then devise a reasonably comprehensive test for it.

Chapter 7 is back; it's the gift that keeps on giving.

I already kind of implemented this back in Chapter 16 when we had to give this code some graphics using FLTK in C16 Exercise 9. I basically took the calculator code; did nothing to it except "fake" a cin buffer by creating an istringstream and passing the binary data directly to the cin buffer:
 string calculate(string input) 
 { 
     //put the input "into" cin 
     istringstream oss(input); 
     cin.rdbuf(oss.rdbuf());
    
     //now do normal calculator stuff as we have "characters in the buffer" 
     string answer = to_string(statement());
     //clean up token stream for next statement 
     ts.ignore(); 
     return answer; 
 }

Using this code (Exercise 9) I made it so it reads from from a text file that takes input per line, then compares it to the expected output from the next line and compares the two. I decided to just read everything in from one file instead of outputting to another file.

Amusingly, I used ChatGPT-4 to generate the test list and as I ran the tests it gave an incorrect answer for sqrt(pow(5,3)). it said it was 8.66 instead of 11.18. I've decided to leave that in so you can see a failure.

Monday 15 May 2023

Chapter 26 // Exercise 5 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 5

Add a test to the set of binary_search tests to try and catch the (unlikely) error of a binary_search modifying the sequence.

I was a bit confused by this as std::binary_search does not modify anything passed to it. The sequence must already be sorted (or it won't work properly). I tried googling for this and couldn't find any information on it. I then asked ChatGPT-4 and it said std::binary_search will not modify but could provide undefined behaviour if the sequence wasn't sorted.

I then thought that maybe, the predicate function you can pass to binary_search would be able to modify the sequence in some way however the variables are passed to the predicate by const so you would have to const_cast to change them which is considered very bad.

I then told Chat this and gave it the name of the book, the author and the exercise and it pretty much told me "you're reading into this too much, you're supposed to just write a test that shows it doesn't modify the sequence". Should've added "duh" at the end as well.

Once again, taking things literally and overthinking was not the answer.

So instead in TestAll I made a local copy of the sequence then added an if that checks if the sequence has changed after the binary_search was done. No new test needed.


Monday 8 May 2023

Ray Tracing In One Weekend // Making it Multi-threaded

So back in February 2021 I completed the online book; Ray Tracing In One Weekend. You can read my post (and review) on it here:
https://lptcp.blogspot.com/2021/02/ray-tracing-in-one-weekend-review.html

I originally wrote and executed the ray tracer on my previous computer; a 4 core intel 4790k. As the program is single threaded, it took 27 minutes to render a single 400x225 image with 100 samples per pixel. I attempted to do a 1k version but after 6 hours I stopped the program.

2 years later, I sat back down and decided now was the time to finally attempt to multithread it to speed it up. I actually tried to after writing the first post however, at the time, my programming experience was still a bit too limited and I just couldn't wrap my head around the concepts of multi-threaded programming. With an extra 2 years experience under my belt, I was able to get it done.

Code:

My attempt isn't perfect but it I'm happy with the result and I can improve on it from here. 

I initially did some very quick "fun with multithreading" exercises in the console window:

I'll probably make a seperate post on simple threading as the MSDN documentation is great but it's not great for someone with little experience and these are the types of examples I would've wanted 2 years ago (not lambda's operating on matrices).

Adding More Threads
So the main issue with just adding more threads to the ray tracer is the output method. It currently writes each pixel as a line in a text file which is saved as a PPM. This means that cout <<  is accessing a single text file every time a pixel is calculated.

If you add more threads, cout is not thread safe and the threads will fight with each other to access the text file and data will be overwritten/jumbled up.

A simple fix for this would be for a thread to lock access to the text file while it's accessing it, then unlock when it's done. This would prevent corrupted data. However, threads spun up by a for loop do not guarantee any kind of order so whereas all the pixels would be calculated correctly, the picture would still be a jumbled mess.

My solution was to therefore split up the picture into "tiles" or "chunks". I was inspired by Blender's cycles renderer which renders a tile at a time. If you choose to render with your CPU, it will use a core per tile and you can see it working on X-cores at a time.

Using std::thread::hardware_concurrency(), I allowed the program to spin up as many threads as it can. Each of these threads then writes pixels to a fixed-sized 2D array. Each thread writes to a certain portion of the array so they aren't overwriting each other. To visualise, if the image is 500x500 and using 4 threads, then thread 1 would render pixels x0-x249 and y0-y249:


Then, once all the threads have have finished, we then go through the vector array of pixels and write them out to a file to create the image.

I ran this new code on my new pc; a 16-Core AMD 3950x using the same width and pixel sample as the old pc and it completed the image in 2 minutes (vs 27 on a single core). It outputs it upside down but that can be easily fixed:

A 1K version took just over 7 minutes; the power of multithreading!

My original solution to this used 4 hardcoded threads that wrote to their own text files and then once they were finished, I stitched the files together. However, I completely forgot how PPM files worked and my chunks wouldn't stitch together properly. Using an array bypassed this problem.

My next task will be to transfer the output to the screen using a GUI library like FLTK or SMFL so you can see the tiles being created in real-time. 

Tuesday 18 April 2023

Dev Diary // Using ChatGPT to make an Idle Clicker Game

There is an idle clicker game called Cookie Clicker. It's amazing, you click a giant cookie, to make more cookies, to buy buildings and upgrades that will make cookies. There is a grandma apocalypse, a dragon called krumblor and ascensions. Kittens can give you milk multipliers which boosts your cookies per second. The entire goal is to make as many cookies as possible per second. It is utterly addictive and completely free:

Cookie Clicker was first released back in 2013 and I started playing around 2015. Soon after release, the creator made a website: Idle Game Maker, which turned the cookie clicker code into an engine and allowed users to make their own idle game. It's really intuitive and easy to use; and you can host your game for free using their website.

Whilst messing around with that engine recently; I realised a lot is hidden away from the user. Being an engine programmer, I wanted to know more about how clicker games actually function but I have next to no knowledge of web development; enter ChatGPT.


The above video is me sitting down with Chat and trying to get it to create the bare bones of an idle clicker with as little coding from me as possible and I'm amazed at the results. I filmed for 50 minutes and by the end of that I had a clicker game with 2 buildings and a lucky button that appears randomly. I edited about 3 lines of code in total but used ChatGPT to generate everything for me. Even asking it to move CSS elements to different places.

I don't think I would continue trying to get it to create the entire game as that would get a bit tedious; but now I've got the bare bones, I've got a solid starting point to tinker with. I would probably start making it look prettier first before adding anything else.

HTML, CSS and Javascript are completely outside my zone of knowledge but having looked through the generated code; the html and JS is actually pretty readable and easy to add to. The CSS on the other hand will require some more thought.

You can find all the code generated in this session here:

Monday 17 April 2023

Chapter 26 // Exercise 4 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 4

Devise a format for test data so that you can define a sequence once and run several tests against it.

I honestly did not understand what he meant by this at first. I guessed that we had defined the test sequence
{ testName value { sequence } testResult }
and so he wants us to be able to define any test sequence like:
{ testName { sequence } value testResult } 
or even
{ testName } { value } { sequence } { testResult }

So in this case I decided to make an enum that held each part of the sequence:

Then, the user could just create a vector<TestSequences> and pass through whatever sequence type they want like:

I then made the functions into a class that held the sequence type, so it could check it whilst using operator>>. I then used a switch statement to define what to do for each part of sequence.

All you have to do then is create a TestSequence, give it a type, set the sequence type and then load in the text file.

It does rely on there being spaces though. Without the spaces, the entire line will be read in however, I imagine that that would be a major "you must do this when writing tests" line in the documentation for creating tests.

Sunday 16 April 2023

Chapter 26 // Exercise 3 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 3

Repeat exercise 1 with the version of binary_search that takes a comparison criterion. Make a list of new opportunities for errors introduced by that extra argument.

I continued using the code from exercise 2 and created a new testAll function called testAllWithPredicate. This takes in the input stream and a function pointer. I then modified testType to take in function pointer and used some std library comparison functions found in <functional>:

Sunday 9 April 2023

Chapter 26 // Exercise 2 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 2

Modify the testing of binary_search to deal with arbitrary element types. Then test it with string sequences and floating-point sequences.

I decided on the rule that you can't have tests that included wildly different types like string and floats. Binary search requires that your elements are sorted, if one element is "cheese" and the other "3.4", how do you sort that?

I then tried to do it so the the same file could read in string tests, followed by int tests or floats. But doing compile time checks on what type the stringstream was reading into became a bit long winded, so I just created 3 seperate text files and fed them into the code.

Then it was just a matter of slightly modifying operator>> overload so it could handle any type. I did this by just reading everything into a string. If it hit '}', I put that character back into the stream then converted the string into the necessary type via istringstream.

Sunday 19 March 2023

Chapter 26 // Exercise 1 - Principles & Practice Using C++

In this exercise I'm using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 26 // Exercise 1

Run your binary search algorithm from section 26.1 with the tests presented in section 26.3.2.1.

I started off writing the function and following his bullet points and it had 3 distinct sections; getting the middle and comparing, then seeing if the middle was less or more than. I then got deja vu because knew I had seen this somewhere before in the book/done it before. And so I went looking through the other chapters and sure enough, I found the info I was looking for back in Chapter 21, page 795.

This then triggered a memory of realising how a binary search is actually implemented and I went back through my posts to this one:

Here we were tasked with writing a binary search for a vector, and I was a bit shocked to see my binary search I started implementing was exactly the same as the one I did 2 years ago. I even used the same std::advance and std::distance calls to get the middle iterator. 

Thanks to these tests though, I did find a bug in my code from that exercise, in that if there is only 1 element in the container, and the value we're looking for is more than the contents of the middleElement iterator; it would go into another binary search and eventually overflow. So I checked the distance was more than 1 before doing that.

Tuesday 14 March 2023

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

A colleague introduced me to the YouTube channel javidx9 the other day with the video:

I sat down after a gym session one dreary monday night and the 36 minute video took me about 90 minutes but javid had delivered and there was Tetris in the console window in about 300 lines of code. I also really enjoyed the little maths trick he employed to rotate the tetromino pieces. I found the video to be a bit rushed in places and some things cut out so I had to refer to the github repo quite a bit. Some things also went unexplained and me from a few years ago would be quite confused but on the whole; a solid tutorial.

Tetris was on my list of games to clone as it's a classic, easy-ish to implement and rife for tinkering. And tinkered with that initial small program I have.

Console Window
Here is the repo for my "all-in-main" version that I wrote whilst following along with the video. It's not exactly as his code but close enough:

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

++Console Window
I then set about taking this apart and creating a more generic Tetris that could eventually be run using any library. This one still runs in the console window but the input options, rendering, tetromino mechanics have been abstracted to work regardless of what library you're using....in theory.

FLTK
This is a small lightweight API  that I was introduced to whilst working my way through Principles & Practice. I actually really like it due to it's simplicity and Windows 95 looking graphics. This was the first test to see how portable I'd made my code in the previous exercise.

I started off modifying the wrapper code given in the book Programming: Principles & Practice by Bjarne Stroustrup. I've been meaning to do this for a while; it's not a perfect wrapper but it makes iteration in FLTK a bit faster.

Here's the repo:

With that done, I then found a free Tetris block png off the internet:

I used GIMP to change the hue of it to create 6 other colours.
Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

I then created a simple window with a quit button.

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

Now I needed to find a way to display the Tetris Board on the window. At this point I already had all of the code needed from the console versions so I created a grey block and wherever '#' is drawn, I told it to draw a grey block instead.

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

Next was to draw the current piece. This required some tweaking but after some trial and error I managed to get it working without having to expressly tell the individual blocks to draw to make up the shapes (it used the text created in the console versions).

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)


I then started copying over all the update logic to move and rotate the pieces. I was extremely surprised that this "just worked". FLTK does have it's own Keyboard event handling system however, the default windows one worked just fine with it so I stuck to that instead of changing it.

To create the "game loop", I used FLTK's timing system and registered a "tick" function with it. The tick function updates the Tetris board then redraws it. The tick function also handles updating the game tick counter to regulate tetromino speeds and locking them in place:

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)
Please ignore the flickering; FLTK and my screen recorder don't get along.

The only thing left after all this was to print out the score:

Dev Diary // Adventures with Tetris (C++ Console Window & FLTK)

And with that I got bored and got the itch to do something else. I will come back to this though as I'd like to do it in SFML next, add sounds and such. I was happy I managed to get a "game" of sorts working in FLTK though as that library is not built for games....and it really shows. It was fun creating helper classes though. I'd like to know why it's flickering so much once the screen gets really full. I think it'd be a good task to delve into Visual Studios performance profiling and debugging options.

EDIT 25/07/2023
I fixed the screen flickering: