Sign in to follow this  
rippingcorpse

[C++] Recommend me some small projects

Recommended Posts

Be warned, you may find this progression fairly steep. A true beginner also won't be able to make sense of all of this yet. It will all fall into place as you work your way through.

1) "Hello World", or as at least one game programming book calls it, "Game Over". Just output a message.
2) Get a line of text from the user and output it backwards. Try several approaches to the problem. Also try getting the "line" (probably only a word) from the command line arguments.
3) Prompt for two numbers and report the product. Add in all the appropriate error handling: for each number, repeatedly ask until you actually get a valid number. Read the standard input a line at a time for this, and ignore any "garbage" text that appears after a valid number on the line (but do complain about garbage at the beginning).
4) Guess the number.
5) Rectangle blitter: Ask for an x-position, y-position, width, height, and symbol, and draw a corresponding rectangle filled with that symbol onto the console. Assume that the first character you output will appear at the top-left of the console window; output enough characters to fill one screen of the console. You don't get full marks until you have robust error handling. Note: if part of the rectangle would be off-screen, make sure you only draw the on-screen part. (It is ok if none of it is on screen; just output a whole field of spaces.)
6) Mad Libs. Read an input file that contains placeholders marked by square brackets (you may assume there are no other instances of square brackets in the file). As you read not-enclosed text, append it to an output string. When you find a square bracket, read the text between the square brackets (it will be some kind of description, like "proper noun") and prompt the user to supply something of that sort. "Fill in the blank" by appending it to the output string. Once you reach the end of the file, output the whole output string.
7) Hangman. This isn't necessarily harder than Mad Libs, but it's more like a "complete game". Read in a word list from a file. Ensure that there are no arbitrary limitations on how many words there are, and pick a random word each game (make sure you are using the srand() properly).
8) Rectangle blitter II. Keep a buffer in memory of the desired screen contents. Ask the user several times to give rectangle coordinates and a symbol, and update the contents of the buffer, then redraw. You may also want to add a (platform-specific) call to make sure that the output lines up with the console window. Also, accept two symbols for each rectangle. Use the first to draw a border, and the second for all the "inside" spaces. The usual error handling standard applies here.
9) Mad Libs II. In this one, you are also responsible for designing the necessary changes to the input file format, and documenting them.
a) Provide some kind of escape syntax that allows the final output to have square brackets in it.
b) Provide a way to "mark" placeholders with an ID to indicate that they should reuse a common value. (When you're telling a story, you want to keep the protagonist's name consistent, for example.)
c) Do error checking to make sure that tags are properly closed. Your escape syntax needs to allow for square brackets in the descriptive text and in the ID for the placeholder, as well as anything else that might be ambiguous.
d) Parse the whole file before you start asking for text from the user. Find some structured way to hold the data as you parse it. If you encounter any error, report it and bail out. (If you are making proper use of the standard library, and/or have learned your stuff about constructors/assignment operators/destructors properly, the data representing the partially-parsed file should get cleaned up automatically.)
10) Rectangle blitter III. Now we are going to model "viewports" in addition to rectangles. A rectangle has a size (width and height), and data that is read from a file. A viewport has a size (width and height) and location (top and left). Write a function that draws a rectangle into a viewport, with a given offset. Use a structure to represent (x,y) coordinate pairs. An offset of (0,0) means that the top-left of the rectangle aligns with the top-left of the viewport; increasing the X offset moves the rectangle to the right, and increasing the Y offset moves it down. Any part of the viewport not covered by the rectangle should be filled with spaces. If the file data for the rectangle is too short, pad with '#' symbols (don't include any in your data files, so that you can see if this has happened); if it is too long, just ignore the excess (this should be automatic if you are doing things in a sane way :) ).
Design the user interface so that the user can create viewports and rectangles (providing all the necessary information for construction), ask for a rectangle to be blitted into a viewport, or remove a viewport (the interesting part: how will you know which one to remove? How will the user be able to tell you?). Only one rectangle should be blitted into a viewport at once: if another "blit rectangle into viewport" call is made, it should replace the existing contents. Figure out what happens if viewports overlap: which is drawn "on top"? Is it consistent? Explain and document the behaviour.
11) jwalsh's Project 2, from the C++ Workshop.
12) Create a representation of a directed graph structure. Make a node structure that represents a point in the graph. It should have a container of handles to the nodes that are reachable from here. Also make a graph class that simply holds a container of all the nodes. Write all the member functions for the graph that you think are useful for creating and modifying a graph. You should be sure that a node will never "duplicate" a connection to one of its neighbours, or point to a non-existant node, and that you never leak memory. Also make sure that your container choice in the graph class, and your handle choice in the node structure, will "work": i.e. a change to the graph should never cause any corruption to other nodes.

