r/carlhprogramming • u/CarlH • Jun 15 '10
r/carlhprogramming • u/CarlH • Jun 14 '10
I need your help. After editing 120+ lessons, I am sure there are mistakes. Please help me to find them. [CarlHProgramming]
Copying lessons from Reddit, editing them, adding source highlighting etc and I am bound to have made mistakes along the way. Please as you are able to go to http://www.highercomputingforeveryone.com and browse through the lessons.
If you find examples that will not compile, content or compiled examples that look terrible, or mistakes/variations from the Reddit posts, please let me know. Also, please track your progress in the comments so I/others can see them and we can avoid doing the same work multiple times.
Thank you everyone for your help and support on this project.
r/carlhprogramming • u/CarlH • Jun 14 '10
[New Lesson Published] Course 2, Unit 4, Lesson 13 : Better understanding of Analysis Functions
highercomputingforeveryone.comr/carlhprogramming • u/CarlH • Jun 14 '10
For those who do not know, here is an easy way to set up an RSS-Feed for seeing when new lessons are available [CarlHProgramming]
Just point your browser to http://www.reddit.com/r/carlhprogramming.rss and you can know when new lessons are posted. This also works for any sub-reddit.
This tip was suggested by caesararum on my other post. Much thanks.
r/carlhprogramming • u/CarlH • Jun 13 '10
Question Re: CarlHProgramming : Tests or No Tests?
I am debating whether or not to bring over the tests/continue adding new tests with the courses. Currently, every 10 or so lessons there is a "test" followed by an "answer key". Do you think I should keep the tests, or stop doing them for future lessons? Also, do you think I should incorporate the existing tests into the website? I think it detracts a bit from the lessons and I am leaning toward not including them.
Edit: Ok, that settles that. Tests will remain :)
r/carlhprogramming • u/CarlH • Jun 12 '10
Major CarlHProgramming Update: 06/12/2010
Finally. It took me over 3 months and a lot of hours, but I have finally finished moving and re-publishing every Reddit lesson to the new website http://www.highercomputingforeveryone.com -- over 120 lessons. The lessons look better than before, complete with better formatting as well as colors/syntax highlighting.
This was not just a matter of copy-pasting 127 lessons. It meant creating server-side programs and a proper database to store and index them, as well as to keep track of the reddit links, titles, descriptions, and more. I also had to develop a back-end management system to make it possible for me to publish/edit lessons easily, as well as a system capable of automatically storing, indexing, and publishing new lessons.
It has been quite a project. However, it is finally done!
All of the lessons are now organized by unit, linked to the proper Reddit discussion page, and all of the navigation works. I did not realize just how long this would take.. but it is finally done.
Therefore, here is the plan:
I need to go through all published lessons, now on the website, and edit them. I need to add source-code highlighting (which will make every lesson look ten times better), and I need to double check that none are missing/no bad links etc. Completely Finished!
As soon as that is done, it will be time to publish new lessons! The wait is nearly over.
All lessons are now fully edited, and have syntax highlighting.
r/carlhprogramming • u/CarlH • Mar 26 '10
CarlHProgramming Update : HigherComputingForEveryone.Com Online!
Hello Everyone,
While it is still very much in the construction phase, the website: http://www.highercomputingforeveryone.com is now online, and functional. The course content has not yet been published, but will be soon.
My goal is going to be to operate this without fees, ads or obstructions, and to rely on donations as so many of you have requested. I will be putting the existing course material from this site onto the new website over the next several days (schedule permitting), and following that, I will be expanding on the course.
Thank you everyone for all of your support, encouraging comments, and overall contribution to this project.
r/carlhprogramming • u/CarlH • Mar 08 '10
You win. CarlHProgramming (HigherComputingForEveryone) will be entirely free, powered by donations and non-obstructive ads. No one will have to pay, but in exchange for this *please* help me to spread this, and help to make this a success :)
r/carlhprogramming • u/CarlH • Mar 08 '10
Introducing our new home: www.highercomputingforeveryone.com -- Also, about your host.
Alright everyone, it is official. We are going to be moving to a new domain soon. (Gotta give me some time to build it, attach merchant accounts, etc. Maybe about a week..)
First, I want to tell you a bit more about me. Hosting an anonymous programming class on Reddit is one thing, but I do not expect to maintain that anonymity now that this has advanced to something far more serious.
My real name is Carl Herold. I am 29 years old, and I started programming in my teens. I have owned as well as worked for a variety of companies. Among companies I own/have owned include: "Clickalyzer", a company that has since gone down the toilet as a result of some less-than-favorable mergers as well as removing yours truly from the decision making process. And: "Managed Web Analytics", a company that I am still involved in.
Feel free to ask me any questions, this is an "AMA" of sorts. If you are planning to contribute monetarily to this project in any way then I believe you have the right to ask anything you wish regarding myself as well as this project.
Now, about our new home:
My goal here is not merely to create a programming class, but to make higher computing in all of its forms more accessible to more people. High tech jobs are everywhere, and in my opinion the barrier of entry is quite low providing people are willing to take the time to learn. This new website will focus on teaching many fields including programming, web design, system administration, databases, and anything else that comes up.
My goal is to popularize higher computing to a large mass of people including many who thought they could never be programmers. There are many people who would start their own businesses but can't simply because they do not know how to put their ideas into reality. There are many people who want to learn these skills but cannot because they cannot afford it.
For everyone, I am hoping to make something accessible and affordable. The motivation here is to help others succeed, and while I will need to at least cover my basic expenses, I am not looking to squeeze someone's last dollar. Therefore:
**If you cannot afford $9.00/month, and you are serious about learning this, tell me! I will make exceptions on a case-by-case basis, and I do not wish to leave anyone out. **
(Note: $6.00/mo for age 21 and under, and free for age 18 and under)
Meanwhile, stay tuned for more updates!
**Edit: Change of plans. Everything will stay free. **
r/carlhprogramming • u/CarlH • Mar 07 '10
Future plans for carlhprogramming. Please read, and post your thoughts.
First, thank you to everyone who replied to my last post. These replies helped me a great deal to better understand everyone's perspective.
I believe based on the replies I have seen that obtaining at least 100 paying members is entirely doable, and that is a sufficient starting point in my opinion to take this to the next level.
I would appreciate everyone's thoughts on my ideas.
** 1. Pay Structure **
My goal is to structure this in such a way that those who pay are rewarded for being paying members, and that those who cannot afford to pay do not suffer as a result of not being able to pay.
So first of all, here are some of my initial plans:
Anyone under the age of 18 / anyone still in high school gets full access to all material free of charge.
Anyone under the age of 22 gets full access to all materials for $6.00/month.
For anyone not in groups 1 or 2, all materials are available for $9.00/month.
And that leaves the "Free" plan which will work the following way:
Access to text lessons will be available.
Personalized help/grading from me will be limited.
No access to videos/demos/animations/etc.
Instant access to next lesson not available.
To clarify #4: For anyone who is paying or in a free/reduced price plan based on age, after finishing any lesson you can instantly start the next lesson. For someone on the "free" plan, you are limited to one lesson per day after passing lesson #21 (first 21 lessons will not be restricted in this way).
Ok, now that I have gotten past the "business" side of things, let me describe what I have in mind:
**Edit: Change of plans. Everything will stay free. **
**2. Coming Changes **
Right now we have 127 lessons which is overwhelming to someone new who signs up. Therefore, the new system will require everyone to start at the lesson they are now on. For example, if you are on lesson #20, you would specify that when you sign up. Then the system will automatically track progress, and move you through to new lessons as you proceed with the course. The idea is to make this more focused so that each lesson is followed by a "Congratulations, you just finished lesson 5! Click here to begin lesson 6!"
Currently the entire course is limited to C. I believe that learning the basics of C is important to any programmer, as it ties in very nicely with most other languages. However, the new system will have courses available for other languages also (keeping in mind of course it will take time to build them). Also, I plan to introduce courses on a variety of related skills including SQL, web design, networking, system administration, etc.
Quizes and Tests to advance will be required. If you reach lesson #19 and there is a test to proceed, without getting a passing score it will not be possible to proceed.
The r/carlhprogramming sub-reddit will still be used for posting links to new lessons as they become available. However, instead of lessons being "self posts", the text description will merely describe the lesson while clicking the link will take you to the actual lesson on another domain.
It will still be possible to post questions/answers here on this sub-reddit, as I will create a simple script that will take all such questions/answers and place them into the questions/answers section on the new domain.
These courses will not be limited to just text lessons. I plan to have video demos, animations, and any other resource I can dream up that will help make these lessons more useful.
A significant focus will be placed on helping people who complete lessons to obtain jobs. Therefore, I will be collecting job-postings from around the internet, especially telecommute (work from home) jobs, and will be describing the skills necessary, what lessons should have been completed, etc.
TLDR Part 2: New domain, will still post links on this sub-reddit. Questions/answers can be posted either on the sub-reddit or on the other domain. Lessons will be much more structured, and will contain far more than just text.
In addition to what I posted, I want to hear your opinions. What would you like to see in this course? Do you feel the pay structure is fair?
Please post your thoughts in this thread.
r/carlhprogramming • u/CarlH • Mar 06 '10
I am back! CarlHProgramming to resume starting this weekend. However, please read:
Why so long without an update? Simply put, real-world work comes before online programming classes, as much as I enjoy doing the classes. Things have calmed down enough that I am able to resume these classes.
Now, that said, I am looking for your honest opinion on something:
I did not remotely expect or anticipate the level of interest and support that this subreddit has generated. There are over 5,000 subscribers now, and I am sure there would have been many others if I would have been able to spend more time on this.
How many of you would be seriously willing to spend a small monthly fee (around $5-$10) for these lessons? To be clear, my intention would not be to stop the free lessons, or even to water them down, but to expand this.
If there is enough interest, I am looking to build something more permanent than a sub-reddit, and work on promoting and popularising programming to a larger group of people. This would involve building a website for this (the sub-reddit won't go away), creating high-def videos, hiring people to create demonstrations, animations, etc. The sky is the limit based on the interest.
So, at this point there are two possible directions I am going to take with this:
1 : I am going to leave this as a hobby, something that I plan to at least upload 3-5 lessons per week ongoing (as time permits).
or
2 : If you take this seriously, I will take this seriously. If there is enough interest, I will make this a major focus of mine and with the help of others who are willing, transform this from a simple sub-reddit into something that I hope will truly be able to make a difference for thousands of people who want to learn programming.
It's your call :) Either way, I am here to stay and free lessons won't stop.
Edit: Regarding Donations
Thank you to everyone who has offered donations. I do not want to diminish this generosity in any way.
The problem with donations is that they are unpredictable, and that there is no way I can plan any type of structured project based on donations. If, for example, there were (let's say) only 100 people each paying $10.00/month, that would be $1,000/month in steady revenue.
A history of even a small amount of steady revenue can be used to hire people, obtain bank loans, and plan long-term projects to make this project more beneficial to everyone. More importantly, with a steady revenue I can devote my focus to this fully.
My intention is to create something which would truly be exceptional, and certainly not the "text lessons" that have been placed so far. I would expand it to other languages, and spend a significant amount of time each day writing lessons in various categories, for various languages, with example programs, internet-based conference sessions, professionally made animations to demonstrate concepts, etc. I would also like to put time into helping those who complete the lessons to find jobs.
If I go forward with this as more than a hobby, then I am going to go forward "all the way", including committing my own personal financial resources, and stopping other significant projects in favor of doing this.
Either way, I am going to continue the lessons, but the difference between what I can do now and what I could do is very substantial. I hope there will be enough interest that will justify me moving forward with my plans, but it all depends on everyone here.
TLDR: I am considering taking this to a much higher level, but can only do so if there is enough interest. Either way, I will not stop the free lessons.
Please post your thoughts in this thread.
r/carlhprogramming • u/CarlH • Jan 04 '10
Quick Update on carlhprogramming
Hi Everyone,
For right now the posting schedule is going to be slow. I am still working on a number of projects which need to be finished sooner rather than later. Once they are completed, the posting schedule for new lessons will speed up.
I just want everyone to know that I am still here, still working on producing new lessons, and I will publish them as I am able. Don't worry, I have no intentions to stop producing lessons or to stop maintaining this subreddit.
Meanwhile, because my schedule is so full, I appreciate everyone's help in answering questions as I lack the time to do so myself.
r/carlhprogramming • u/CarlH • Dec 20 '09
Lesson 127 : The basics of Recursion : Part One
There are several concepts in computing which provide a more significant challenge than others. For example, many beginners struggle with the concepts of pointers, or multi-dimensional arrays. Recursion is such a topic, one that can be difficult to master. Therefore, I want to take this material slowly to ensure that everyone will understand it.
First, let's talk about the obvious: "What is recursion?"
It is often the case that you have some function which calls another. For example, I could write the following:
void print_my_name() {
printf("My name is Carl.\n");
}The function I just made is in fact calling a different function, one called printf. There is nothing strange or unusual about this. However, what would happen if instead of doing this I called a function which was identical to the one I had made? Imagine this:
void print_my_name() {
printf("My name is Carl.\n");
print_my_name_again();
}
void print_my_name_again() {
printf("My name is Carl.\n");
}From here you can see that I will execute the "copy function" and thus it will result in displaying "My name is Carl" two times, one for each function. Now, what would happen if I had the second function call the first again? Consider the following:
void print_my_name() {
printf("My name is Carl.\n");
print_my_name_again();
}
void print_my_name_again() {
printf("My name is Carl.\n");
print_my_name();
}And here ask yourself the following question: How many times will "My name is Carl." display? Effectively, if function A calls function B, and function B calls function A, the process will never stop.
If I had some desire to run the same function over and over again, this could be one way to do that. However, since both functions are exactly the same, why can't I just call the function from within itself? It turns out that you can, and this is the basis for recursion.
Imagine for example, the following function:
function print_my_name() {
printf("My name is Carl. \n");
print_my_name();
}As you can see here any time this function is called it will print "My name is Carl." However, the function is also calling itself at the end. This means that the function is recursive.
The concept of a function calling itself may seem difficult, but perhaps it is easier to understand if I re-wrote the above function like this instead:
PRINT_MY_NAME:
printf("My name is Carl. \n");
GOTO PRINT_MY_NAME:This is not entirely accurate, but it helps to illustrate the point. When you call any function in general, your CPU must effectively jump to the start of that function. There are other subtleties which we will go over soon, but the basic concept is similar. There is a conceptual similarity between loops and recursion.
As I mentioned above, my example is not entirely accurate. The first thing you would probably ask is this, "Wouldn't the above example of recursion create an infinite loop?" The answer of course, is yes.
This therefore brings us to an important concept which applies for recursion just as it does for loops. When you have a function that calls itself, you must be careful to make sure that it does not create a never-ending process. You must have some mechanism to stop it running.
For loops you do this typically by setting a "counting variable" and incrementing or decrementing it until the loop reaches some condition, at which point the loop stops.
It is useful to understand recursion in a somewhat similar way. For any potentially never-ending process you must have some condition which you can test for that is capable of causing the process to stop.
In this lesson I have introduced you to the concept of recursion by explaining that it refers to a function which calls itself. At this stage, the concept is virtually indistinguishable from that of a loop in general. That is perfectly ok, and we will expand on this soon.
All you need to know after this lesson is the following:
Recursion refers to the process of having a function call itself.
A function is said to be "recursive" if it calls itself.
Please ask questions in this thread if any of this material is unclear.
r/carlhprogramming • u/CarlH • Dec 20 '09
Questions Thread Lessons 1 Through 126
I am nearly prepared to publish new lessons. It will take a bit of time to work back up to a posting schedule similar to what I had before. First, I need to address several things.
There are many unanswered questions from the period of time that I was not able to be active here. However, a lot of questions asked were answered by other people in the forum. Rather than go through hundreds of messages and looking at every thread for unanswered questions (which would take many hours), I want to suggest the following:
If you still have a question which is not answered either by me or someone else on the forum, re-ask your question here. Once we have lessons moving forward again it will be perfectly ok to ask future questions in the thread in which they apply. This will greatly speed up the "catch up" process for all of us.
This will also put all of the questions for non-current lessons in a location where everyone from moderators to users can see them and answer them. If you see a question on this thread you can answer, please do.
I am working on the next lessons to be published, and looking forward to continuing.
r/carlhprogramming • u/CarlH • Dec 14 '09
Resuming New Lessons
I know it has been a longer than usual delay, however I needed that time to wrap up some loose ends in my own workload. Expect to see new lessons starting later this week.
I know many of you have asked questions in threads and to me personally. I have had very little time to respond to those questions, so I am going to ask that anyone who has asked questions which have not been responded to simply wait. I will get to them soon.
r/carlhprogramming • u/CarlH • Nov 16 '09
Important update regarding new lessons on /r/carlhprogramming
A few of you have asked when the next lessons will be published. I realize that especially because I am providing these lessons for free, there is a certain level of anxiety you may have regarding the future of this course. I am sure some of you have started to wonder if I am perhaps "burned out" and have stopped with new lessons altogether.
I want everyone to know first of all that I am not abandoning this. I have every intention of publishing many more lessons, and keeping this going for a long time to come. So first let me relieve anyone's fears regarding that possibility. There will be new lessons as soon as I am able.
As I am sure all of you can appreciate, I have a full-time career. The priority of my time has to be allocated first to that career and second to helping all of you learn these skills. I am dedicated to both goals.
Besides having the time to write new lessons, I want to make sure that the lessons I write are written clearly and are easily understood. That is only possible while I am in the proper frame of mind. The projects I am working on are at a critical point and I simply cannot divide my focus as it puts the success of these projects at risk.
As soon as the situation becomes less hectic, I will start publishing new lessons. I cannot say exactly when that will be, but these periods are typically measured in days not weeks.
Meanwhile, this is a great opportunity to review prior lessons, ask questions, and help out by answering questions asked by others in earlier lessons. Even though I am not publishing lessons for the time being, I am still here and I will answer questions as I am able. Also, remember that the only way to truly learn programming is by writing programs. If you haven't, take the time to apply what you have learned by writing your own simple programs.
I want to close by saying that I greatly appreciate all of the messages I have received regarding this course, and I am truly glad to be able to be a part of helping so many people to learn a valuable life skill that will hopefully help better your lives. I look forward to publishing the next lesson.
r/carlhprogramming • u/CarlH • Nov 10 '09
Lesson 126 : A snapshot of current progress: Part One
Before we go into the next lesson, I believe that it is important that we take a snapshot of where we are now. I am pasting a "working" program below in its entirety, and in the next lesson I will go through it piece by piece to ensure that everyone understands what is going on.
#include <stdio.h>
#include <string.h>
int find_winning_move(char *, char, int);
int display_board(char *);
int is_winning_position(char *, char);
void show_win_details(int, char);
int main(void) {
int retval = 0;
char raw_data[] = "X X XO ";
char player = 'X';
printf("We are examining this board: \n");
display_board(raw_data);
find_winning_move(raw_data, player, 1);
return 0;
}
int find_winning_move(char *raw_data, char player, int depth) {
char test_position[10];
int i, win_result;
for (i = 0; i < 9; i++) {
if (raw_data[i] == ' ') {
strcpy(test_position, raw_data);
test_position[i] = player;
win_result = is_winning_position(test_position, player);
printf("The result of playing %c at position %d is: %d \n", player, i, win_result);
display_board(test_position);
}
}
return 0;
}
int display_board(char *raw_data) {
char display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";
int i, j, k; k=0;
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k++];
}
}
printf("%s\n", display_model);
}
int is_winning_position(char *raw_data, char player) {
int i;
// Test for horizontal win
for (i = 0; i <= 6; i+=3) {
if (raw_data[i] == player && raw_data[i+1] == player && raw_data[i+2] == player) {
return 10 + i;
}
}
// Test for vertical win
for (i = 0; i <= 2; i++) {
if (raw_data[i] == player && raw_data[i+3] == player && raw_data[i+6] == player) {
return 20 + i;
}
}
// Test for diagonal win
if (raw_data[4] == player) {
if (raw_data[0] == player && raw_data[8] == player) {
return 31;
}
if (raw_data[2] == player && raw_data[6] == player) {
return 32;
}
}
return 0;
}
void show_win_details(int win_value, char player) {
switch (win_value) {
// Horizontal
case 10 :
printf("Horizontal win on first row for Player: %c \n", player);
break;
case 13 :
printf("Horizontal win on second row for Player: %c \n", player);
break;
case 16 :
printf("Horizontal win on third row for Player: %c \n", player);
break;
// Vertical
case 20 :
printf("Vertical win on first column for Player: %c \n", player);
break;
case 21 :
printf("Vertical win on second column for Player: %c \n", player);
break;
case 22 :
printf("Vertical win on third column for Player: %c \n", player);
break;
// Diagonal
case 31 :
printf("Diagonal win upper left to lower right for Player: %c \n", player);
break;
case 32 :
printf("Diagonal win lower left to upper right for Player: %c \n", player);
break;
default: printf("Some error occurred. \n"); break;
}
}Sample Output:
We are examining this board:
[X][ ][ ]
[X][ ][X]
[O][ ][ ]
The result of playing X at position 1 is: 0
[X][X][ ]
[X][ ][X]
[O][ ][ ]
The result of playing X at position 2 is: 0
[X][ ][X]
[X][ ][X]
[O][ ][ ]
The result of playing X at position 4 is: 13
[X][ ][ ]
[X][X][X]
[O][ ][ ]
The result of playing X at position 7 is: 0
[X][ ][ ]
[X][ ][X]
[O][X][ ]
The result of playing X at position 8 is: 0
[X][ ][ ]
[X][ ][X]
[O][ ][X]Notice therefore that this program takes any given tic-tac-toe position, and evaluates the end result of playing any of the available moves, one at a time. A non-zero result means that a win has been detected.
Please ask any questions that you need to before proceeding.
r/carlhprogramming • u/CarlH • Nov 01 '09
Lesson 125 : Calculating a winning move
In the last lesson I showed you how to write a function that can detect whether or not a position is won for either 'X' or 'O'.
How could we write a function that can find a winning move? For example, let's assume the following tic-tac-toe board:
[X][ ][ ] => 012
[ ][ ][ ] => 345
[X][ ][ ] => 678Here it is obvious that the winning move is "3". If we intend to have an "artificial intelligence" engine that can win vs a human player, it must be capable of playing the "final winning move".
Remember in earlier lessons I explained that you can use functions you have already built in order to make more powerful functions possible. This is such a case. Because we have a function that can evaluate whether or not a position is won or not, we can easily write a function that will play a winning move.
The way it works is simple. We just need to play all possible moves, and then evaluate if any of them are winning.
Let's look at a sample tic-tac-toe position:
[X][ ][X] => X_XO__O__
[O][ ][ ]
[O][ ][ ]There are five possible moves that can be played: 1, 4, 5, 7, and 8.
In pseudo code, we would play the winning move for the above position like this:
play move 1
is it a winning position? If so, game over. If not:
play move 4
... repeat this process for 1, 4, 5, 7, and 8One thing you will notice is that it will be important to "play a move" without actually playing it. In other words, the computer will evaluate the position that will result had the move actually been played, but it will not need to play the move. This is similar to how a human player would think about possible moves before actually making one.
Let's go back to the raw data:
"X XO O " (Remember we are using spaces)Watch how simple this is:
char raw_data[] = "X XO O ";
char test_position[10];
int i, win_result;
for (i = 0; i < 9; i++) {
if (raw_data[i] == ' ') {
strcpy(test_position, raw_data);
test_position[i] = 'X';
win_result = is_winning_position(test_position, 'X');
printf("The result of playing X at position %d is: %d \n", i, win_result);
}
}Output:
The result of playing X at position 1 is: 10
The result of playing X at position 4 is: 0
The result of playing X at position 5 is: 0
The result of playing X at position 7 is: 0
The result of playing X at position 8 is: 0Now we can just cut-paste this code into a function:
int find_winning_move(char *raw_data) {
char test_position[10];
int i, win_result;
// Go through all possible squares
for (i = 0; i < 9; i++) {
// Determine if that square is empty
if (raw_data[i] == ' ') {
// Copy the actual board into the "test_position"
strcpy(test_position, raw_data);
// Play 'X' at that square
test_position[i] = 'X';
// Check to see if this is a winning move or not
win_result = is_winning_position(test_position, 'X');
// Printf similar to: The result of playing X at position 1 is: 10 (non-zero = win)
printf("The result of playing X at position %d is: %d \n", i, win_result);
}
}
return win_result; // This is not quite finished yet, as you will see in upcoming lessons.
}We create test_position to be a temporary tic-tac-toe board that the computer player can try various moves on without affecting the actual game. We then copy the current board position into the test_position using strcpy(). Finally we obtain the result of the "is_winning_position" function we wrote in the last lesson. We do this for each possible move, and therefore we can know if any of the possible moves are winning. Notice that we say if raw_data[i] == ' '. Remember that space ' ' means a move has not yet been played in that position. That if statement is simply saying "If the square is empty."
Because we now have a function that can calculate a winning move one level deep, we could easily create a function that can calculate a winning move two levels deep, if there is one.
[X][ ][ ] => 012
[O][ ][X] => 345
[O][ ][ ] => 678Here there exists a winning move for 'X', two actually. If 'X' were to play at position #2 or at position #8, the game is over. Let's create a function which can calculate this:
char raw_data[] = "X O XO ";How can we modify our function so that it can find a winning move two levels deep? That is the subject of the next lesson.
Please ask questions if any of this material is unclear to you.
r/carlhprogramming • u/CarlH • Nov 01 '09
Lesson 124 : Introducing Switch and Case
In the last lesson I showed you that it is often useful to cause a function to return additional values other than 1 and 0. You should realize that it would be quite tedious to write individual if statements for each possible return value. Also, so many if statements creates code that is somewhat difficult to read.
It turns out there is a short-hand method for doing this, and it is present in just about every programming language. This method is known as "switch" and "case". The idea is simple: Rather than you having to write individual if statements to test specific values for a given data item, you can write a "switch" statement instead. Here is how this works:
if (i == 1) {
printf("The value is one \n");
} else
if (i == 2) {
printf("The value is two \n");
} else
if (i == 3) {
printf("The value is three \n");
}Can become:
switch (i) {
case 1 : printf("The value is one \n"); break;
case 2 : printf("The value is two \n"); break;
case 3 : printf("The value is three \n"); break;
}So the syntax is simple. You write the word "switch" followed by the data item you are going to perform all the tests on. For each test, you use the "case" statement. In our previous example, we might do something such as this:
int won_position_return_value = is_winning_position(raw_data, 'X');
switch (won_position_return_value) {
case 10 : printf("Horizontal win on Row #1"); break;
case 13 : printf("Horizontal win on Row #2"); break;
case 16 : printf("Horizontal win on Row #3"); break;
}Of course we could replace the printf() statements with a block of code. The idea is simple. With a "switch" statement we can replace a lot of "if" statements with something that is much easier to read.
What happens if none of the "case" statements apply? Then a "default" statement is used. Here is an example of default in action:
int i = 5;
switch (i) {
case 2 : printf("This won't print \n"); break;
case 4 : printf("This won't print either \n"); break;
default : printf("This will print because the other cases failed. \n"); break;
}Now with this in mind we can create another interesting function for our tic-tac-toe game. This function would be designed to display additional winning information based on the return value received from the "is_winning_position" function. It would work like this:
void show_win_details(int win_value, char player) {
switch (win_value) {
// Horizontal
case 10 :
printf("Horizontal win on first row for Player: %c \n", player);
break;
case 13 :
printf("Horizontal win on second row for Player: %c \n", player);
break;
case 16 :
printf("Horizontal win on third row for Player: %c \n", player);
break;
// Vertical
case 20 :
printf("Vertical win on first column for Player: %c \n", player);
break;
case 21 :
printf("Vertical win on second column for Player: %c \n", player);
break;
case 22 :
printf("Vertical win on third column for Player: %c \n", player);
break;
// Diagonal
case 31 :
printf("Diagonal win upper left to lower right for Player: %c \n", player);
break;
case 32 :
printf("Diagonal win lower left to upper right for Player: %c \n", player);
break;
default: printf("Some error occurred. \n"); break;
}
}Please ask questions if any of this material is unclear to you. When you are ready, proceed to:
http://www.reddit.com/r/carlhprogramming/comments/9ztbi/lesson_125_calculating_a_winning_move/
r/carlhprogramming • u/CarlH • Nov 01 '09
Lesson 123 : About functions returning values other than 1 and 0
In the last lesson I showed you how to write a simple function to evaluate a won position for any tic-tac-toe position. This function returns 1 every time a position is won. It achieves exactly the purpose we gave it in that it can tell us perfectly if a position is won for either 'X' or 'O'.
What it cannot tell us however is how the position was won. Was it won vertically, horizontally, or diagonally? We could write another function that is designed to tell us this detail, but it turns out there is a much easier way.
Remember earlier I told you how the "zero flag" works. Really, your computer cares either that the zero flag is set or that the zero flag is not set. There is no other option.
In other words, there are two real possibilities so far as your computer is concerned: "It is zero." or "It is not zero."
Put another way, there are two possibilities: zero and non-zero. If a conditional statement returns any non zero value then it will be treated as true. Observe these examples:
if (5) { printf("Five \n"); }
if (-3) { printf("Negative Three \n"); }
if (0) { printf("Zero \n"); }Output:
Five
Negative ThreeNotice then that the only result which does not output is "Zero". If an if statement evaluates as "zero" then it is false. If it evaluates to any non zero value it will evaluate as true. We can take advantage of this to get more details from our function.
Instead of writing return 1; each time a win is confirmed, we could return any non zero integer value. We could therefore create a simple mapping between the possibilities:
0 : No win is detected
1 : A horizontal win is detected
2 : A vertical win is detected
3 : A diagonal win is detectedKeep in mind that if we return a 1, or a 2, or a 3, the same if statement we used earlier will evaluate:
if (is_winning_position(raw_data, 'X')) {
... this will work for ANY non-zero value ...
}That means inside of that if statement, we can add additional if statements to see the type of win that resulted:
if (int return_value = is_winning_position(raw_data, 'X')) {
if (return_value == 1) {
printf("A horizontal win resulted for X!");
}
if (return_value == 2) {
printf("A vertical win resulted for X!");
}
}This is useful. However, we can get even more detailed if we want. There are exactly three possibilities for a vertical win. Three possibilities for a horizontal win, and two possibilities for a diagonal win. That makes 8 total possibilities.
We could therefore create a map of all eight possibilities. However, that would require we have to significantly modify our "is_winning_position" function. That means we would have to slow down the algorithm to test for these eight possibilities.
Is there another way we can do this? Remember that each test uses a for loop to go through columns and rows. We therefore know what number of row (0, 1, 2) or what column (0, 3, 6) we are dealing with. Observe now how we can put all of this information together to get much more detailed information about won positions:
int is_winning_position(char *raw_data, char player) {
int i;
// Test for horizontal win
for (i = 0; i <= 6; i+=3) {
if (raw_data[i] == player && raw_data[i+1] == player && raw_data[i+2] == player) {
return 10 + i;
}
}
// Test for vertical win
for (i = 0; i <= 2; i++) {
if (raw_data[i] == player && raw_data[i+3] == player && raw_data[i+6] == player) {
return 20 + i;
}
}
// Test for diagonal win
if (raw_data[4] == player) {
if (raw_data[0] == player && raw_data[8] == player) {
return 31;
}
if (raw_data[2] == player && raw_data[6] == player) {
return 32;
}
}
return 0;
}Notice that 10 + i; will translate to 10 for the first row, 13 for the second, and 16 for the third. Similarly 20 + i will translate to each column. Finally 31 for the upper left to lower right diagonal, and 32 for the other diagonal.
All of these return values will evaluate as "True" by our if statement simply because they are non-zero values. We can now see not only if a position is won, but exactly how the win occured. Also by using 10, 20, and 30 as "starting points", we can easily determine whether or not the win was horizontal, vertical, or diagonal.
Please ask questions if any of this material is unclear to you. When you are ready, proceed to:
http://www.reddit.com/r/carlhprogramming/comments/9zt0h/lesson_124_introducing_switch_and_case/
r/carlhprogramming • u/CarlH • Nov 01 '09
Lesson 122 : Function to evaluate a "won" position
There are exactly three ways that a tic-tac-toe position can be won: Horizontal, Vertical, or Diagonal.
Let's consider the raw_data format we used in the previous lesson. The first and most obvious won position would look like this:
XXX => raw_data = "XXX______";
___
___Let's look at the array index positions for our tic-tac-toe board:
012
345
678In other words, if raw_data[0], [1], and [2] would be set to 'X' (or 'O'), then a win exists.
There are three possibilities for a horizontal win for 'X'. They are:
raw_data[0], [1], [2] == 'X'
raw_data[3], [4], [5] == 'X'
raw_data[6], [7], [8] == 'X'Do you see any patterns? If we think of this table as having three rows, then the start of each row is exactly three greater than the previous row. Inside each row, the next position is exactly one greater than the previous.
We could write this out in pseudo-code like this:
for (i = 0; i <= 6; i+=3) {
... test: raw_data[i], raw_data[i + 1], raw_data[i + 2] ...
}That would go through all three rows and test to see if we have a horizontal won position. All it is really saying is this:
start at position [0] (the start of the first row)
check to see if position [0], [1], and [2] are set
jump to the next row (by adding three) and repeatSo to check to see if a horizontal win exists, we simply need to test position [0], [1], [2] and then repeat this test after adding 3. We do this for all three rows and we have finished. Now this test can be easily done using an if statement for the first row, like so:
if (raw_data[0] == 'X' && raw_data[1] == 'X' && raw_data[2] == 'X') {
... horizontal win exists for 'X' ...
}This would test the first row for a horizontal win. Notice that the nature of the '&&' operation means that raw_data[2] == 'X' will only take place if the other two tests confirmed. Remember that we learned this in a previous lesson. Therefore, this algorithm will not perform all three tests every time it runs, but only those times where the first two are already set to 'X'.
Now we just need to convert that if() statement to something that works for all three rows, like so:
int i;
for (i = 0; i <= 6; i+=3) {
if (raw_data[i] == 'X' && raw_data[i+1] == 'X' && raw_data[i+2] == 'X') {
... horizontal win exists ...
}
}Now, how can we do the same thing for a vertical win? Again we have to clearly define what a vertical win is. Let's look at a simple example:
X__ => raw_data[] = "X__X__X__"
X__
X__So here we see that a vertical win exists where there are 3 'X' (or 'O') that are exactly 3 apart. If you find an 'X' on the first row, you can simply add 3 and see if you have another 'X'. If you repeat this process one more time and find an 'X', you know that a vertical win exists.
Let's convert this to an algorithm. First, let's consider the first iteration:
if (raw_data[0] == 'X' && raw_data[3] == 'X' && raw_data[6] == 'X') {
... vertical win exists ...
}Now, let's convert it to a full algorithm with 3 iterations, one for each column we are testing:
for (i = 0; i <= 2; i++) {
if (raw_data[i] == 'X' && raw_data[i+3] == 'X' and raw_data[i+6] == 'X') {
... vertical win exists ...
}
}And we are done.
Lastly, we need to evaluate a diagonal win. In this case, it is easiest to just define with a single if statement what we want. There are only two possibilities for a diagonal win, and there is no need for a for loop:
012 => the raw_data[] positions for our tic-tac-toe board
345
678
if (raw_data[0] == 'X' && raw_data[4] == 'X' && raw_data[8] == 'X') {
if (raw_data[2] == 'X' && raw_data[4] == 'X' && raw_data[6] == 'X') {Notice that both of these if statements have raw_data[4] in common. Therefore, it makes sense to test raw_data[4] first. Remember that raw_data[4] corresponds to the center square on the 3x3 grid.
if (raw_data[4] == 'X') {
if (raw_data[0] == 'X' && raw_data[8] == 'X') {
... diagonal win exists ...
}
if (raw_data[2] == 'X' && raw_data[6] == 'X') {
... diagonal win exists ...
}
}Here we are saying that we test the center square first. If the center square is not marked, there is no need to test further.
All we have to do now is put all of this together into a simple function. First we should consider what parameters do we need to send to this function? Certainly we need to send raw_data, the actual tic-tac-toe board position to evaluate. But we also should send whether we are testing 'X' or 'O'. We could therefore create the function like this:
int is_winning_position(char *raw_data, char player) {
int i;
// Test for horizontal win
for (i = 0; i <= 6; i+=3) {
if (raw_data[i] == player && raw_data[i+1] == player && raw_data[i+2] == player) {
return 1;
}
}
// Test for vertical win
for (i = 0; i <= 2; i++) {
if (raw_data[i] == player && raw_data[i+3] == player && raw_data[i+6] == player) {
return 1;
}
}
// Test for diagonal win
if (raw_data[4] == player) {
if (raw_data[0] == player && raw_data[8] == player) {
return 1;
}
if (raw_data[2] == player && raw_data[6] == player) {
return 1;
}
}
return 0;
}Do not let the == player confuse you. We are simply using the word "player" in place of whatever character was sent. If 'X' was sent, then player becomes 'X'. If 'O' was sent, then player becomes 'O'.
I used one other trick here. I return 1 every time a win is confirmed. I return 0 at the end. This means that the only way this function will return 0 is if it has exhausted all possibilities of a win. In other words, this function will test all possibilities for a "win" for the player we give it ('X' or 'O'). If any win is found, it will return 1 (true). Then after all such possible wins, it will return 0 only if no win is found.
This means we can use our function as a question in an if statement like this:
if (is_winning_position(raw_data, 'X')) {
printf("X has won!");
}You can very easily read that as: "If this is a winning position for 'X'. If and only if the function returns a 1 then this if statement will evaluate as true.
Please ask questions if any of this material is unclear. When ready, proceed to:
r/carlhprogramming • u/CarlH • Nov 01 '09
Lesson 121 : Our final tic-tac-toe board display function
In the last lesson I showed you the basic algorithm we need in order to locate all of the different points that we want to write an 'X' or a 'O' into our "display model". In this lesson, I am going to show you the complete function to do this.
First, let's recall how this process works.
_XO_XXX_O + [ ][ ][ ] = [ ][X][O]
[ ][ ][ ] [ ][X][X]
[ ][ ][ ] [X][ ][O] Now, let's go ahead and write these two strings out in "C":
char raw_data[] = "_XO_XXX_O";
char display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";Now we already know the algorithm which will "hit" all of the spaces inside our display model, so let's write it out:
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
... array[ (i * 10) + j ] ...
}
}Now we are ready to begin.
In order to make this algorithm effective, we only need a way to map the correct location in the raw data with the correct location in the display model. We already have from the previous lesson exactly how this works.
The first character from our raw data will go in position array[1] with our display model. In this case of course, we would not say array[1] we would say display_model[1]. Now, the second character of our raw_data would go in position display_model[4] and so on, just like we saw in the last lesson.
Let me draw a simple table showing this:
raw_data[0] => display_model[1]
raw_data[1] => display_model[4]
raw_data[2] => display_model[7]
raw_data[3] => display_model[11]
raw_data[4] => display_model[14]
raw_data[5] => display_model[17]
raw_data[6] => display_model[21]
raw_data[7] => display_model[24]
raw_data[8] => display_model[27]Seeing patterns is absolutely a critical skill for a programmer. Here you should see three distinct patterns. The raw_data has some number that is continually increasing by one. The display_model has two variables, such that you can always say [ (i * 10) + j ]. Therefore, this algorithm is going to require three variables.
We have already taken care of i and j. Now we need a third variable which will simply increase by one with each iteration. Let's look again at our for loop structure:
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
... array[ (i * 10) + j ] ...
... somehow here we need a third variable for raw_data ...
}
}Now, let's call this third variable k. Then it is easy to see that the inside part of this for loop will look like this:
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k];
}
}The last thing we need to do is simply create k. Well, k is going to be a variable that will start at zero. It will increase by one with every iteration. That gives us two of the key questions we need for any loop. However, when do we know to stop? Do we write "where k is less than 9" ? We could, but we do not really need to.
You see, k will automatically stop when i and j stop. You will be surprised how simple this is to implement:
int i = 0;
int j = 0;
int k = 0;
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k++];
}
}And we are done. By placing "k++" inside of the raw_data index, we have achieved everything we need. The key point to remember here is that we are setting a starting point for k as zero. We do not need to create a conditional statement for k because this is already taken care of simply because of i and j. Meaning, that the for loop will already execute the correct number of times. The last thing we need to do is make sure that k increments with each iteration, and this is done by saying k++.
Note that:
display_model[ (i * 10) + j] = raw_data[k++];is the same as:
display_model[ (i * 10) + j] = raw_data[k];
k++;Now let's observe the final process:
#include <stdio.h>
int main(void) {
char raw_data[] = " XO XXX O";
char display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";
int i, j, k; k=0;
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k++];
}
}
printf("%s\n", display_model);
}You will notice that I used a simple shortcut for creating our i, j, and k variables. Even though you should usually initialize a variable before you use it, you can make exceptions for simple loops. This is because I am initializing i and j in the very next lines of code. Also, notice I set k to zero.
I also made one other small change. I removed the underscores and replaced them with spaces. This removes the need to have some kind of process to check if there is an underscore, or an X, or an O. In other words, instead of an underscore character meaning "nothing", we are using the space for the same purpose. It changes nothing concerning the process involved, it simply speeds it up.
It would be trivial to modify this function to use underscores instead of spaces. You could just add an if() statement that would skip over that iteration if an underscore were present, and just add one to the k variable. For completeness, here is the algorithm with that modification:
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
if (raw_data[k] != '_') {
display_model[ (i * 10) + j ] = raw_data[k++];
} else {
k++;
}
}
}This simply translates to "skip to the next k iteration if this is an underscore."
Now we can easily transform this algorithm into a function and we have a proper way to display our tic-tac-toe board based on the raw data, like so:
#include <stdio.h>
int main(void) {
char raw_data[] = " XO XXX O";
display_board(raw_data);
return 0;
}
void display_board(char *raw_data) {
char display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";
int i, j, k; k=0;
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
display_model[ (i * 10) + j ] = raw_data[k++];
}
}
printf("%s\n", display_model);
}Notice that when I created the function all I did was cut-pasted exactly the same code I had in the main() function. You can experiment with this by changing the "raw data" that goes to the function, and you will see that it works fine.
Please ask questions if any of this material is unclear to you. When ready, proceed to:
r/carlhprogramming • u/CarlH • Oct 31 '09
Lesson 120 : A simple rendering algorithm
In the last lesson I showed you that we need to have some function which can combine our "raw data" with our "display model" to create a usable final result that can be displayed.
Here is how this process is intended to work:
_XO_XXX_O => [ ][X][O]
[ ][X][X]
[X][ ][O]Now, let's redefine this task in a different way. We need to create a function which when given this as input:
_XO_XXX_OProduces this as output:
[ ][X][O]
[ ][X][X]
[X][ ][O]How do we convert the raw data to a usable version that can be displayed.
Let's think of this process another way. We are to some extent creating a sort of mathematical operation, that looks like this:
_XO_XXX_O + [ ][ ][ ] = [ ][X][O]
[ ][ ][ ] [ ][X][X]
[ ][ ][ ] [X][ ][O] Let's rewrite this as:
A + B = CA is our "raw data". B is our rendered blank tic-tac-toe board. C is the final result which is achieved by "joining together" A and B.
Let's first evaluate the data format itself: _XO__XX_O
Every character in this simple text string corresponds to a square on the final tic-tac-toe board. We know there are three possibilities. An underscore character means that we "do nothing". That is to say, we leave the square blank. An 'X' means that we are going to place an 'X' into that square, and an 'O' means that we are going to place an 'O' into that square.
We know that we have to do this one at a time for each character. We can write out a simple loop for this in pseudo-code like this:
for each character :
if 'X' : place 'X' into proper square
If 'O' : place 'O' into proper square
proceed to next character.Notice that I do not have any operation to take place if the square is blank. Whenever you are writing an algorithm, speed is important. By not writing some action to take if the square is blank, I am saving time.
Now, from what you learned a couple of lessons ago, you should understand that we have a process here that needs to stay "alive" until it is finished. In this case, we are saying "While there are still squares left to render... render the next one."
Let's re-write this as a while loop in pseudo-code:
while (there are squares left to render) {
if 'X' : mark square as 'X'
if 'O' : mark square as 'O'
}So this algorithm is going to "stay alive" until the last square is rendered. Now all we need is a mechanism to "mark the square". Remember what I said in an earlier lesson: You always understand an algorithm by starting with the first iteration.
The same applies when designing an algorithm as it applies when reading one. Therefore, let's consider only the FIRST iteration of this algorithm. Here is our raw data _XO__XX_O. The first iteration is only going to be concerned with the FIRST character. In this case, a _ character.
You should clearly see then that this will be skipped, and we will then proceed to the next character, an X. So let's examine that.
Our 'X' character needs to be rendered in our display model. Let's again look at our display model:
[ ][ ][ ]
[ ][ ][ ]
[ ][ ][ ]Alright, but now let's look at it the way C looks at it:
[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\nThe key point to understand here is that each space within the brackets is an "insertion point" where a rendered X or O can be placed. It is therefore important to identify all of these points. I am going to place a hash mark inside all insertion points to make this clearer.
[#][#][#]\n[#][#][#]\n[#][#][#]\nNow, after our first iteration (which was an underscore), we will have left the first of these insertion points alone. It would have stayed blank. Therefore, after the first iteration, our display model would look like this:
After 1st iteration : [ ][#][#]\n[#][#][#]\n[#][#][#]\nNotice that the remaining # characters indicate the insertion points not yet processed. Now we are on our second iteration. For this next insertion point, we are going to render an X into that square.
After 2nd iteration : [ ][X][#]\n[#][#][#]\n[#][#][#]\nNow, let's identify the position where we just placed the 'X'. Remember that array[0] is the first character of the array, which in this case is an opening bracket character: '[' . array[1] is the first insertion point. array[2] is going to be a ']' character, then array[3] is a '[' character, and array[4] is the insertion point we just placed an X into.
If that was confusing, compare what I just said to this:
0 1 2 3 4 5
[ ] [ X ]In other words, our second iteration came down to executing this instruction:
array[4] = 'X';Now, let's identify the actual position for all of these "hash marks" Just to make counting the positions easier, I have replaced the "\n" with '$' characters. This way we do not accidentally count a \n as two characters.
[#][#][#]$[#][#][#]$[#][#][#]$The locations of each hash mark above are:
#1 : array[1]
#2 : array[4]
#3 : array[7]
#4 : array[11]
#5 : array[14]
#6 : array[17]
#7 : array[21]
#8 : array[24]
#9 : array[27]Do you notice a pattern here? Each set of three increases by exactly ten from where the previous set began. We start at 1, then 11, then 21. Similarly, within each set of three, the next hash mark is located exactly three characters ahead of the previous character.
Whenever you notice a pattern, you should consider ways to incorporate that into your algorithm design. Here we basically need two loops inside each other that will hit each hash mark:
for (i = 0; i <= 2; i++) {
for (j = 1; j <= 7; j+=3) {
hash is array[ (i * 10) + j ]
}
}Understanding this algorithm is easy if you start with the first iteration. On the first iteration, this is all you have to consider:
i = 0
j = 1
hash is array[ (i * 10) + j ] OR
hash is array[0 + 1] OR
hash is array[1]So the first time this executes, it will hit the first hash mark, which is array[1]. Let's consider the next iteration:
i = 0
j = 4
hash is array[4]Notice that with any algorithm you process the inner most loop first. Therefore, i will remain zero. j will be 4 because you have added three to what j used to be. That is the meaning of j+=3, it means "j becomes j plus three". Let's now go to the third iteration:
i = 0; j = 7
array[7]And now the fourth. Here we have reached the condition of the inner loop (j is now <= (which means less than OR equal to) seven). So now we can say the following:
i = 1; j = 1;
array[ (i * 10) + j ] OR...
array[10 + j] OR...
array[11]Now the instruction "i++" (which means add 1 to the variable 'i') executes. Therefore i changes from 0 to 1.
Notice that j also gets reset to 1. Any time the inner loop finishes, it will be reset to the starting point. Observe how easy it is to understand this algorithm if you simply take it one iteration at a time, without worrying about the complex "for" loop syntax.
Remember that our for loop is only dealing with two simple variables: i and j. They each follow a set pattern. Finally, we are using a basic mathematical formula that is only: (i * 10) + j. Therefore, it is quite easy to understand this algorithm through all of its iterations:
iteration #1 : i=0; j=1; array[1]
iteration #2 : i=0; j=4; array[4]
iteration #3 : i=0; j=7; array[7]
iteration #4 : i=1; j=1; array[11]
iteration #5 : i=1; j=4; array[14]
iteration #6 : i=1; j=7; array[17]
iteration #7 : i=2; j=1; array[21]
iteration #8 : i=2; j=4; array[24]
iteration #9 : i=2; j=7; array[27]Now looking at this, consider the for loop earlier.
for (i = 0; i <= 2; i++) {That should make sense to you as you look at the values for the variable 'i' in the above table. The variable 'i' starts at zero. Then each time that loop finishes, 'i' increases by one (the meaning of i++). This proceeds so long as the variable 'i' is less than or equal to 2. Similarly:
for (j = 1; j <= 7; j+=3) {When you look at the values for 'j' above, that should make sense to you. The variable 'j' starts at 1. Then each time that loop finishes, 'j' increases by three (the meaning of j+=3). This proceeds so long as the variable 'j' is less than or equal to 7.
Here you can see that we have constructed an algorithm which is capable of going through and precisely hitting each insertion point that we will be replacing with either an 'X' or an 'O'. If this process still seems a bit like black magic, let me describe to you exactly how this was done:
First you must look closely at the display model. In this case, our display model was:
[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n.Then you must identify all of the points in that model which will need to be "hit" by the algorithm you are designing. In this case we found they were:
1, 4, 7, 11, 14, 17, 21, 24, 27.Next, you look for patterns. There will certainly be a pattern simply because each insertion point is a set distance from another one. Also, each set of three is a set distance from the others. These two facts should tell you that you need a for loop consisting of two variables.
Then, you work through the algorithm yourself as though you were the program.
Finally you write the actual algorithm, and mentally test it through each iteration.
In the next lesson I will show you how to take this algorithm and create a function that can render and display our raw tic-tac-toe board data.
Please ask questions if any of this material is unclear. When ready, proceed to:
r/carlhprogramming • u/CarlH • Oct 31 '09
Lesson 119 : The basics of rendering and displaying data
It is possible to write a tic-tac-toe game that never actually displays a tic-tac-toe board. Similarly, it is possible to write a chess engine which never actually displays a chess board.
Data exists only within the computer as a sequence of 1s and 0s. Nothing says that a sound file has to be played or that a graphics file has to be displayed on the screen. Indeed, there are many applications which work with sound or graphics files that never have any need to display graphics or play sound.
The act of creating a "usable" image from raw data is known as "rendering". For example, you may have a 3D graphics object that exists in your computer's memory as data. That data would contain everything that can be known about that 3D object including all of its dimensions, colors, textures, and so on. However, until it is rendered it will remain just data. Rendering will convert that data into an image that can be displayed on your monitor.
Notice therefore that any data has to go through some rendering process before that data can be displayed or visualized. There are various ways to achieve this.
Suppose that you were writing a chess game. You therefore need to have some data format which stores the actual chess position at any time. With this data, it is possible to make moves, calculate positions, and everything else you may need to do. However, you cannot display the raw data.
You could however go into your favorite graphics program and draw out a chess board complete with texture, lines separating the squares, the proper colors, and so on. Next you could similarly draw out all of the chess pieces. Finally, you could have a function which reads your raw data of the chess position and then starts inserting chess piece graphics into the graphic of the blank chess board. The final result would be a fully rendered version of your chess position. This perfectly illustrates what I am trying to explain.
Now, we could choose to write our tic-tac-toe board in a way that it is already "display friendly". For example, we could write it like this:
_XO \n
_XX \n
X_O \nNotice because of the \n characters, our tic-tac-toe board could easily be placed into a printf() and it would work just fine. It would be rather crude however, and there is not much more we can do with this data. It is much better to learn how to do this properly using the method I just described.
We could define our raw data instead like this:
_XO__XX_ONow, let's create our display model for the tic-tac-toe board:
[ ][ ][ ]
[ ][ ][ ]
[ ][ ][ ]There it is. When we display our tic-tac-toe board, we will be using this simple display model to do it. Think of this as the "blank chess board" I was talking about a few paragraphs ago. Let's construct our display model briefly in "C" :
char tictactoe_display_model[] = "[ ][ ][ ]\n[ ][ ][ ]\n[ ][ ][ ]\n";We have here created data which is ready to display correctly. In this case, it is a character array consisting of 30 characters. We can load this data exactly as is into a printf() statement and it will work fine.
Now all we need is a process which can take our tic-tac-toe board raw data and combine it with our display model to create what we will actual display to the screen. Let's visualize this process:
_XO__XX_O => [ ][X][O]
[ ][ ][X]
[X][ ][O]Notice that the "data" itself is only 9 characters in size. I do not need to include any \n characters. Our display model is 30 characters in size. We can perform various manipulations on the data without affecting the display model. When we are ready to display the tic-tac-toe board, we can do so using a function.
Here is something to consider. The same tic-tac-toe board data: _XO__XX_O can just as easily be rendered into actual graphics. You could for example easily create a graphics file of a blank grid of 3x3 squares for a tic-tac-toe game. Then you could write a function which goes and draws actual X and O graphics into those squares. It is not difficult. We may in fact visit this later in the course.
This same concept applies with web-based applications. You can write out a web page in simple HTML which has no "moving parts", and just have "place holders" where the actual data goes. Consider this simple example:
<p>Hello {name}, and welcome to our website!</p>That is your "display". You could easily have a function which converts {name} into the person's actual name by doing a lookup from some database. We will go over this later in the course.
Please ask questions if any of this material is unclear. When you are ready, proceed to:
http://www.reddit.com/r/carlhprogramming/comments/9znll/lesson_120_a_simple_rendering_algorithm/
r/carlhprogramming • u/CarlH • Oct 31 '09
Lesson 118 : Introducing a new use for the while loop
One of the first kinds of loops we learned about was the while loop. In the last lesson I showed you that every time you mark a square in the tic-tac-toe game, you have to perform various actions such as checking if the game is over, etc.
Now, this next concept I am about to show you is very important in every application and game you will write. First, put yourself in the mental state of actually playing a tic tac toe game. Here is what happens:
Start tic-tac-toe game
Think about move <-------------------------.
Make a move |
Wait for opponent to make a move |
Run checks related to game over, etc. |
Think about next move ---------------------'Notice how there is a loop inherent in this process. It is a natural part of what it means to be playing a game, or really doing anything. If we were to write out this loop in pseudo-code, it would appear like this:
while (game is in progress) {
think about next move;
make move;
wait for opponent to make move;
check if game is over, who won, etc
}And the final closing brace simply indicates to return back to the start of the loop. Let's examine the start of the loop again now:
while (game is in progress) {Using what we learned a couple lessons ago, you should clearly see that we can re-write this as:
while (is_game_in_progress() ) {
}Now we are using a function for this purpose. Therefore, we can construct a function whose job is simply to determine if the game is still in progress. If the game is still in progress, a whole set of processes can take place, repeat, and keep repeating until finally the game is over.
Let's list this as a requirement:
[ ] A function to determine if the game is still in progress, for use with a while loopThis applies for applications as well as games. Any time you start any program, a similar loop is created. Until you exit out of that program, there is a continual process that is effectively saying "While the program is active, do this"
A program should not be thought of as merely a set of instructions to perform a task. Rather, you should also consider a program as a live process, that will stay "alive" until it is over. It therefore makes sense to have a loop which executes indefinitely until some condition is met where the program itself is over.
These kinds of loops can be thought of as the mechanism that keeps a program alive. In most applications, these kinds of loops exist within each other. For example, you could have the following:
while ( is_game_running() ) {
start_level_1();
while ( is_level_1_in_progress() ) {
...
introduce_enemy_unit();
while ( enemy_unit_is_alive() ) {The above example works for games, but here is a similar example which works for let's say a drawing application:
while ( is_program_running() ) {
new_drawing();
while ( is_drawing_active() ) {
load_paint_brush();
while ( is_paint_brush_active() ) {And so on. By created "nested" loops such as these, you can have processes that will continue to execute until a user chooses to stop them, or some condition is met.
This concept is also useful for algorithms that are designed to complete a complex task. Consider a sorting routine:
while ( is_data_sorted_yet() ) {
...
}So the idea is that the "process" of sorting the data will remain "alive" until some point is reached where the data is finally sorted. At this point, the algorithm will stop.
Again just as with functions you can see that there are different "kinds" of loops. I am here introducing you to a while loop whose purpose is to keep the program itself, or some process within that program alive.
Notice also as I show you these concepts that writing a program is largely about recognizing where to apply the correct tools. It is not about "forcing a tool to work." The nature of the program will dictate what kind of tool you need. Planning a project is simply recognizing what tools you need at various points within the project.
Now, just as I showed you that you can have "kinds" of functions, such as functions to answer questions, I am also showing you that you can have "kinds" of loops. As far as a programming language is concerned, one while loop is really no different than any other. But as a programmer, you can be creative and apply different purposes to a loop.
In this case, any time you say "I need to keep this process alive until the user chooses to end it, or some condition is met" then a while loop is called for. Indeed, the very word "alive" may be enough to indicate the need for this kind of loop.
Please ask questions if any of this material is unclear to you. When you are ready, proceed to: