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:
-
Group Code Quality Score
= Your group’s code quality score, as discussed below -
Group Functionality Score
= As per the gdd, this is a percentage based on how many features your group completes -
k
= A scaling factor based on individual contribution and how many of your individual features you completed. This factor will be strictly non-negative.
Overall Personal Score
-
Personal Functionality Score
=(Group Functionality Score)
\(\times\)(1 + k)
, capped at 100% -
Final Personal Game Score
= \(0.9 \times\)(Personal Functionality Score)
+ \(0.1 \times\)(Group Code Quality Score)
Code Quality Items
There are two categories of code quality items that we will look for in your code:
- “very important” items are major design flaws
- “important” items are more limited in scope and don’t indicate major design flaws.
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 inemscripten_init
(which only gets called once inemscripten.c
) rather than inemscripten_main
(which gets called every frame).
- Ex.
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 andTTF_Font
’s in state rather than using theasset
library for rendering text and images.
- Ex. Rather than going through every body in a scene and rendering it, you should just use
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.
- Encapsulation is, at a high level, hiding data from clients of structures in the
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
orfalse
, you do not need to further compare totrue
/false
or convert a boolean expression totrue
/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 byelse if {}
- Ex.