CS 3 (Spring 2025) Final Project Rubrics

This document describes how we will grade webserver04 and the game project. Both will be based on functionality and code quality, at varying percentages of the projects.

Overall Grading Policies

We will grade each project slightly differently. Please see below for details.

Grading for webserver04

On webserver04, your code quality score (which will be discussed below) will be 20% of your grade. The remaining 80% of your grade will be determined by (1) running the tests and (2) trying every route in an actual browser. This includes running your game route.

Grading for the game

The scoring for the game is a little more complicated.

Components of Your Score

The following components all factor into your personal score on the game:

Overall Personal Score

Code Quality Items

There are two categories of code quality items that we will look for in your code:

Very Important Items

The following items are considered “very important design errors”. For each of the items in this list that your code violates at least once (regardless of how many times you violate the item), a penalty of 25% will be applied to your code quality score, which starts at 100%. For example. if 10 pairs of functions violate functions::code-duplication-multiple-functions, but you violate functions::library-improper-usage only once, you would lose 50% of your code quality score overall, resulting in a code quality score of 50%.

functions::code-duplication-multiple-functions
  • Decompose significant amount of code duplication (this is usually any more than ~10 lines) by factoring out common code into helper functions.
functions::code-duplication-single-function
  • Lines of code should not be duplicated within a single function.
  • In these cases, a do while loop may be helpful.
functions::library-improper-usage
  • Library functions should be called properly according to their function definitions.
    • Ex. sdl_init() should be called in emscripten_init (which only gets called once in emscripten.c) rather than in emscripten_main (which gets called every frame).
functions::library-reimplementation
  • Functionality that is already provided by library functions should not be reimplemented.
    • Ex. Rather than going through every body in a scene and rendering it, you should just use sdl_render_scene().
    • Ex. Storing SDL_Texture’s and TTF_Font’s in state rather than using the asset library for rendering text and images.
design::encapsulation
  • Code should be encapsulated
    • Encapsulation is, at a high level, hiding data from clients of structures in the .c files. It is the process of hiding the implementation of a module from the code that uses it. This is important because if we need to change our underlying implementation, code that we have written that uses it should still be able to function. Encapsulation also makes things more readable and understandable for the user.
    • Ex: Implementing structs in .h files, and directly accessing them in other .c files.
    • Why? Our more advanced structs should have their implementations closed, and should have getter and setter methods to interact with them.

Important Items

The following items are considered “important design errors”. For each of the items in this list that your code violates at least once, a penalty of 5% will be applied to your code quality score.

variables::declaration-location
  • Declare variables in the narrowest possible scope, as close to its usage as possible.
  • Ex., if a variable is used only inside a loop, declare it inside the scope for the loop body rather than at the top of the function or at the top of the file.
  • Declaring a variable in an inner scope with the same name as a variable in the outer scope will cause the inner use of name to “shadow” the outer definition. Not only is this confusing, but it often leads to difficult bugs.
variables::global-variables
  • Do not use global variables besides constants. When there is information to be shared across function calls, it should flow into and out via parameters and return values, not reach out and access global state.
variables::magic-constants
  • Use a const variable to appropriately abstract magic constants from the code
    • Why? Magic constants can make it hard to understand the purpose of code. They (especially when appearing multiple times) are very difficult to tweak (e.g., for a faster machine).
    • Constants should be declared using SHOUTING_CASE
    • This doesn’t just apply to numbers. For example, file paths are examples of variables that should (most of the time) be constants.
  • All constants should be defined globally at the top of the file to make it easier to modify and manage them in one place.
macros::defines
  • Uses constant variables instead of defines.
    • Defines are used for text substitution and unlike consts, they are not typed checked, which could lead to unexpected issues in the code.
macros::misuse
  • Do not misuse or abuse a macro (We expect almost all usages of function macros to fit this definition. You have been warned.)
    • A macro in C is a named text substitution that is performed by the C preprocessor. Macros can be used to define constants, function-like constructs, and reusable code snippets.
functions::expensive-function-calls
  • Function calls (especially for expensive ones) should be minimized while still preserving the functionality of the code.
  • If a function returns a value that can be reused/slightly modified, it should be saved into a variable rather than called multiple times.
functions::over-modularization
  • While code should be decomposed into helper methods, it shouldn’t be taken to the extreme. This ends up making the code harder to read and trace. Ex. A line of code that is only written once is factored into a helper method. Instead, a concise comment describing what the line does (if it’s even necessary) would be more helpful.
types::header-file
  • Make sure that all functions outlined by the header file (e.g., it has a public interface) are implemented in the C file
types::include-guards
  • A header file should not misuse include guards
compilation::warnings
  • No warnings should be generated when the code is compiled
    • Make sure to resolve all warnings locally, as the tests will not pass on gitlab with warnings
design::booleans
  • Do not compare boolean expressions to true/false
  • Boolean expressions are prone to redundant/awkward constructions. Prefer concise and direct alternatives. A boolean value is true or false, you do not need to further compare to true/false or convert a boolean expression to true/false.
design::extra-control-flow
  • Additional control flow should not be used if they can be simplified.
    • Ex. if (...){...return;} does not need an else statement if it returns no matter what.
    • Ex. else{ if (...){...} } can be replaced by else if {}