Write a function to determine how many separate "pieces" there are in the graph.




By this point, you should be more than ready to start looking at some basic graphical APIs.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
2) Get a line of text from the user and output it backwards. Try several approaches to the problem. Also try getting the "line" (probably only a word) from the command line arguments.



Am I allowed to look this up? I don't see how I would know this just after doing the "Hello World" program without learning some sort of reverse function or looking it up online.

Share this post


Link to post
Share on other sites
Learning things pretty much requires looking things up. I did say "try several approaches" for a reason. :)

There is such a reverse function in the standard library. It's also not difficult to do by hand, if you consider that a string is basically a sequence of characters. First figure out how to swap two characters, and then figure out how to use swapping of pairs of elements to reverse a sequence.

Share this post


Link to post
Share on other sites
How come the following code doesn't work?:

#include "stdafx.h"
#include <iostream>

using namespace std;

int main()
{
char cString[50];
char cTemp;

system("CLS");
cout << "Enter a string to write backwards: " << endl;
cin >> cString;

for(int i = 0; i < 50; i++)
{
cTemp = cString[i];
cString[i] = cString[i + 1];
cString[i + 1] = cTemp;
}
cout << "The string backwards is " << cString << endl;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by rippingcorpse
How come the following code doesn't work?:

*** Source Snippet Removed ***


Read Zahlman's signature. :-)

Specifically, use std::string instead of char[]. If you're going to learn c++, you might as well learn c++ (meaning the standard libraries, as well as the syntax). That's something that a lot of us could work on more, actually, myself included.

Share this post


Link to post
Share on other sites
Also, in general, you want to define "doesn't work": give the exact compiler errors (if you find you're getting dozens, post the first one – some problems have a tendency to cause a whole long chain). If you've cropped out code (which is good, so long as it's not done to excess), try to indicate where the line of code with the problem is (the compiler will tell you).

Share this post


Link to post
Share on other sites
Quote:
Specifically, use std::string instead of char[]. If you're going to learn c++, you might as well learn c++ (meaning the standard libraries, as well as the syntax). That's something that a lot of us could work on more, actually, myself included.

Using std::string is appropriate in "real" code, but when you're first learning a language, I firmly believe you should start with the very basics. I wouldn't trust a C++ programmer that couldn't handle raw pointers / memory management / raw string manipulation. That doesn't mean I wouldn't use std::string, std::vector etc in real production code, but when learning, get your hands dirty and learn the fundamentals. I.e., learn how to write your own std::string replacement, then throw out all your code and use std::string :).

Share this post


Link to post
Share on other sites
Quote:
Original post by emeyex
Using std::string is appropriate in "real" code, but when you're first learning a language, I firmly believe you should start with the very basics.

I actually agree with that... I didn't mean to imply that OP should only learn to use std::string. I only meant that as a hint to what might have caused the problem, though it did come across that way.

I think Zahlman's recommendation to try multiple approaches neatly includes both char* and std::string. :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by rippingcorpse
How come the following code doesn't work?:

*** Source Snippet Removed ***


Other than telling you "not to do that", the most obvious reason it wouldn't work is because you are trying to reverse the whole buffer, not just the string. Your buffer probably starts out unitialized, but just for the sake of example, lets say it starts out full of 0's:

cString: \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0...

Then you read the input:

cString: Test\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0...

Then you reverse it:

cString: \0\0\0\0\0\0\0\0\0\0\0\0...tseT

Then get nothing when you output because your string starts with a NULL. Alternatively, you print garbage until you get to the NULL terminator for the originally input string.

Share this post


Link to post
Share on other sites
No scratch that. On a second look it looks like you're reversing every sequential pair of characters rather than the whole string.

This concludes the example of why you should just use the standard algorithms when you can...

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
2) Get a line of text from the user and output it backwards. Try several approaches to the problem. Also try getting the "line" (probably only a word) from the command line arguments.


OK I did that...

Being the dumbass that I am, I thought the actual char array had to be reversed, so I spent some time doing that. I then remembered the real task and quickly did this:


int main()
{ char cInput[51];
int iStringLength;

system("CLS");
cout << "Enter a string to write backwards: " << endl;
cin >> cInput;
strlen(cInput);

for(int i= strlen(cInput); i>=0; i--)
cout << (cInput[i]);
cout << endl;

system("PAUSE");
}







Quote:
Original post by ZahlmanAlso try getting the "line" (probably only a word) from the command line arguments.


What do you mean by that? Also, how many approaches should I do and how diverse should they be? Should just try it with std::string as well as char?

Thanks for your help =)

Up to the rectangle blitter is easy for me right now, and I think that's just 2-dimensional arrays, so I was just unsure of this one.





PS: I read this in a thread in a sticky at the top of the beginner's section:

Quote:
Original post by STICKY * Find the 'input' section of the book or tutorial. Some courses will input text using a sequence of lines such as:

char name[number];

followed some time after by

cin >> name;

or

std::cin >> name;.

This is a bug (known as a buffer overflow: a common weakness in many programs and often exploited by hackers), and the text you are reading is encouraging unsafe behavior which can lead to unexpected (and dangerous) results.
What should I do instead?

Quote:
Original post by STICKY * Professional C++ programmers tend to use ++i instead of i++ whenever possible. If the latter form is overused, be wary.
What makes ++i better than i++?

[Edited by - rippingcorpse on February 3, 2008 11:59:02 AM]

Share this post


Link to post
Share on other sites
Blackjack is a good one since you get practice with multi dimension arrays,random,enums,sorting,etc.
You'd be suprised at how much you will have to know to write it if you haven't already learned about all the stuff above.

Share this post


Link to post
Share on other sites
Quote:
Original post by rippingcorpse
Quote:
Original post by ZahlmanAlso try getting the "line" (probably only a word) from the command line arguments.


What do you mean by that? Also, how many approaches should I do and how diverse should they be? Should just try it with std::string as well as char?


The command line arguments are what you type when you start your program from a console window.

Try this. First, figure out where on your hard drive the program .exe is.

Go to (I am going to assume you are on Windows, because people who use Linux and are also capable of getting anything done at all with it, generally know the equivalent stuff :) ) start->Run... and type 'cmd' (no quotes) and hit OK.

