Here you will find suggestions for programming projects, roughly sorted by their difficulty (in each level projects will be sorted roughly by difficulty too). You can use this to practice what you've learned in [c tutorial](c_tutorial.md), try to follow the [LRS](lrs.md) principles. We are kind of assuming you'll be programming these projects in [C](c.md) -- that's how we judge the difficulty etc. -- but of course no one is stopping you to make the project in another language if you so desire :)
**LRS programming challenge!** If you want you can treat this as a [game](game.md), kind of achievements you can collect. You can even make a git repo for your solutions so others can see and admire them { I'll be glad if you send me a link. ~drummyfish } Here are the rules:
- If you complete all projects in level *N*, you can automatically consider all projects of all lower levels completed as well, i.e. if you complete level 2, count yourself whole level 1 and 0 as well.
- A project is considered completed only if you really complete all the requirements! It is not enough to say "mmm, I could do this if I wanted" -- no, you have to REALLY DO IT to count. If the requirement is to make a complete game, a buggy demo doesn't count. Also if you just use some cheat, use 100 libraries to do everything for you, you know you didn't really complete it :) Just be honest with yourself.
- You CANNOT award yourself partial points, i.e. if you meet 90% of requirements for some project, you CANNOT give yourself 90% points for it, not even one point. Complete it 100%, then get 100% points. Again, it doesn't count to say "mmm, I could finish this if I wanted" -- no, until you finish it, it's not finished. This is part of the challenge and insisting on it also makes you potentially make a nice, tidy program that will increase good in the world ;)
- You may reuse your own code without it counting as third party library, i.e. if you write 3D renderer in one project, you can use it in writing 3D game as another project, with it counting as if you wrote everything from scratch just for that project.
- Don't [cheat](cheating.md), you're only cheating yourself :)
2.**counting**: Make a program that outputs numbers from 1 up to 100.
3.**guess a number**: Make a game in which the computer secretly thinks a number from 0 to 9 and the player guesses the number. The computer then says if the player won and what the secret number what.
4.**password generator**: Make a program which when run outputs randomly generated password (the password must be different each time you run the program of course). The password must be at least 10 characters long, contain at least one decimal digit and one special character.
5.**average**: Make a program that reads two numbers (you can assume only non-negative integers will be input) and writes out their average (it can be rounded, even to just integer, e.g. 3 and 8 can give 5).
2.**[anagram](anagram.md) checker**: Make a program that reads one line of text from the user and checks if it's an anagram (i.e. if it's spelled the same forward and backwards) or not -- you can just output *yes* or *no*.
3.**number [encyclopedia](encyclopedia.md)**: Make a program that writes number from 0 to 1000 (including both) and about each of which it writes some facts. These facts have to include at least the number's square, square root, sum of its decimal digits, its [binary](binary.md) representation, prime factorization and whether the number is [prime](prime.md), perfect number and [Fibonacci](fibonnaci.md) number.
4.**[brainfuck](brainfuck.md) interpreter**: Make a program that interprets brainfuck. You may choose to read the input program either from standard input or from a file (the file may have some hardcoded name, e.g. your program will just look for a file `program.bf` in the same directory). If the brainfuck program is invalid or runtime error occurs in it, you may just write out `error` and halt your interpreter. Thumbs up for making the interpreter nicer, e.g. allowing to pass input file name as a CLI argument, reporting more details about errors (e.g. its position in source code) and so on.
5.**[game of life](game_of_life.md)**: Make a program that simulates game of life on a finite *N * N* grid, with wrapping (i.e. a cell on the very left of the grid is considered a neighbor of the cell on the very right in the same row, same thing with top and bottom). Make *N* configurable at least as a compile time option, draw the world as [ASCII art](ascii_art.md) to terminal, make the user step forward by pressing some key. You can initialize the grid values randomly, but thumbs up for allowing setting the initial world state (e.g. reading it from a file or something).
6.**text adventure**: Make an interactive [CLI](cli.md) text adventure that will take an average player at least 10 minutes to finish. Part of game mechanics must involve inventory, i.e. picking up items, carrying them around and using them.
7.**calculator**: Make an interactive calculator -- it can be a purely [command line](cli.md) program into which user types expressions and your program evaluates them. The functionality must be at least on the level of the most plain physical calculators, i.e. it doesn't have to parse whole complex expressions, but it should be able to add, subtract, multiply, divide and find square roots. Results can be approximate, showing just 3 fractional decimal digits. Thumbs up for more features like handling expressions with brackets, converting between bases and so on.
8.**[bytebeat](bytebeat.md)**: Make at least two cool sounding bytebeat songs.
1.**[chess](chess.md) without AI**: Make a program that allows two human players to play chess, AI is not required. It can be just a CLI program that draw the chessboard to terminal and reads moves by having players type the squares. Of course the program mustn't allow illegal moves, it must know if the game ended, who won (or if it's a draw) and so on. Implement all rules correctly, i.e. don't forget en passant, castling rights and so on. Time controls are not required at all. Thumbs up for some basic recording of games, undos, showing playable squares or even having some kind of stupid AI (can just make random moves).
2.**2D game**: Make a complete 2D game in which you control a character, with at least 5 levels. Genre is up to you, recommended is e.g. platformer or top-down shooter. Sounds are not required but thumbs up if you have them. If you want, you can try [SAF](saf.md) for this.
3.**[gopher](gopher.md) browser**: Write interactive gopher browser -- it can be a purely [command line](cli.md) browser. It has to be able to follow links and go back at least one page. The program must include some basic help and ability to save files to disk.
4.**simple text [compression](compression.md)**: Write a program that can compress and decompress plain [ASCII](ascii.md) text files using some very simple technique like [run length encoding](rle.md) (RLE) or dictionary methods (you can even use a fixed dictionary, e.g. have a list of common English words that you will represent by some shorter symbols). You can assume input characters will only have 7bit ASCII codes, so you can compress the text also by dropping the 8th unused bit. You don't have to achieve great compression ratio (you can even enlarge some files), but you must pass the following test: take the program's source code, this article's plain text and Wikipedia main page plain text, your program must compress at least two of these to a smaller size (and of course successfully decompress them into identical files). The program must work as a [filter](filter.md), i.e. it mustn't load the whole file into memory, it has to use approximately same amount of RAM for input of any size.
5.**stupid chatbot**: Make an entertaining chatbot that can react to basic sentences like "how are you?", "are you a robot?" and so on. It must give a human-like answer to at least 20 different sentences. It has to deal with typos and text variability a little bit and has to have some kind of memory (for example it can remember the name of its chatting partner). Test the bot by having it chat with itself.
6.**arbitrary size [rational numbers](rational_number.md)**: Make a library that allows working with arbitrary size rational numbers, i.e. represent each number as a pair of numerator and denominator, the number will be automatically allocating itself as much memory as it needs for storing the two numbers. It mustn't waste too much memory, i.e. whenever it changes, it will try to reallocate its memory and decrease its size if possible. Size of the number will only be limited by amount of RAM your program can use. Furthermore implement these operations with the numbers: converting to/from the language's native numbers (with rounding if necessary), comparisons (equal, greater, greater or equal, smaller, smaller or equal), addition, subtraction, multiplication, division and printing and/or converting the number to string (at least decimal -- if the number has infinitely many fractional digits, just cut it somewhere).
7.**image to [ASCII art](ascii_art.md)**: Make a program that takes an RGB bitmap image and renders it with ASCII characters (i.e. prints it out to console). You can support loading the image from just one file format of your choice, possibly something simple like PPM, BMP or Farbfeld. The program must support resizing the image and it must allow to just set one dimension with keeping the aspect ratio.
8.**educational [sorting](sorting.md) visualization**: Make a program for visualizing sorting algorithms -- it may draw real graphics (either directly to the screen or by outputting animation file) or just render ASCII art graphics, but it has to clearly show what the sorting algorithm is doing, i.e. which elements are being compared, which are swapped and if it makes good sense to highlight something else (like the pivot or already sorted part of the array), you should do it. Implement at least bubble sort, insertion sort, selection sort and quick sort. Also offer benchmark mode in which all algorithms race in sorting the same array (this can be without advanced visualization, just show e.g. number of steps for each).
9.**3D model of [fractal](fractal.md)**: Make a program that outputs 3D model of either Sieprinski triangle or Koch snowflake fractal. The output shall be some simple 3D format like obj or Collada. The model can be primitive, i.e. it can be just flat shape made of triangles which don't have to really be connected, but the program must allow specifying the number of iterations of the fractal (during invocation, e.g. as a CLI flag). Check that the model is correct by opening it in some 3D editor such as Blender.
10.**[sudoku](sudoku.md) solver**: Create a program to which the user somehow passes a sudoku puzzle (in a file, through a CLI flag, interactively... the choice is yours, but passing a new puzzle mustn't require program recompilation) and the program attempts to solve it. It must first employ some basic reasoning, at very least it has to repeatedly try the elimination method, i.e. marking a set of possible values in each empty square and then reducing these sets by crossing out values that can't be in that square because the same value is in its column/row/minisquare -- wherever only one value remains in the set, it is filled in as final; this has to be repeated until no more progress is being made. If you want, you can employ other techniques as well. After this if the puzzle is still not solved, the program will resort to [brute force](brute_force.md) which has to eventually lead to solution (even if it would take too long). If the program finds that the puzzle is unsolvable, it has to report it.
1.**non-trivial [programming language](programming_language.md)**: Design language *L* and make an interpreter for it. *L* must be [Turing complete](turing_complete.md) and you have to provide mathematical proof of it. *L* must allow [recursive](recursion.md) function calls. It must not support native [OOP](oop.md). *L* must be usable for programming very basic things -- show it is so by writing [bubble sort](bubble_sort.md) in it. Write [quine](quine.md) in it.
2.**radiation hardened quine**: Without looking it up, write radiation hardened [quine](quine.md) in some language. Quine is a program that outputs its own source code (don't cheat, you can't read it from the source file), radiation hardened quine is a quine that remains a quine if you remove any single character from the program.
3.**3D game**: Make a complete game with 3D graphics from 1st or 3rd man perspective that will have at least half an hour worth of gameplay time -- the gameplay can really be 2D (e.g. like [wolf3D](wolf3d.md)) but the graphics must be judged as 3D by average guy who sees the game. If your platform allows it at all, it must have basic sounds (no need for music, but e.g. shooting should at least make beeps and so on). The genre is up to you, it can be a shooter, platformer, RPG or anything where you control a character moving through 3D world. For the 3D graphics you can either use a 3D library, in which case you HAVE TO implement textured graphics (the textures may be [procedural](procgen.md) if you want), or you can write your own renderer. If you write custom renderer, then if it's a "true 3D", it can have just flat, untextured graphics; if it's a "[pseudo 3D](pseudo3d.md)" (like raycasting or BSP, ...), it must have at least some texturing (e.g. walls).
4.**textured 3D [software renderer](software_rendering.md)**: Make 3D software renderer that rasterizes triangles (just like for example [OpenGL](ogl.md)), with texturing. Affine texture mapping (i.e. the easier, incorrect texturing by linear interpolation of texturing coordinates in screen space) will pass, but thumbs up for perspective correct texture mapping. Implement some basic [shading](shading.md) like, e.g. Goraud with ambient and diffuse light. You have to handle visibility even of non-convex shapes, e.g. with z-buffer or at least approximately by sorting triangles. It's enough if you can display some textured model with setting camera position and rotation somehow. You don't have to handle any 3D formats, 3D models can just be passed as arrays of numbers. It is enough if you output static images e.g. to a file, but thumbs up for being able to handle real-time rendering, animation and having extra features like transparency, scene graph and so on. Extra thumbs up for not using [float](float.md).
5.**[regular expression](regex.md) library**: Make a library for working with regular expressions. Implement at least the following operations: search of regular expression, substitution of regular expressions WITH capture groups and generating random strings by regular expression.
6.**[chess](chess.md) [AI](ai.md)**: Use any sane approach to write a chess engine of reasonable strength. No, you can't just fork stockfish, write it from scratch. It has to support xboard or UCI interface, the strength must be such that it beats [smolchess](smallchesslib.md), Maia 1500, GNU chess, Dreamer, Stockfish or similar engine in a 10 game match with both engines having equivalent settings (search depth, time for move etc.); alternatively it can pass by getting stable rating over 1600 on lichess or by beating someone with FIDE rating over 1500 in a 10 game match. You get the idea.
7.**bitmap image editor**: [GIMP](gimp.md) is bloated! You have to save us by writing a GUI image editor that's at least a bit more advanced than the original MS paint. It has to be able to save and load images (supporting just one format is enough), draw basic shapes (at least a line, rectangle and circle), copy/paste parts of the image (with rectangle select), resize the image as a whole (with scaling it), have fill bucket and adjust brightness and contrast of the whole image. It should be reasonably user friendly, i.e. upon quitting it should ask if you want to save the work etc. Thumbs up for extra features like filters (blur, invert, edge detect, ...), layers and so on.
8.**64K intro**: Make an impressive [demoscene](demoscene.md)-style 3D intro with music that's at least 1 minute long and fits into 64 KB. It has to be good enough so that an average demoscener would approve it as not completely laughable.
9.**3D [path tracer](path_tracing.md) without [floating point](float.md)**: Write a path tracer (NOT a mere [ray tracer](ray_tracing.md)) without using floating point. It can only produce static images that may just be saved to a file in some simple format (no need to draw real time animation to the screen). It must be possible to position and rotate the camera arbitrarily and to set its field of view. It has to support several shapes of objects in the scene: at least a sphere, plane and cylinder, and it must support transparent objects. Thumbs up for supporting polygonal models, depth of field and loading scene description from a file.
10.**[gopher](gopher.md) fulltext search engine**: Create a whole search engine (with crawler, index creator, user frontend, ...) for the gopher network. It can store its database just to flat files (no need to use SQL or something like that). It has to allow at least very basic fulltext search, i.e. about each gopher site you'll have to remember which words it contains (and possibly their count), so that if the user searched e.g. for `cats dogs`, you'll give him sites that contain both of these words somewhere in their text. Besides this you can make simplifications (ignore case, don't support Unicode, special characters etc.). Thumbs up for additional features like creating a graphical map of the crawled gopherspace along the way.
1.**3D [physics engine](physics_engine.md) without [floating point](float.md)**: Warm up for the god tier by making a 3D physics engine without using floating point, usable in real time. It must support complex shapes, i.e. not just plain spheres ;) The engine can use rigid body or soft body physics, or both. It doesn't have to be physically accurate but should produce results that an average observer will judge realistic enough for a game.
2.**[operating system](operating_system.md)**: Make a whole [self hosted](self_hosting.md) operating system with your own custom kernel, with basic [GUI](gui.md) and tools such as a text editor, file browser and programming language compiler. Throw in some games because without them your OS will be boring. Run the OS on real hardware. It doesn't have to support networking, sound, USB and similar bloat, but thumbs up if you manage even that.
3.**[MMORPG](mmorpg.md)**: Make both client and server for an MMORPG game. The game has to support 3D graphics (but can also have 2D frontends) and have some basic lore that makes sense. Remember, it is MASSIVELY multiplayer game, so you have to be able to handle at least 1000 players connected at the same time on some kind of affordable computer. There must be chat, PvP and PvE combat. Thumbs up for releasing it all under [CC0](cc0.md).
4.**[Python](python.md)**: Implement the Python programming language, INCLUDING its whole standard library. Bonus points for finishing before the version you are implementing stops being supported.
5.**ruin [bitcoin](bitcoin.md)**: Make a program that can mine one bitcoin by running for at most one minute on some consumer laptop released before year 2010. Warning: this is probably unsolvable, but if you solve it you may help save the planet :P
Here are some questions to test your LRS related knowledge :D
1. What's the difference between *[free software](free_software.md)* and *[open source](open_source.md)*?
2. Name at least 10 different [programming languages](programming_language.md).
3. Why is text written on a piece of paper flipped horizontally when viewed in a mirror -- why is it not flipped vertically?
4. Say we want to generate a random number from 0 to 999 (including both) with uniform probability distribution (i.e. every number is equally likely). In C we often do it using the modulo operator like this: `int num = rand() % 1000`. However there is a problem with this -- describe what the problem is and how its negative effect can be reduced. Hint: it's called *modulo bias*.
5. What's the difference between [data](data.md) and [information](information.md)?
6. Bob has written a program and died. The program is now [unmaintained](maintenance.md). Bob's program uses 10 libraries. The probability that the API of one such library will be [updated](update_culture.md) and changed in any given year is 5%. If this happens, Bob's program will stop working. During the next 5 years what is the probability of his program breaking?
7. What will the following C (C99) snippet print out? `int x = 2; putchar('a' + ((1 == 3 > 2) + ++x));`
8. Order the following software by the date of the release of their 1.0 version from oldest to newest: [TempleOS](temple_os.md), [MS DOS](dos.md), original [Unix](unix.md), [Linux](linux.md), [Windows](windows.md). Also point out which one stands out from others and why.
9. If you're running in a race and overtake the guy who's currently in third place, what place will you be in?
10. We have two gears, each of same size and same number of teeth. Gear A is fixed in place, it can't move or rotate, gear B runs around gear A so that it keeps touching it (and therefore rotates along the way) until it gets to the place where it started. How many revolutions around its own axis (from your stationary point of view) has gear B made?
11. What's the worst socioeconomic system in the world? You don't even have to say why because that would take too long.
12. Manually convert the [binary](binary.md) numeral 10110000000010110101 to hexadecimal.
### Answers
1. Though legally similar (but not identical), free software is a movement based on ethics and pursuing freedom for the software user, open source is evil business movement that avoids talking about ethics, it was forked from free software and is solely focused on exploiting free software licenses for making profit.
3. The mirror doesn't flip the text, you flipped it by pointing it at the mirror -- you most likely flipped it horizontally so that's how you see it in the mirror, but you could as well have flipped it vertically; then the text would be flipped vertically in the mirror.
4. Modulo bias happens when the random number generator's range is non-divisible by our desired range that we enforce with modulo operator -- with shown approach some numbers then have higher probability of being generated than others. For example if rand() here return numbers from 0 to 1023, there is only one way to get 999 (999 % 1000) but two ways to get 0 (0 % 1000 and 1000 % 1000), i.e. 0 is more likely to be generated. Common approach to reducing this effect is to repeatedly generate numbers until we get one falling into the "fair" range (this is not guaranteed to end so we should limit the maximum number of attempts).
5. The relationship is commonly described like this: information is interpreted data. I.e. data is just a sequence of symbols, information is the knowledge we extract from it.
6. The probability of program breaking is 1 minus probability of it not breaking. For a program to NOT break during one year, all libraries have to stay unchanged (probability 0.95 for each one): that's 0.95 * 0.95 * 0.95 * ... = 0.95^10. Similarly the probability of it not breaking during 5 years is (0.95^10)^5, so the probability of the program breaking in 5 years is around 92%.
7.`e`
8. Original Unix (around 1970), MS DOS (1981), Windows (1985), Linux (1998), TempleOS (2007). Linux stands out because it's not an operating system, it's a kernel.