You should get a black-and-white console window with a prompt. The prompt indicates a "current folder" that the console is "in".

Use the command 'cd ..' to go up a folder, and 'cd {name of child folder goes here}' to enter a subdirectory. Find your program this way.

Use the name of your program as a command, to run it.

Now, when you write the code for your program, you have the option of capturing some information with a more complicated signature for the 'main' function. Observe the example:

test.cpp

#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
for (int i = 0; i < argc; ++i) {
cout << "command line argument " << i << " is: \"" << argv[i] << "\"" << endl;
}
}


Try it and see what happens. Now, try running the program, typing more words after the name (I assume you created "test.exe"):


C:\path\to\folder> test.exe foo bar baz
command line argument 0 is: "test.exe"
command line argument 1 is: "foo"
command line argument 2 is: "bar"


(Or at least, that's what I intend to happen. I typed that all off the top of my head!)




As for the different approaches:

Try reversing the actual string contents. Which pairs of characters should you swap? You need to be able to characterise this as a function of the length of the string. Keep in mind that the indices start at 0, and range to one less than the length of the string.

Try storing the text in a std::string object. (When you use the command line arguments, you can't just ask for std::strings; you'll have to create one from a char*. Fortunately, there is a constructor which does the obvious thing.) The swap will work the same way: std::string provides an operator[] which does the obvious thing.

Get a *line* of text, not just a word. The operator>> only reads up to any whitespace (including spaces and tabs). To read into a std::string, use the free function std::getline(). To read into the character buffer, use the .getline member function of the stream: thus, std::cin.getline(name of buffer, size of buffer). Notice how the string version does not require a size parameter, because it does not set a limit on line length.

When you "swap" characters in order to reverse the string contents, try doing it with the standard library algorithm std::swap.

When you do the reversal, try doing it by just calling the standard library algorithm std::reverse. [wink]

Those two algorithms come, naturally, from <algorithm>.

Quote:
Up to the rectangle blitter is easy for me right now, and I think that's just 2-dimensional arrays, so I was just unsure of this one.


Are you sure you know how to do the error handling for reading in numbers? I can assure you I will be testing it thoroughly. [grin]

You don't need any data storage (i.e. "2-dimensional arrays") for Rectangle Blitter I. You're intended to figure out something much more straightforward. Explaining more would be giving too much of a hint. [wink] The reason it doesn't come earlier is that you will have to think a little bit more. (Actually, maybe the string reversal is harder than I gave it credit for.)

You will need to know something about 2D arrays for Rectangle Blitter II, though. But you don't need to store an array of characters-to-output for each rectangle - only the one for the screen, where you know what size it is. That's for Rectangle Blitter III, and trust me, doing it properly is not as easy as it sounds. [smile] Once you have working code for RBIII though, you will understand a lot about how 2D platformer games work: just pretend your console is in fact a tiny 80x25 screen, with each character representing a different-coloured pixel.

PS: I read this in a thread in a sticky at the top of the beginner's section:

Quote:
What should I do instead?


Read into a std::string.

Quote:
What makes ++i better than i++?


Short answer: It's standard idiom for incrementing in a loop. It never hurts - except in some very tricky code where ++i isn't actually correct - and it can help.

Long answer: ++i means "add 1 to i, and tell me what i is now"; i++ means "add 1 to i, and tell me what i was then". In this case, we aren't paying attention to what we're being told - we only care about adding 1 to i - so it doesn't matter very much. In C++, though, it's possible that 'i' is not a simple number, but instead an instance of a class. In these cases, 'i++' can be slower, because the implementation (meaning, the code that explains to the compiler what 'i++' means for that particular class) has to "remember" the old value of i and then return it. In many cases, it's difficult or impossible for the compiler to "realize" that you don't care about this remembered value and to make the corresponding optimizations.

Share this post


Link to post
Share on other sites
Quote:
Original post by daviangel
Blackjack is a good one since you get practice with multi dimension arrays,random,enums,sorting,etc.
You'd be suprised at how much you will have to know to write it if you haven't already learned about all the stuff above.


I bet that stuff would of helped alot when I wrote my blackjack : /

Share this post


Link to post
Share on other sites
Quote:
Original post by emeyexI.e., learn how to write your own std::string replacement, then throw out all your code and use std::string :).


Last question for awhile, I promise...

Out of curiosity, is there a proper way to use char[] to create strings that would validly replace std::string and wouldn't allow buffer overflow?


Share this post


Link to post
Share on other sites
Quote:
Original post by rippingcorpse
Quote:
Original post by emeyexI.e., learn how to write your own std::string replacement, then throw out all your code and use std::string :).


Last question for awhile, I promise...

Out of curiosity, is there a proper way to use char[] to create strings that would validly replace std::string and wouldn't allow buffer overflow?


Yes. std::string is such a wrapper. It uses char[] internally. The problem is muuuch more complex than it seems at first.

And in C++, buffer overflows cannot be prevented due to nature of language. You can only provide reasonable protection from it.

Share this post


Link to post
Share on other sites
Quote:
Original post by rippingcorpse
Quote:
Original post by emeyexI.e., learn how to write your own std::string replacement, then throw out all your code and use std::string :).


Last question for awhile, I promise...

Out of curiosity, is there a proper way to use char[] to create strings that would validly replace std::string and wouldn't allow buffer overflow?


You could try reading this. It still only addresses the very basics of std::string functionality, though.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this