Merge branch 'main' of gitlab.emi.u-bordeaux.fr:pt2/teams-s4/tm07/lightup-07c
This commit is contained in:
commit
3e370a8696
21 files changed
+3255
No files matched your search
+148
@@ -0,0 +1,148 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Chromium
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 160
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
...
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
build/
|
||||
.vscode/
|
||||
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) game_text",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/game_text",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "make_build"
|
||||
},
|
||||
{
|
||||
"name": "(gdb) debug tests thoguet",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/game_test_thoguet",
|
||||
"args": [
|
||||
"game_default_solution"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "make_build"
|
||||
},
|
||||
{
|
||||
"name": "(gdb) debug tests histo",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/history_test",
|
||||
"args": [
|
||||
"history_copy"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "make_build"
|
||||
},
|
||||
{
|
||||
"name": "(gdb) debug tests thperrier",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/game_test_thperrier",
|
||||
"args": [
|
||||
"game_copy"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "make_build"
|
||||
},
|
||||
]
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"game_ext.h": "c",
|
||||
"game.h": "c",
|
||||
"game_private.h": "c"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"C_Cpp.clang_format_path": "/usr/bin/clang-format"
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#version minimale de cmake nécessaire
|
||||
cmake_minimum_required(VERSION 2.6...3.13)
|
||||
|
||||
enable_testing()
|
||||
|
||||
#nom du projet
|
||||
project (game_text)
|
||||
include(CTest)
|
||||
|
||||
#positionne la variable
|
||||
set(CMAKE_C_FLAGS "-std=c99 -g -Wall")
|
||||
|
||||
#définit le nom du programme ainsi que
|
||||
#ses sources
|
||||
add_executable(game_text game_text.c)
|
||||
add_executable(game_test_thoguet game_test_thoguet.c)
|
||||
add_executable(game_test_thperrier game_test_thperrier.c)
|
||||
add_executable(game_test_nnunes game_test_nnunes.c)
|
||||
#add_executable(history_test history_test.c)
|
||||
|
||||
#les dépendances sont calculées automatiquement
|
||||
target_link_libraries(game_text game)
|
||||
target_link_libraries(game_test_thoguet game)
|
||||
target_link_libraries(game_test_thperrier game)
|
||||
target_link_libraries(game_test_nnunes game)
|
||||
#target_link_libraries(history_test game)
|
||||
|
||||
#Libraries
|
||||
add_library (game game.c game_aux.c game_ext.c game_private.c history.c)
|
||||
|
||||
#Tests THOGUET
|
||||
add_test(test_thoguet_dummy ./game_test_thoguet dummy)
|
||||
add_test(test_thoguet_game_new ./game_test_thoguet game_new)
|
||||
add_test(test_thoguet_game_print ./game_test_thoguet game_print)
|
||||
add_test(test_thoguet_game_get_square ./game_test_thoguet game_get_square)
|
||||
add_test(test_thoguet_game_default ./game_test_thoguet game_default)
|
||||
add_test(test_thoguet_game_default_solution ./game_test_thoguet game_default_solution)
|
||||
add_test(test_thoguet_game_restart ./game_test_thoguet game_restart)
|
||||
add_test(test_thoguet_game_is_over ./game_test_thoguet game_is_over)
|
||||
add_test(test_thoguet_game_update_flags ./game_test_thoguet game_update_flags)
|
||||
add_test(test_thoguet_game_play_move ./game_test_thoguet game_play_move)
|
||||
add_test(test_thoguet_game_check_move ./game_test_thoguet game_check_move)
|
||||
add_test(test_thoguet_game_new_empty_ext ./game_test_thoguet game_new_empty_ext)
|
||||
add_test(test_thoguet_game_new_ext ./game_test_thoguet game_new_ext)
|
||||
|
||||
#Tests THPERRIER
|
||||
add_test(test_thperrier_dummy ./game_test_thperrier dummy)
|
||||
add_test(test_thperrier_game_copy ./game_test_thperrier game_copy)
|
||||
add_test(test_thperrier_game_new_empty ./game_test_thperrier game_new_empty)
|
||||
add_test(test_thperrier_game_equal ./game_test_thperrier game_equal)
|
||||
add_test(test_thperrier_game_delete ./game_test_thperrier game_delete)
|
||||
add_test(test_thperrier_game_is_blank ./game_test_thperrier game_is_blank)
|
||||
add_test(test_thperrier_game_is_lightbulb ./game_test_thperrier game_is_lightbulb)
|
||||
add_test(test_thperrier_game_is_black ./game_test_thperrier game_is_black)
|
||||
add_test(test_thperrier_game_get_black_number ./game_test_thperrier game_get_black_number)
|
||||
add_test(test_thperrier_game_undo ./game_test_thperrier game_undo)
|
||||
add_test(test_thperrier_game_redo ./game_test_thperrier game_redo)
|
||||
|
||||
#Tests NNUNES
|
||||
add_test(test_nnunes_dummy ./game_test_nnunes dummy)
|
||||
add_test(test_nnunes_game_set_square ./game_test_nnunes game_set_square)
|
||||
add_test(test_nnunes_game_get_state ./game_test_nnunes game_get_state)
|
||||
add_test(test_nnunes_game_get_flags ./game_test_nnunes game_get_flags)
|
||||
add_test(test_nnunes_game_is_marked ./game_test_nnunes game_is_marked)
|
||||
add_test(test_nnunes_game_is_lighted ./game_test_nnunes game_is_lighted)
|
||||
add_test(test_nnunes_game_has_error ./game_test_nnunes game_has_error)
|
||||
add_test(test_nnunes_game_nb_rows ./game_test_nnunes game_nb_rows)
|
||||
add_test(test_nnunes_game_nb_cols ./game_test_nnunes game_nb_cols)
|
||||
add_test(test_nnunes_game_is_wrapping ./game_test_nnunes game_is_wrapping)
|
||||
|
||||
#Tests HISTORY
|
||||
# add_test(test_history_history_alloc ./history_test history_alloc)
|
||||
# add_test(test_history_create_empty ./history_test history_create_empty)
|
||||
# add_test(test_history_delete_entire_history ./history_test history_delete_entire_history)
|
||||
# add_test(test_history_is_empty ./history_test history_is_empty)
|
||||
# add_test(test_history_next ./history_test history_next)
|
||||
# add_test(test_history_prev ./history_test history_prev)
|
||||
# add_test(test_history_insert_first ./history_test history_insert_first)
|
||||
# add_test(test_history_delete_first ./history_test history_delete_first)
|
||||
# add_test(test_history_insert_after ./history_test history_insert_after)
|
||||
# add_test(test_history_delete_after ./history_test history_delete_after)
|
||||
# add_test(test_history_insert_before ./history_test history_insert_before)
|
||||
# add_test(test_history_delete_before ./history_test history_delete_before)
|
||||
# add_test(test_history_last ./history_test history_last)
|
||||
# add_test(test_history_first ./history_test history_first)
|
||||
# add_test(test_history_append ./history_test history_append)
|
||||
# add_test(test_history_copy ./history_test history_copy)
|
||||
@@ -0,0 +1,72 @@
|
||||
# lightup-a42e
|
||||
|
||||
Projet Techno
|
||||
|
||||
:warning: <b>LE PREMIER QUI COMMIT DU CODE QUI COMPILE PAS JE L'ATTRAPE </b> :warning:
|
||||
|
||||
## game_ext.h
|
||||
|
||||
| Fonction | REF | Assigned to | Notes | Finished |
|
||||
| ------------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------- | ----- | :--------------------: |
|
||||
| [game_new_ext](./game_ext.c#L?) | [game game_new_ext(uint nb_rows, uint nb_cols, square *squares, bool wrapping)](./game_ext.h#L20-30) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_new_empty_ext](./game_ext.c#L?) | [game game_new_empty_ext(uint nb_rows, uint nb_cols, bool wrapping);](./game_ext.h#L32-41) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_nb_rows](./game_ext.c#L?) | [uint game_nb_rows(cgame g);](./game_ext.h#L43-59) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_nb_cols](./game_ext.c#L?) | [uint game_nb_cols(cgame g);](./game_ext.h#L51-57) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_wrapping](./game_ext.c#L?) | [bool game_is_wrapping(cgame g);](./game_ext.h#L59-64) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_undo](./game_ext.c#L?) | [void game_undo(game g);](./game_ext.h#L66-75) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
| [game_redo](./game_ext.c#L?) | [void game_redo(game g);](./game_ext.h#L77-86) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
|
||||
## game.c
|
||||
|
||||
| Fonction | REF | Assigned to | Notes | Finished |
|
||||
| ------------------------------------------ | ---------------------------------------------------------------------------- | ----------- | ----- | :--------------------: |
|
||||
| [game_new](./game.c#L9-17) | [game game_new(square *squares)](./game.h#L73-81) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_new_empty](./game.c#L19-41) | [game game_new_empty(void)](./game.h#L83-88) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_copy](./game.c#L43-51) | [game game_copy(cgame g)](./game.h#L90-96) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_equal](./game.c#L53-62) | [bool game_equal(cgame g1, cgame g2)](./game.h#L98-106) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_delete](./game.c#L64-72) | [void game_delete(game g);](./game.h#L108-113) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_set_square](./game.c#L?) | [void game_set_square(game g, uint i, uint j, square s)](./game.h#L115-128) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_get_square](./game.c#L78-80) | [square game_get_square(cgame g, uint i, uint j)](./game.h#L130-140) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_get_state](./game.c#L?) | [square game_get_state(cgame g, uint i, uint j)](./game.h#L142-153) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_get_flags](./game.c#L?) | [square game_get_flags(cgame g, uint i, uint j)](./game.h#L155-166) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_blank](./game.c#L?) | [bool game_is_blank(cgame g, uint i, uint j)](./game.h#L168-178) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_lightbulb](./game.c#L?) | [bool game_is_lightbulb(cgame g, uint i, uint j)](./game.h#L180-190) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_black](./game.c#L98-102) | [bool game_is_black(cgame g, uint i, uint j)](./game.h#L192-202) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_get_black_number](./game.c#L104-108) | [int game_get_black_number(cgame g, uint i, uint j)](./game.h#L204-214) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_marked](./game.c#L?) | [bool game_is_marked(cgame g, uint i, uint j)](./game.h#L216-226) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_lighted](./game.c#L?) | [bool game_is_lighted(cgame g, uint i, uint j)](./game.h#L228-238) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_has_error](./game.c#L?) | [bool game_has_error(cgame g, uint i, uint j)](./game.h#L240-252) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_check_move](./game.c#L122-128) | [bool game_check_move(cgame g, uint i, uint j, square s)](./game.h#L242-269) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_play_move](./game.c#L130-133) | [void game_play_move(game g, uint i, uint j, square s)](./game.h#L271-284) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_update_flags](./game.c#L135-234) | [void game_update_flags(game g)](./game.h#L145-406) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_over](./game.c#L139-150) | [bool game_is_over(cgame g)](./game.h#L295-304) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_restart](./game.c#L152-160) | [void game_restart(game g)](./game.h#L306-313) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
|
||||
## Test
|
||||
|
||||
| Test | REF | Assigned to | Notes | Finished |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----------------------------------------------- | :--------------------: |
|
||||
| [game_new](./game_test_thoguet.c#L49) | [game game_new(square *squares)](./game.h#L73-81) | @thoguet | | <ul><li>[x] </li></ul> |
|
||||
| [game_new_empty](./game_test_thperrier.c#L16) | [game game_new_empty(void)](./game.h#L83-88) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
| [game_copy](./game_test_thperrier.c#L32) | [game game_copy(cgame g)](./game.h#L90-96) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
| [game_equal](./game_test_thperrier.c#L?) | [bool game_equal(cgame g1, cgame g2)](./game.h#L98-106) | @thperrier | | <ul><li>[X] </li></ul> |
|
||||
| [game_delete](./game_test_thperrier.c#L?) | [void game_delete(game g);](./game.h#L108-113) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_set_square](./game_test_nnunes.c#L?) | [void game_set_square(game g, uint i, uint j, square s)](./game.h#L115-128) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_get_square](./game_test_thoguet.c#L89) | [square game_get_square(cgame g, uint i, uint j)](./game.h#L130-140) | @thoguet | | <ul><li>[x] </li></ul> |
|
||||
| [game_get_state](./game_test_nnunes.c#L?) | [square game_get_state(cgame g, uint i, uint j)](./game.h#L142-153) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_get_flags](./game_test_nnunes.c#L?) | [square game_get_flags(cgame g, uint i, uint j)](./game.h#L155-166) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_blank](./game_test_thperrier.c#L?) | [bool game_is_blank(cgame g, uint i, uint j)](./game.h#L168-178) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_lightbulb](./game_test_thperrier.c#L?) | [bool game_is_lightbulb(cgame g, uint i, uint j)](./game.h#L180-190) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_black](./game_test_thperrier.c#L?) | [bool game_is_black(cgame g, uint i, uint j)](./game.h#L192-202) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_get_black_number](./game_test_thperrier.c#L?) | [int game_get_black_number(cgame g, uint i, uint j)](./game.h#L204-214) | @thperrier | | <ul><li>[x] </li></ul> |
|
||||
| [game_is_marked](./game_test_nnunes.c#L?) | [bool game_is_marked(cgame g, uint i, uint j)](./game.h#L216-226) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_is_lighted](./game_test_nnunes.c#L?) | [bool game_is_lighted(cgame g, uint i, uint j)](./game.h#L228-238) | @nnunes | | <ul><li>[X] </li></ul> |
|
||||
| [game_has_error](./game_test_nnunes.c#L?) | [bool game_has_error(cgame g, uint i, uint j)](./game.h#L240-252) | @nnunes | | <ul><li>[x] </li></ul> |
|
||||
| [game_check_move](./game_test_thoguet.c#L439-463) | [bool game_check_move(cgame g, uint i, uint j, square s)](./game.h#L242-269) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_play_move](./game_test_thoguet.c#L412-436) | [void game_play_move(game g, uint i, uint j, square s)](./game.h#L271-284) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_update_flags](./game_test_thoguet.c#L144-410) | [void game_update_flags(game g)](./game.h#L145-406) | @thoguet | done but not sure if it test every possibilites | <ul><li>[X] </li></ul> |
|
||||
| [game_is_over](./game_test_thoguet.c#L17) | [bool game_is_over(cgame g)](./game.h#L295-304) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_restart](./game_test_thoguet.c#L37) | [void game_restart(game g)](./game.h#L306-313) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_print](./game_test_thoguet.c#L70) | [void game_print(cgame g)](./game_aux.h#L13-20) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_default](./game_test_thoguet.c#L107) | [game game_default(void)](./game_aux.h#L22-28) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
| [game_default_solution](./game_test_thoguet.c#L125) | [game game_default_solution(void)](./game_aux.h#L30-36) | @thoguet | | <ul><li>[X] </li></ul> |
|
||||
@@ -0,0 +1,291 @@
|
||||
#include "game.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "game_ext.h"
|
||||
#include "game_private.h"
|
||||
|
||||
// JWRAPPING and IWRAPPING have a "+ game_nb_xxxx(g)" to avoid falling in negative when we are at 0 for exemple
|
||||
#define JWRAPPING (j + game_nb_cols(g) + gap_position * tab[index_tab + 1]) % game_nb_cols(g)
|
||||
#define IWRAPPING (i + game_nb_rows(g) + gap_position * tab[index_tab]) % game_nb_rows(g)
|
||||
#define JNORMAL j + gap_position* tab[index_tab + 1]
|
||||
#define INORMAL i + gap_position* tab[index_tab]
|
||||
|
||||
game game_new(square* squares) {
|
||||
game g = game_new_empty();
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
g->tab_cell[i][j] = squares[game_nb_cols(g) * i + j];
|
||||
}
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
game game_new_empty(void) {
|
||||
// alloc struct
|
||||
game g = (game)malloc(sizeof(struct game_s));
|
||||
if (g == NULL) {
|
||||
memoryError();
|
||||
}
|
||||
// set variable of struct
|
||||
g->wrapping = false;
|
||||
g->height = DEFAULT_SIZE;
|
||||
g->width = DEFAULT_SIZE;
|
||||
g->hist = history_create_empty();
|
||||
// alloc the tab with variables set before
|
||||
g->tab_cell = (square**)malloc(sizeof(square*) * game_nb_rows(g));
|
||||
if (g->tab_cell == NULL) {
|
||||
memoryError();
|
||||
}
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
g->tab_cell[i] = (square*)malloc(sizeof(square) * game_nb_cols(g));
|
||||
if (g->tab_cell[i] == NULL) {
|
||||
memoryError();
|
||||
}
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
g->tab_cell[i][j] = S_BLANK;
|
||||
}
|
||||
}
|
||||
// init history with a cell to avoid falling off of g->hist (if there is only this cell we consider the history as empty)
|
||||
g->hist = history_insert_first(g->hist, F_ERROR, 0, 0);
|
||||
return g;
|
||||
}
|
||||
|
||||
game game_copy(cgame g1) {
|
||||
game g2 = game_new_empty_ext(g1->height, g1->width, g1->wrapping);
|
||||
for (int i = 0; i < g2->height; i++) {
|
||||
for (int j = 0; j < g2->width; j++) {
|
||||
g2->tab_cell[i][j] = g1->tab_cell[i][j];
|
||||
}
|
||||
}
|
||||
// delete first allocated hist (by game new) of g2
|
||||
history_delete_entire_history(g2->hist);
|
||||
g2->hist = history_copy(g1->hist);
|
||||
return g2;
|
||||
}
|
||||
|
||||
bool game_equal(cgame g1, cgame g2) {
|
||||
// check if the two games have the same options
|
||||
if (g1->height != g2->height || g1->width != g2->width || g1->wrapping != g2->wrapping)
|
||||
return false;
|
||||
// check each cell and seek any difference between g1 and g2
|
||||
for (int i = 0; i < g1->height; i++) {
|
||||
for (int j = 0; j < g1->width; j++) {
|
||||
if (g1->tab_cell[i][j] != g2->tab_cell[i][j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void game_delete(game g) {
|
||||
// free each tab of tab_cell
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
free(g->tab_cell[i]);
|
||||
g->tab_cell[i] = NULL;
|
||||
}
|
||||
free(g->tab_cell);
|
||||
g->tab_cell = NULL;
|
||||
history_delete_entire_history(g->hist);
|
||||
g->hist = NULL;
|
||||
free(g);
|
||||
g = NULL;
|
||||
}
|
||||
|
||||
void game_set_square(game g, uint i, uint j, square s) {
|
||||
g->tab_cell[i][j] = s;
|
||||
return;
|
||||
}
|
||||
|
||||
square game_get_square(cgame g, uint i, uint j) {
|
||||
return g->tab_cell[i][j];
|
||||
}
|
||||
|
||||
square game_get_state(cgame g, uint i, uint j) {
|
||||
square temp = g->tab_cell[i][j];
|
||||
square list_flag[] = {F_ERROR, F_LIGHTED};
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
if (temp >= list_flag[flag_index]) {
|
||||
temp -= list_flag[flag_index];
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
square game_get_flags(cgame g, uint i, uint j) {
|
||||
square temp = g->tab_cell[i][j];
|
||||
square list_flag[] = {(F_ERROR | F_LIGHTED), F_ERROR, F_LIGHTED};
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
if (temp >= list_flag[flag_index]) {
|
||||
return list_flag[flag_index];
|
||||
}
|
||||
}
|
||||
return (S_BLANK);
|
||||
}
|
||||
|
||||
bool game_is_blank(cgame g, uint i, uint j) {
|
||||
return game_get_state(g, i, j) == S_BLANK;
|
||||
}
|
||||
|
||||
bool game_is_lightbulb(cgame g, uint i, uint j) {
|
||||
return game_get_state(g, i, j) == S_LIGHTBULB;
|
||||
}
|
||||
|
||||
bool game_is_black(cgame g, uint i, uint j) {
|
||||
return game_get_state(g, i, j) >= S_BLACK0 && game_get_state(g, i, j) <= S_BLACKU;
|
||||
}
|
||||
|
||||
int game_get_black_number(cgame g, uint i, uint j) {
|
||||
if (game_get_state(g, i, j) == S_BLACKU)
|
||||
return -1;
|
||||
return game_get_state(g, i, j) - S_BLACK;
|
||||
}
|
||||
|
||||
bool game_is_marked(cgame g, uint i, uint j) {
|
||||
return game_get_state(g, i, j) == S_MARK;
|
||||
}
|
||||
|
||||
bool game_is_lighted(cgame g, uint i, uint j) {
|
||||
return game_get_flags(g, i, j) >= F_LIGHTED;
|
||||
}
|
||||
|
||||
bool game_has_error(cgame g, uint i, uint j) {
|
||||
return g->tab_cell[i][j] >= F_ERROR;
|
||||
}
|
||||
|
||||
bool game_check_move(cgame g, uint i, uint j, square s) {
|
||||
return (i < game_nb_rows(g) && j < game_nb_cols(g) && (s == S_BLANK || s == S_MARK || s == S_LIGHTBULB) && !game_is_black(g, i, j));
|
||||
}
|
||||
|
||||
void game_play_move(game g, uint i, uint j, square s) {
|
||||
// shouldn't happen because we initalized in game new
|
||||
if (g->hist == NULL) {
|
||||
g->hist = history_create_empty();
|
||||
g->hist = history_insert_first(g->hist, game_get_state(g, i, j), i, j);
|
||||
} else {
|
||||
// to avoid redo after play
|
||||
g->hist = history_delete_all_after(g->hist, g->hist);
|
||||
// add new played element to hist and get the last element of hist
|
||||
g->hist = history_next(history_insert_after(g->hist, g->hist, game_get_state(g, i, j), i, j));
|
||||
}
|
||||
game_set_square(g, i, j, s);
|
||||
game_update_flags(g);
|
||||
}
|
||||
|
||||
void delete_flags(game g) {
|
||||
// delete prev flags
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
game_set_square(g, i, j, game_get_state(g, i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addF_LIGHTED(game g, uint i, uint j) {
|
||||
square flags = game_get_flags(g, i, j);
|
||||
if (flags == S_BLANK)
|
||||
game_set_square(g, i, j, game_get_state(g, i, j) | F_LIGHTED);
|
||||
else if (flags == F_ERROR) {
|
||||
game_set_square(g, i, j, game_get_state(g, i, j) | F_LIGHTED | F_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void update_flags_lightbulb(game g, uint i, uint j) {
|
||||
// add F_LIGHTED to the current lightbulb
|
||||
addF_LIGHTED(g, i, j);
|
||||
// add F_LIGHTED on the 4 directions, when reaching a wall by following a direction, remove it from tab, when reaching another lightbulb, put a
|
||||
// F_ERROR on the initial lightbulb
|
||||
// tab[] = { i, j, i, j, i, j, i, j}
|
||||
int tab[] = {-1, 0, 1, 0, 0, -1, 0, 1};
|
||||
for (int gap_position = 1; gap_position < max(game_nb_cols(g), game_nb_rows(g)); gap_position++) {
|
||||
// index_tab => pair = i
|
||||
// index_tab => odd = j
|
||||
for (uint index_tab = 0; index_tab < sizeof(tab) / sizeof(tab[0]); index_tab += 2) {
|
||||
// big if to check if INORMAL and JNORMAL are correct or if wrapping is true and IWRAPPING and JWRAPPING are not the initial case
|
||||
if (/* test if both tab are not 0*/ tab[index_tab] != tab[index_tab + 1] &&
|
||||
(/* normal check */ (JNORMAL >= 0 && JNORMAL < game_nb_cols(g) && INORMAL >= 0 && INORMAL < game_nb_rows(g)) ||
|
||||
/* wrapping check + not the inital case*/ (game_is_wrapping(g) && !(IWRAPPING == i && JWRAPPING == j)))) {
|
||||
if (game_is_black(g, IWRAPPING, JWRAPPING)) {
|
||||
tab[index_tab] = 0;
|
||||
tab[index_tab + 1] = 0;
|
||||
} else {
|
||||
// if we found another lightbulb on the line
|
||||
if (game_is_lightbulb(g, IWRAPPING, JWRAPPING))
|
||||
// update initial lightbulb on F_ERROR
|
||||
game_set_square(g, i, j, (S_LIGHTBULB | F_LIGHTED | F_ERROR));
|
||||
addF_LIGHTED(g, IWRAPPING, JWRAPPING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_flags_walls(game g, uint i, uint j) {
|
||||
int lightbulb = 0;
|
||||
int not_empty = 0;
|
||||
int tab[] = {-1, 0, 1, 0, 0, -1, 0, 1};
|
||||
for (uint index_tab = 0; index_tab < (sizeof(tab) / sizeof(tab[0])); index_tab += 2) {
|
||||
uint gap_position = 1;
|
||||
if (/* normal check*/ (JNORMAL >= 0 && JNORMAL < game_nb_cols(g) && INORMAL >= 0 && INORMAL < game_nb_rows(g)) ||
|
||||
/*wrapping check*/ (game_is_wrapping(g) &&
|
||||
/*not the same case*/ !(IWRAPPING == i && JWRAPPING == j))) {
|
||||
if (game_is_lightbulb(g, IWRAPPING, JWRAPPING))
|
||||
lightbulb++;
|
||||
else if (!game_is_blank(g, IWRAPPING, JWRAPPING) || game_is_lighted(g, IWRAPPING, JWRAPPING))
|
||||
not_empty++;
|
||||
} else {
|
||||
not_empty++;
|
||||
}
|
||||
}
|
||||
if (lightbulb > game_get_black_number(g, i, j)) {
|
||||
game_set_square(g, i, j, (game_get_state(g, i, j) | F_ERROR));
|
||||
}
|
||||
// look if there is enough empty cell around the wall (4 for the four directions)
|
||||
else if (not_empty > abs(game_get_black_number(g, i, j) - 4)) {
|
||||
game_set_square(g, i, j, (game_get_state(g, i, j) | F_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
void game_update_flags(game g) {
|
||||
delete_flags(g);
|
||||
// update flags lighted and lightbulb error
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
if (game_is_lightbulb(g, i, j)) {
|
||||
update_flags_lightbulb(g, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
// update flags wall (need to wait all FLIGHTED being updated)
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
if (game_is_black(g, i, j) && game_get_black_number(g, i, j) >= 0) {
|
||||
update_flags_walls(g, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool game_is_over(cgame g) {
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
if ((game_get_state(g, i, j) == S_BLANK && game_get_flags(g, i, j) == S_BLANK) || game_get_flags(g, i, j) == F_ERROR ||
|
||||
game_get_flags(g, i, j) == (F_LIGHTED | F_ERROR))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void game_restart(game g) {
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
if (game_get_state(g, i, j) == S_MARK || game_is_lightbulb(g, i, j))
|
||||
game_set_square(g, i, j, S_BLANK);
|
||||
}
|
||||
}
|
||||
game_update_flags(g);
|
||||
history_delete_entire_history(g->hist);
|
||||
// insert f_error on first cell of histo. initalized to avoid bug on first move undo
|
||||
g->hist = history_insert_first(history_create_empty(), F_ERROR, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* @file game.h
|
||||
* @brief Basic Game Functions.
|
||||
* @details See @ref index for further details.
|
||||
* @copyright University of Bordeaux. All rights reserved, 2021.
|
||||
**/
|
||||
|
||||
#ifndef __GAME_H__
|
||||
#define __GAME_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Standard unsigned integer type.
|
||||
**/
|
||||
typedef unsigned int uint;
|
||||
|
||||
/**
|
||||
* @brief Size of the default game grid.
|
||||
**/
|
||||
#define DEFAULT_SIZE 7
|
||||
|
||||
/**
|
||||
* @brief Different squares used in the game.
|
||||
* @details The value of a square is an integer represented on one byte, with a
|
||||
* low-order half-byte that codes for the square state (blank, black wall, light
|
||||
* bulb or mark) and a high-order half-byte that codes for the additionnal
|
||||
* square flags (lighted or error). While each square has a single state, it can
|
||||
* have zero, one or several flags (combined with bitwise operations). For
|
||||
* instance, a light bulb can have both the lighted and error flags. In this
|
||||
* case, the raw square value is S_LIGHTBULB | F_LIGHTED | F_ERROR, using the
|
||||
* bitwise OR operator (|). For more details on bitwise operations, see
|
||||
* https://en.wikipedia.org/wiki/Bitwise_operations_in_C.
|
||||
**/
|
||||
typedef enum {
|
||||
/* states */
|
||||
S_BLANK = 0, /**< a blank square */
|
||||
S_LIGHTBULB = 1, /**< a light bulb */
|
||||
S_MARK = 2, /**< a marked square (as not-a-light) */
|
||||
S_BLACK = 8, /**< black wall base code */
|
||||
S_BLACK0 = S_BLACK, /**< a numbered black wall (with 0 adjacent lights) */
|
||||
S_BLACK1, /**< a numbered black wall (with 1 adjacent light) */
|
||||
S_BLACK2, /**< a numbered black wall (with 2 adjacent lights) */
|
||||
S_BLACK3, /**< a numbered black wall (with 3 adjacent lights) */
|
||||
S_BLACK4, /**< a numbered black wall (with 4 adjacent lights) */
|
||||
S_BLACKU, /**< an unnumbered black wall (any number of adjacent lights) */
|
||||
/* flags */
|
||||
F_LIGHTED = 16, /**< lighted flag */
|
||||
F_ERROR = 32 /**< error flag */
|
||||
} square;
|
||||
|
||||
/** state mask used in square enum */
|
||||
#define S_MASK 0x0F
|
||||
|
||||
/** flag mask used in square enum */
|
||||
#define F_MASK 0xF0
|
||||
|
||||
/** square mask used in square enum */
|
||||
#define A_MASK 0xFF
|
||||
|
||||
/**
|
||||
* @brief The structure pointer that stores the game state.
|
||||
**/
|
||||
typedef struct game_s* game;
|
||||
|
||||
/**
|
||||
* @brief The structure constant pointer that stores the game state.
|
||||
* @details That means that it is not possible to modify the game using this
|
||||
* pointer.
|
||||
**/
|
||||
typedef const struct game_s* cgame;
|
||||
|
||||
/**
|
||||
* @brief Creates a new game with default size and initializes it.
|
||||
* @param squares an array describing the initial square values (<a
|
||||
* href="https://en.wikipedia.org/wiki/row-_and_column-major_order">row-major
|
||||
* storage</a>)
|
||||
* @pre @p squares must be an initialized array of default size squared.
|
||||
* @return the created game
|
||||
**/
|
||||
game game_new(square* squares);
|
||||
|
||||
/**
|
||||
* @brief Creates a new empty game with defaut size.
|
||||
* @details All squares are initialized with blank squares.
|
||||
* @return the created game
|
||||
**/
|
||||
game game_new_empty(void);
|
||||
|
||||
/**
|
||||
* @brief Duplicates a game.
|
||||
* @param g the game to copy
|
||||
* @return the copy of the game
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
game game_copy(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Tests if two games are equal (same states and same flags).
|
||||
* @param g1 the first game
|
||||
* @param g2 the second game
|
||||
* @return true if the two games are equal, false otherwise
|
||||
* @pre @p g1 must be a valid pointer toward a game structure.
|
||||
* @pre @p g2 must be a valid pointer toward a game structure.
|
||||
**/
|
||||
bool game_equal(cgame g1, cgame g2);
|
||||
|
||||
/**
|
||||
* @brief Deletes the game and frees the allocated memory.
|
||||
* @param g the game to delete
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
void game_delete(game g);
|
||||
|
||||
/**
|
||||
* @brief Sets the value of a given square.
|
||||
* @details This function is useful for initializing the squares of an empty
|
||||
* game.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @param s the square value
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @pre @p s must be a valid square value.
|
||||
**/
|
||||
void game_set_square(game g, uint i, uint j, square s);
|
||||
|
||||
/**
|
||||
* @brief Gets the raw value of a given square.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return the square value
|
||||
**/
|
||||
square game_get_square(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Gets the state of a given square.
|
||||
* @details See description of enum square.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return the square state
|
||||
**/
|
||||
square game_get_state(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Gets the flags of a given square.
|
||||
* @details See description of enum square.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return the square flags
|
||||
**/
|
||||
square game_get_flags(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square is blank.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square is blank
|
||||
**/
|
||||
bool game_is_blank(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square is a lightbulb.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square is a lightbulb
|
||||
**/
|
||||
bool game_is_lightbulb(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square is black (whether or not it is numbered).
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square is black
|
||||
**/
|
||||
bool game_is_black(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Get the number of lightbulbs expected against a black wall.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @pre The square at position (i,j) must be a black wall (either numbered or
|
||||
* unumbered).
|
||||
* @return the back wall number, or -1 if it is unumbered
|
||||
**/
|
||||
int game_get_black_number(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square is marked (as not-a-light).
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square is marked
|
||||
**/
|
||||
bool game_is_marked(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square is lighted.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square is lighted
|
||||
**/
|
||||
bool game_is_lighted(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Test if a given square has an error flag
|
||||
* @details An error can only occur on an numbered black wall or on a light
|
||||
* bulb.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @return true if the square has an error flag
|
||||
**/
|
||||
bool game_has_error(cgame g, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Checks if a given move is legal.
|
||||
* @details This function checks that it is possible to play a move at a given
|
||||
* position in the grid. More precisely, a move is said to be legal: 1) if the
|
||||
* coordinates (i,j) are inside the grid, 2) if @p s is either a blank, light
|
||||
* bulb or mark square, and 3) if the current square at (i,j) is not a black
|
||||
* square.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @param s the square value
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @return false if the move is not legal.
|
||||
**/
|
||||
bool game_check_move(cgame g, uint i, uint j, square s);
|
||||
|
||||
/**
|
||||
* @brief Plays a move in a given square.
|
||||
* @details The grid flags are updated consequently after each move.
|
||||
* @param g the game
|
||||
* @param i row index
|
||||
* @param j column index
|
||||
* @param s the square value
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
* @pre @p i < game height
|
||||
* @pre @p j < game width
|
||||
* @pre @p s must be either BLANK, LIGHTBULB or MARK.
|
||||
* @pre The game square at position (i,j) must not be a black square.
|
||||
**/
|
||||
void game_play_move(game g, uint i, uint j, square s);
|
||||
|
||||
/**
|
||||
* @brief Update all grid flags.
|
||||
* @details This is a low-level function, which is not intended to be used
|
||||
* directly by end-user during the game.
|
||||
* @param g the game
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
void game_update_flags(game g);
|
||||
|
||||
/**
|
||||
* @brief Checks if the game is won.
|
||||
* @param g the game
|
||||
* @details This function checks that all the game rules (decribed on @ref
|
||||
* index) are satisfied, ie. that all the blank squares are ligthed, without any
|
||||
* errors.
|
||||
* @return true if the game ended successfully, false otherwise
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
bool game_is_over(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Restarts a game.
|
||||
* @details All the game is reset to its initial state. In particular, all the
|
||||
* squares except black walls are reset to blank, and all flags are cleared.
|
||||
* @param g the game
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
void game_restart(game g);
|
||||
|
||||
#endif // __GAME_H__
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "game.h"
|
||||
#include "game_ext.h"
|
||||
#include "game_private.h"
|
||||
|
||||
char charPrintCell(cgame g, uint i, uint j) {
|
||||
square sqState = game_get_state(g, i, j);
|
||||
square sqFlags = game_get_flags(g, i, j);
|
||||
char tab[] = {' ', '*', '-', '?', '?', '?', '?', '?', '0', '1', '2', '3', '4', 'w', '?', '?', '.'};
|
||||
if (!sqState)
|
||||
return tab[sqFlags];
|
||||
return tab[sqState];
|
||||
}
|
||||
|
||||
void game_print(cgame g) {
|
||||
if (g != NULL) {
|
||||
uint i;
|
||||
printf(" 0");
|
||||
for (i = 1; i < game_nb_cols(g); i++) {
|
||||
printf("%u", i);
|
||||
}
|
||||
printf("\n -");
|
||||
for (i = 1; i < game_nb_cols(g); i++) {
|
||||
printf("-");
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < game_nb_rows(g); i++) {
|
||||
printf("%u |", i);
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
printf("%c", charPrintCell(g, i, j));
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
printf(" -");
|
||||
for (i = 1; i < game_nb_cols(g); i++) {
|
||||
printf("-");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
game game_default(void) {
|
||||
game g = game_new_empty();
|
||||
game_set_square(g, 0, 2, S_BLACK1);
|
||||
game_set_square(g, 1, 2, S_BLACK2);
|
||||
game_set_square(g, 2, 5, S_BLACKU);
|
||||
game_set_square(g, 2, 6, S_BLACK2);
|
||||
game_set_square(g, 4, 0, S_BLACK1);
|
||||
game_set_square(g, 4, 1, S_BLACKU);
|
||||
game_set_square(g, 5, 4, S_BLACK2);
|
||||
game_set_square(g, 6, 4, S_BLACKU);
|
||||
return g;
|
||||
}
|
||||
|
||||
game game_default_solution(void) {
|
||||
game g = game_default();
|
||||
game_set_square(g, 0, 0, S_LIGHTBULB);
|
||||
game_set_square(g, 1, 1, S_LIGHTBULB);
|
||||
game_set_square(g, 0, 3, S_LIGHTBULB);
|
||||
game_set_square(g, 1, 6, S_LIGHTBULB);
|
||||
game_set_square(g, 2, 2, S_LIGHTBULB);
|
||||
game_set_square(g, 3, 6, S_LIGHTBULB);
|
||||
game_set_square(g, 4, 4, S_LIGHTBULB);
|
||||
game_set_square(g, 5, 0, S_LIGHTBULB);
|
||||
game_set_square(g, 5, 5, S_LIGHTBULB);
|
||||
game_set_square(g, 6, 1, S_LIGHTBULB);
|
||||
game_update_flags(g);
|
||||
return g;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file game_aux.h
|
||||
* @brief Auxiliarry Game Functions.
|
||||
* @details See @ref index for further details.
|
||||
* @copyright University of Bordeaux. All rights reserved, 2021.
|
||||
**/
|
||||
|
||||
#ifndef __GAME_AUX_H__
|
||||
#define __GAME_AUX_H__
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "game.h"
|
||||
|
||||
/**
|
||||
* @brief Prints a game as text on the standard output stream.
|
||||
* @details The different squares are respectively displayed as text, based on a
|
||||
* square-character mapping table, as described in @ref index.
|
||||
* @param g the game
|
||||
* @pre @p g must be a valid pointer toward a game structure.
|
||||
**/
|
||||
void game_print(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Creates the default game.
|
||||
* @details See the description of the default game in @ref index.
|
||||
* @details https://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/lightup.html#7x7:b1f2iB2g1Bi2fBb
|
||||
* @return the created game
|
||||
**/
|
||||
game game_default(void);
|
||||
|
||||
/**
|
||||
* @brief Creates the default game solution.
|
||||
* @details See the description of the default game in @ref index.
|
||||
* @details https://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/lightup.html#7x7:b1f2iB2g1Bi2fBb
|
||||
* @return the created game
|
||||
**/
|
||||
game game_default_solution(void);
|
||||
|
||||
#endif // __GAME_AUX_H__
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
#include "game_ext.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "game_private.h"
|
||||
|
||||
game game_new_ext(uint nb_rows, uint nb_cols, square* squares, bool wrapping) {
|
||||
game g = game_new_empty_ext(nb_rows, nb_cols, wrapping);
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
g->tab_cell[i][j] = squares[game_nb_cols(g) * i + j];
|
||||
}
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
game game_new_empty_ext(uint nb_rows, uint nb_cols, bool wrapping) {
|
||||
// alloc struct
|
||||
game g = (game)malloc(sizeof(struct game_s));
|
||||
if (g == NULL) {
|
||||
fprintf(stderr, "not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// set variable of struct
|
||||
g->wrapping = wrapping;
|
||||
g->height = nb_rows;
|
||||
g->width = nb_cols;
|
||||
g->hist = history_create_empty();
|
||||
// alloc the tab with variables set before
|
||||
// alloc first tab
|
||||
g->tab_cell = (square**)malloc(sizeof(square*) * game_nb_rows(g));
|
||||
if (g->tab_cell == NULL) {
|
||||
fprintf(stderr, "not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// alloc each tab of tab_cell
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
g->tab_cell[i] = (square*)calloc(game_nb_cols(g), sizeof(square));
|
||||
if (g->tab_cell[i] == NULL) {
|
||||
fprintf(stderr, "not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
// insert f_error on first cell of histo. initalized to avoid bug on first move undo
|
||||
g->hist = history_insert_first(g->hist, F_ERROR, 0, 0);
|
||||
return g;
|
||||
}
|
||||
|
||||
uint game_nb_rows(cgame g) {
|
||||
return g->height;
|
||||
}
|
||||
|
||||
uint game_nb_cols(cgame g) {
|
||||
return g->width;
|
||||
}
|
||||
|
||||
bool game_is_wrapping(cgame g) {
|
||||
return g->wrapping;
|
||||
}
|
||||
|
||||
void game_undo(game g) {
|
||||
// check if g->hist is not empty or if it is possible to undo
|
||||
if (g->hist == NULL || history_is_empty(history_prev(g->hist))) {
|
||||
printf("you are at your first move\n");
|
||||
} else {
|
||||
square tmp = game_get_state(g, history_i(g->hist), history_j(g->hist));
|
||||
game_set_square(g, history_i(g->hist), history_j(g->hist), history_state(g->hist));
|
||||
game_update_flags(g);
|
||||
g->hist->state = tmp;
|
||||
g->hist = history_prev(g->hist);
|
||||
}
|
||||
}
|
||||
|
||||
void game_redo(game g) {
|
||||
// check if g->hist is not empty or if it is possible to redo
|
||||
if (g->hist == NULL || history_next(g->hist) == NULL) {
|
||||
printf("you are at your last move\n");
|
||||
} else {
|
||||
g->hist = history_next(g->hist);
|
||||
square tmp = game_get_state(g, history_i(g->hist), history_j(g->hist));
|
||||
game_set_square(g, history_i(g->hist), history_j(g->hist), history_state(g->hist));
|
||||
game_update_flags(g);
|
||||
g->hist->state = tmp;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file game_ext.h
|
||||
* @brief Extended Game Functions.
|
||||
* @details See @ref index for further details.
|
||||
* @copyright University of Bordeaux. All rights reserved, 2021.
|
||||
**/
|
||||
|
||||
#ifndef __GAME_EXT_H__
|
||||
#define __GAME_EXT_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "game.h"
|
||||
|
||||
/**
|
||||
* @name Extended Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Creates a new game with extended options and initializes it.
|
||||
* @details See description of game extensions on @ref index.
|
||||
* @param nb_rows number of rows in game
|
||||
* @param nb_cols number of columns in game
|
||||
* @param squares an array describing the initial state of each square
|
||||
* (row-major storage)
|
||||
* @param wrapping wrapping option
|
||||
* @return the created game
|
||||
**/
|
||||
game game_new_ext(uint nb_rows, uint nb_cols, square* squares, bool wrapping);
|
||||
|
||||
/**
|
||||
* @brief Creates a new empty game with extended options.
|
||||
* @details All squares are initialized with empty squares.
|
||||
* @details See description of game extensions on @ref index.
|
||||
* @param nb_rows number of rows in game
|
||||
* @param nb_cols number of columns in game
|
||||
* @param wrapping wrapping option
|
||||
* @return the created game
|
||||
**/
|
||||
game game_new_empty_ext(uint nb_rows, uint nb_cols, bool wrapping);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of rows (or height).
|
||||
* @param g the game
|
||||
* @return the number of rows on this game
|
||||
* @pre @p g is a valid pointer toward a cgame structure
|
||||
**/
|
||||
uint game_nb_rows(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of columns (or width).
|
||||
* @param g the game
|
||||
* @return the the number of columns on this game
|
||||
* @pre @p g is a valid pointer toward a cgame structure
|
||||
**/
|
||||
uint game_nb_cols(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Checks if the game has the wrapping option
|
||||
* @return true, if wrapping, false otherwise
|
||||
* @pre @p g is a valid pointer toward a cgame structure
|
||||
**/
|
||||
bool game_is_wrapping(cgame g);
|
||||
|
||||
/**
|
||||
* @brief Undoes the last move.
|
||||
* @details Searches in the history the last move played (by calling
|
||||
* @ref game_play_move or @ref game_redo), and restores the state of the game
|
||||
* before that move. If no moves have been played, this function does nothing.
|
||||
* The @ref game_restart function clears the history.
|
||||
* @param g the game
|
||||
* @pre @p g is a valid pointer toward a cgame structure
|
||||
**/
|
||||
void game_undo(game g);
|
||||
|
||||
/**
|
||||
* @brief Redoes the last move.
|
||||
* @details Searches in the history the last cancelled move (by calling @ref
|
||||
* game_undo), and replays it. If there are no more moves to be replayed, this
|
||||
* function does nothing. After playing a new move with @ref game_play_move, it
|
||||
* is no longer possible to redo an old cancelled move.
|
||||
* @param g the game
|
||||
* @pre @p g is a valid pointer toward a cgame structure
|
||||
**/
|
||||
void game_redo(game g);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // __GAME_EXT_H__
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int max(int a, int b) {
|
||||
if (a > b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
void checkPointer(void* p) {
|
||||
if (!p) {
|
||||
fprintf(stderr, "Error on given pointer.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef __GAME_PRIVATE_H__
|
||||
#define __GAME_PRIVATE_H__
|
||||
#include "history.h"
|
||||
|
||||
struct game_s {
|
||||
// tab of tab of square (eg: tab_cell[i][j])
|
||||
square** tab_cell;
|
||||
bool wrapping;
|
||||
uint height; // i in general
|
||||
uint width; // j in general
|
||||
// case of history
|
||||
history hist;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief return the max between a and b
|
||||
*
|
||||
* @param a int to test
|
||||
* @param b int to test
|
||||
* @return the max between a and b
|
||||
*/
|
||||
int max(int a, int b);
|
||||
|
||||
/**
|
||||
* @brief check if the pointer is NULL fprinf and exit else nothing
|
||||
*
|
||||
* @param p any pointer
|
||||
*/
|
||||
void checkPointer(void* p);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "game.h"
|
||||
#include "game_aux.h"
|
||||
#include "game_ext.h"
|
||||
#include "game_private.h"
|
||||
|
||||
bool test_dummy(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void usage(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Usage: %s <testname> [<...>]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* ************** game_set_square ************** */
|
||||
bool test_game_set_square(void) {
|
||||
game g = game_new_empty();
|
||||
square list[] = {S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU};
|
||||
square list_flag[] = {F_ERROR, F_LIGHTED, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
for (uint tab_index = 0; tab_index < sizeof(list) / sizeof(list[0]); tab_index++) {
|
||||
game_set_square(g, i, j, (list[tab_index] | list_flag[flag_index]));
|
||||
if (game_get_square(g, i, j) != (list[tab_index] | list_flag[flag_index])) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************** game_get_state ************** */
|
||||
bool test_game_get_state(void) {
|
||||
game g = game_new_empty();
|
||||
square list[] = {S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU};
|
||||
square list_flag[] = {S_BLANK, F_ERROR, F_LIGHTED, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
for (uint tab_index = 0; tab_index < sizeof(list) / sizeof(list[0]); tab_index++) {
|
||||
game_set_square(g, i, j, (list[tab_index] | list_flag[flag_index]));
|
||||
if (game_get_state(g, i, j) != list[tab_index]) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************** game_get_flags ************** */
|
||||
bool test_game_get_flags(void) {
|
||||
game g = game_new_empty();
|
||||
square list_flag[] = {F_ERROR, F_LIGHTED, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
game_set_square(g, i, j, (S_BLANK | list_flag[flag_index]));
|
||||
if (game_get_flags(g, i, j) != list_flag[flag_index]) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************** game_is_marked ************** */
|
||||
bool test_game_is_marked(void) {
|
||||
game g = game_new_empty();
|
||||
square list_flag[] = {S_BLANK, F_ERROR, F_LIGHTED, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
game_set_square(g, i, j, (S_MARK | list_flag[flag_index]));
|
||||
if ((game_get_state(g, i, j) == S_MARK) && game_is_marked(g, i, j)) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************** game_is_lighted ************** */
|
||||
bool test_game_is_lighted(void) {
|
||||
game g = game_new_empty();
|
||||
square list_flag[] = {F_LIGHTED, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
game_set_square(g, i, j, (S_BLANK | list_flag[flag_index]));
|
||||
if ((game_get_flags(g, i, j) == list_flag[flag_index]) && game_is_lighted(g, i, j)) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************** game_has_error ************** */
|
||||
bool test_game_has_error(void) {
|
||||
game g = game_new_empty();
|
||||
square list_flag[] = {F_ERROR, (F_ERROR | F_LIGHTED)};
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
for (uint flag_index = 0; flag_index < sizeof(list_flag) / sizeof(list_flag[0]); flag_index++) {
|
||||
game_set_square(g, i, j, (S_BLANK | list_flag[flag_index]));
|
||||
if ((game_get_flags(g, i, j) == list_flag[flag_index]) && game_has_error(g, i, j)) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************** game_nb_rows ************** */
|
||||
bool test_game_nb_rows(void) {
|
||||
game g = game_new_empty();
|
||||
if (game_get_square(g, game_nb_rows(g) - 1, 0) == S_BLANK) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************** game_nb_cols ************** */
|
||||
bool test_game_nb_cols(void) {
|
||||
game g = game_new_empty();
|
||||
if (game_get_square(g, 0, game_nb_cols(g) - 1) == S_BLANK) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************** game_is_wrapping ************** */
|
||||
bool test_game_is_wrapping(void) {
|
||||
game g = game_new_empty();
|
||||
game_set_square(g, 0, 0, S_LIGHTBULB);
|
||||
game_set_square(g, 1, 0, S_BLACK);
|
||||
game_set_square(g, 0, 1, S_BLACK);
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
if (!(game_is_lighted(g, 0, i) && game_is_wrapping(g))) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
if (!(game_is_lighted(g, i, 0) && game_is_wrapping(g))) {
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
usage(argc, argv);
|
||||
}
|
||||
fprintf(stderr, "=> Start test \"%s\"\n", argv[1]);
|
||||
bool success = false;
|
||||
if (strcmp("dummy", argv[1]) == 0)
|
||||
success = test_dummy();
|
||||
else if (strcmp("game_set_square", argv[1]) == 0) {
|
||||
success = test_game_set_square();
|
||||
} else if (strcmp("game_get_state", argv[1]) == 0) {
|
||||
success = test_game_get_state();
|
||||
} else if (strcmp("game_get_flags", argv[1]) == 0) {
|
||||
success = test_game_get_flags();
|
||||
} else if (strcmp("game_is_marked", argv[1]) == 0) {
|
||||
success = test_game_is_marked();
|
||||
} else if (strcmp("game_is_lighted", argv[1]) == 0) {
|
||||
success = test_game_is_lighted();
|
||||
} else if (strcmp("game_has_error", argv[1]) == 0) {
|
||||
success = test_game_has_error();
|
||||
} else if (strcmp("game_nb_rows", argv[1]) == 0) {
|
||||
success = test_game_nb_rows();
|
||||
} else if (strcmp("game_nb_cols", argv[1]) == 0) {
|
||||
success = test_game_nb_cols();
|
||||
} else if (strcmp("game_is_wrapping", argv[1]) == 0) {
|
||||
success = test_game_is_wrapping();
|
||||
} else {
|
||||
fprintf(stderr, "Error: test \"%s\" not found!\n", argv[1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (success) {
|
||||
fprintf(stderr, "Test \"%s\" finished: SUCCESS\n", argv[1]);
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Test \"%s\" finished: FAILURE\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "game.h"
|
||||
#include "game_aux.h"
|
||||
#include "game_ext.h"
|
||||
|
||||
#define SIZE_LIMIT_GAME 10
|
||||
// put usable square at the start of the list and S_BLANK at the first element
|
||||
#define LIST_OF_SQUARE \
|
||||
{ S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU, F_LIGHTED, F_ERROR }
|
||||
#define USABLE_SQUARE 2
|
||||
|
||||
/* ********** DUMMY ********** */
|
||||
bool test_dummy(void) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_new_ext_empty ******* */
|
||||
/**
|
||||
* @brief test creating every game between size 0 to SIZE_LIMIT_GAME
|
||||
*
|
||||
* @return EXIT_SUCCESS if every game has been created well
|
||||
*/
|
||||
bool test_game_new_empty_ext(void) {
|
||||
for (uint height = 1; height <= SIZE_LIMIT_GAME; height++) {
|
||||
for (uint width = 1; width <= SIZE_LIMIT_GAME; width++) {
|
||||
for (int wrap = 0; wrap < 2; wrap++) {
|
||||
game g = game_new_empty_ext(height, width, wrap);
|
||||
assert(g);
|
||||
game_delete(g);
|
||||
g = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_new_ext ******* */
|
||||
/**
|
||||
* @brief test creating every game between size 0 to SIZE_LIMIT_GAME + fill it with every square of list
|
||||
*
|
||||
* @return EXIT_SUCCESS if every game has been created well and well filled
|
||||
*/
|
||||
bool test_game_new_ext(void) {
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
for (uint height = 1; height <= SIZE_LIMIT_GAME; height++) {
|
||||
for (uint width = 1; width <= SIZE_LIMIT_GAME; width++) {
|
||||
square tab[height * width];
|
||||
for (uint index_list = 0; index_list < sizeof(list) / sizeof(list[0]); index_list++) {
|
||||
for (uint index_tab = 0; index_tab < height * width; index_tab++) {
|
||||
tab[index_tab] = list[index_list];
|
||||
}
|
||||
for (int wrap = 0; wrap < 2; wrap++) {
|
||||
printf("%d\n", index_list);
|
||||
game g = game_new_ext(height, width, tab, wrap);
|
||||
assert(g);
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
printf("list :%d, get square :%d\n", list[index_list], game_get_square(g, i, j));
|
||||
assert(list[index_list] == game_get_square(g, i, j));
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
g = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_is_over ******* */
|
||||
/**
|
||||
* @brief test if game_is_over return true with default_solution, false with one flag F_ERROR, false with one S_BLANK and false with game_default
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no errors
|
||||
*/
|
||||
bool test_game_is_over(void) {
|
||||
game g = game_default_solution();
|
||||
game_update_flags(g);
|
||||
assert(game_is_over(g));
|
||||
game_set_square(g, 0, 0, (S_LIGHTBULB | F_LIGHTED | F_ERROR));
|
||||
assert(!game_is_over(g));
|
||||
game_update_flags(g);
|
||||
game_set_square(g, 0, 1, S_BLANK);
|
||||
assert(!game_is_over(g));
|
||||
game_delete(g);
|
||||
g = game_default();
|
||||
game_update_flags(g);
|
||||
assert(!game_is_over(g));
|
||||
game_delete(g);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_restart ******* */
|
||||
/**
|
||||
* @brief test if game_restart remove every S_LIGHTBULB, S_MARK, and F_LIGHTED but nothing else and if the history has been reset
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_restart(void) {
|
||||
game game_def = game_default();
|
||||
game game_def_solution = game_default_solution();
|
||||
game_set_square(game_def, 1, 5, S_BLACK4);
|
||||
game_set_square(game_def_solution, 1, 5, S_BLACK4);
|
||||
game_set_square(game_def, 3, 2, S_BLACK3);
|
||||
game_set_square(game_def_solution, 3, 2, S_BLACK3);
|
||||
game_play_move(game_def, 0, 1, S_LIGHTBULB);
|
||||
game_play_move(game_def_solution, 0, 1, S_LIGHTBULB);
|
||||
game_play_move(game_def, 2, 0, S_MARK);
|
||||
game_play_move(game_def_solution, 2, 0, S_MARK);
|
||||
game_play_move(game_def, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(game_def_solution, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(game_def, 1, 1, S_MARK);
|
||||
game_play_move(game_def_solution, 1, 1, S_MARK);
|
||||
game_undo(game_def);
|
||||
game_undo(game_def_solution);
|
||||
assert(!game_equal(game_def, game_def_solution));
|
||||
game_restart(game_def_solution);
|
||||
game_restart(game_def);
|
||||
assert(game_equal(game_def, game_def_solution));
|
||||
game_redo(game_def);
|
||||
assert(game_equal(game_def, game_def_solution));
|
||||
game_undo(game_def);
|
||||
assert(game_equal(game_def, game_def_solution));
|
||||
game_delete(game_def);
|
||||
game_delete(game_def_solution);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ********* game_new ********* */
|
||||
/**
|
||||
* @brief test if created game with game_new are well filled by the tab
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_new(void) {
|
||||
square tab[DEFAULT_SIZE * DEFAULT_SIZE];
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
for (uint index_list = 0; index_list < sizeof(list) / sizeof(list[0]); index_list++) {
|
||||
for (uint index_tab = 0; index_tab < DEFAULT_SIZE * DEFAULT_SIZE; index_tab++) {
|
||||
tab[index_tab] = list[index_list];
|
||||
}
|
||||
printf("%d\n", index_list);
|
||||
game g = game_new(tab);
|
||||
for (uint i = 0; i < DEFAULT_SIZE; i++) {
|
||||
for (uint j = 0; j < DEFAULT_SIZE; j++) {
|
||||
printf("list :%d, get square :%d\n", list[index_list], game_get_square(g, i, j));
|
||||
assert(list[index_list] == game_get_square(g, i, j));
|
||||
}
|
||||
}
|
||||
assert(g);
|
||||
game_delete(g);
|
||||
g = NULL;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******** game_print ******** */
|
||||
/**
|
||||
* @brief test if there is no major problems by printing every square of list
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_print(void) {
|
||||
for (int height = 1; height <= SIZE_LIMIT_GAME; height++) {
|
||||
for (int width = 1; width <= SIZE_LIMIT_GAME; width++) {
|
||||
square tab[width * height];
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
game g;
|
||||
for (uint index_list = 0; index_list < sizeof(list) / sizeof(list[0]); index_list++) {
|
||||
for (uint index_tab = 0; index_tab < width * height; index_tab++) {
|
||||
tab[index_tab] = list[index_list];
|
||||
}
|
||||
printf("%d\n", list[index_list]);
|
||||
g = game_new_ext(height, width, tab, false);
|
||||
assert(g);
|
||||
game_print(g);
|
||||
game_delete(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_get_square ******* */
|
||||
/**
|
||||
* @brief test if get_square return the same as tab, used to create the game
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_get_square(void) {
|
||||
for (int height = 1; height <= SIZE_LIMIT_GAME; height++) {
|
||||
for (int width = 1; width <= SIZE_LIMIT_GAME; width++) {
|
||||
square tab[width * height];
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
for (uint index_list = 0; index_list < sizeof(list) / sizeof(list[0]); index_list++) {
|
||||
for (uint index_tab = 0; index_tab < height * width; index_tab++) {
|
||||
tab[index_tab] = list[index_list];
|
||||
game g = game_new_ext(height, width, tab, false);
|
||||
printf("[%d, %d] %d %d\n", index_tab / game_nb_cols(g), index_tab % game_nb_cols(g),
|
||||
game_get_square(g, index_tab / game_nb_cols(g), index_tab % game_nb_cols(g)), tab[index_tab]);
|
||||
assert(game_get_square(g, index_tab / game_nb_cols(g), index_tab % game_nb_cols(g)) == tab[index_tab]);
|
||||
game_delete(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ******* game_default ******* */
|
||||
/**
|
||||
* @brief test if the game_default is the same as tab (tab is game_default)
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_default(void) {
|
||||
game game_def = game_default();
|
||||
assert(game_def);
|
||||
// clang-format off
|
||||
square tab[49] =
|
||||
{
|
||||
/*X0 X1 X2 X3 X4 X5 X6*/
|
||||
/*Y 0*/ S_BLANK, S_BLANK, S_BLACK1, S_BLANK, S_BLANK, S_BLANK, S_BLANK,
|
||||
/*Y 1*/ S_BLANK, S_BLANK, S_BLACK2, S_BLANK, S_BLANK, S_BLANK, S_BLANK,
|
||||
/*Y 2*/ S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLACKU, S_BLACK2,
|
||||
/*Y 3*/ S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK,
|
||||
/*Y 4*/ S_BLACK1, S_BLACKU, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK,
|
||||
/*Y 5*/ S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLACK2, S_BLANK, S_BLANK,
|
||||
/*Y 6*/ S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLACKU, S_BLANK, S_BLANK
|
||||
};
|
||||
// clang-format on
|
||||
game game_test = game_new(tab);
|
||||
assert(game_equal(game_def, game_test));
|
||||
game_delete(game_def);
|
||||
game_delete(game_test);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* *** game_default_solution *** */
|
||||
/**
|
||||
* @brief test if game_default_solution is the same as game_default with moves needed to win
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_default_solution(void) {
|
||||
game game_def_solution = game_default_solution();
|
||||
game game_def = game_default();
|
||||
assert(game_def_solution);
|
||||
// solution
|
||||
game_set_square(game_def, 0, 0, S_LIGHTBULB);
|
||||
game_set_square(game_def, 1, 1, S_LIGHTBULB);
|
||||
game_set_square(game_def, 0, 3, S_LIGHTBULB);
|
||||
game_set_square(game_def, 1, 6, S_LIGHTBULB);
|
||||
game_set_square(game_def, 2, 2, S_LIGHTBULB);
|
||||
game_set_square(game_def, 3, 6, S_LIGHTBULB);
|
||||
game_set_square(game_def, 4, 4, S_LIGHTBULB);
|
||||
game_set_square(game_def, 5, 0, S_LIGHTBULB);
|
||||
game_set_square(game_def, 5, 5, S_LIGHTBULB);
|
||||
game_set_square(game_def, 6, 1, S_LIGHTBULB);
|
||||
game_update_flags(game_def);
|
||||
assert(game_equal(game_def_solution, game_def));
|
||||
game_delete(game_def_solution);
|
||||
game_delete(game_def);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* **** game_update_flags **** */
|
||||
/**
|
||||
* @brief count the number of F_ERROR on the entire game g
|
||||
*
|
||||
* @param g the game to analyze
|
||||
* @return uint the number of F_ERROR on the game g
|
||||
*/
|
||||
uint counterF_ERROR(game g) {
|
||||
uint cpt = 0;
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
if (game_has_error(g, i, j))
|
||||
cpt++;
|
||||
}
|
||||
}
|
||||
return cpt;
|
||||
}
|
||||
/*
|
||||
Tests without the wrapping option
|
||||
|
||||
test on a 2x2 game without *wrapping*
|
||||
test on a 3x3 game without *wrapping*
|
||||
test on a 5x3 game without *wrapping*
|
||||
test flags *error* on specifics cases
|
||||
|
||||
On the 2x2, 3x3 and 5x3 tests, we play these move to win and we test if the grid is correct
|
||||
|
||||
01 012 012
|
||||
-- --- ---
|
||||
0 |2*| 0 |.w0| 0 |*..|
|
||||
1 |*.| 1 |*1w| 1 |w*1|
|
||||
-- 2 |..*| 2 |*2.|
|
||||
(2x2) --- 3 |..*|
|
||||
(3x3) 4 |.*.|
|
||||
---
|
||||
(5x3)
|
||||
|
||||
Tests of the wrapping option
|
||||
|
||||
test on a 2x2 game with option *wrapping* (cas limite)
|
||||
test on a 3x3 game with option *wrapping*
|
||||
test on a 5x3 game with option *wrapping*
|
||||
test of the flags *error* in the specifics cases of the option *wrapping*
|
||||
|
||||
On the 2x2, 3x3 and 5x3 tests, we play these move to win and we test if the grid is correct
|
||||
|
||||
01 012 012
|
||||
-- --- ---
|
||||
0 |4*| 0 |*w2| 0 |...|
|
||||
1 |*.| 1 |.ww| 1 |w*1|
|
||||
-- 2 |..*| 2 |*2.|
|
||||
(2x2) --- 3 |..*|
|
||||
(3x3) 4 |...|
|
||||
---
|
||||
(5x3)
|
||||
*/
|
||||
bool test_game_update_flags(void) {
|
||||
square test2x2w[4] = {S_BLACK4, S_BLANK, S_BLANK, S_BLANK};
|
||||
square test3x3w[9] = {S_BLANK, S_BLACKU, S_BLACK2, S_BLANK, S_BLACKU, S_BLACKU, S_BLANK, S_BLANK, S_BLANK};
|
||||
square test2x2[4] = {S_BLACK2, S_BLANK, S_BLANK, S_BLANK};
|
||||
square test3x3[9] = {S_BLANK, S_BLACKU, S_BLACK0, S_BLANK, S_BLACK1, S_BLACKU, S_BLANK, S_BLANK, S_BLANK};
|
||||
square test5x3[15] = {S_BLANK, S_BLANK, S_BLANK, S_BLACKU, S_BLANK, S_BLACK1, S_BLANK, S_BLACK2,
|
||||
S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK, S_BLANK};
|
||||
// with wrapping
|
||||
game g2x2w = game_new_ext(2, 2, test2x2w, true);
|
||||
game_play_move(g2x2w, 0, 1, S_LIGHTBULB);
|
||||
game_play_move(g2x2w, 1, 0, S_LIGHTBULB);
|
||||
assert(game_is_over(g2x2w));
|
||||
game g3x3w = game_new_ext(3, 3, test3x3w, true);
|
||||
game_play_move(g3x3w, 0, 0, S_LIGHTBULB);
|
||||
game_play_move(g3x3w, 2, 2, S_LIGHTBULB);
|
||||
assert(game_is_over(g3x3w));
|
||||
game_delete(g3x3w);
|
||||
game g5x3w = game_new_ext(5, 3, test5x3, true);
|
||||
game_play_move(g5x3w, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(g5x3w, 2, 0, S_LIGHTBULB);
|
||||
game_play_move(g5x3w, 3, 2, S_LIGHTBULB);
|
||||
assert(game_is_over(g5x3w));
|
||||
game_restart(g2x2w);
|
||||
game_restart(g5x3w);
|
||||
game_play_move(g2x2w, 0, 1, S_MARK);
|
||||
assert(!game_is_over(g2x2w));
|
||||
assert(game_has_error(g2x2w, 0, 0));
|
||||
assert(counterF_ERROR(g2x2w) == 1);
|
||||
game_delete(g2x2w);
|
||||
game_play_move(g5x3w, 0, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3w, 2, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3w, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(g5x3w, 2, 0, S_LIGHTBULB);
|
||||
assert(!game_is_over(g5x3w));
|
||||
assert(game_has_error(g5x3w, 0, 2));
|
||||
assert(game_has_error(g5x3w, 1, 2));
|
||||
assert(game_has_error(g5x3w, 2, 2));
|
||||
assert(game_has_error(g5x3w, 2, 0));
|
||||
assert(game_has_error(g5x3w, 2, 1));
|
||||
assert(counterF_ERROR(g5x3w) == 5);
|
||||
game_delete(g5x3w);
|
||||
// without wrapping
|
||||
game g2x2 = game_new_ext(2, 2, test2x2, false);
|
||||
game_play_move(g2x2, 0, 1, S_LIGHTBULB);
|
||||
game_play_move(g2x2, 1, 0, S_LIGHTBULB);
|
||||
assert(game_is_over(g2x2));
|
||||
game g3x3 = game_new_ext(3, 3, test3x3, false);
|
||||
game_play_move(g3x3, 1, 0, S_LIGHTBULB);
|
||||
game_play_move(g3x3, 2, 2, S_LIGHTBULB);
|
||||
assert(game_is_over(g3x3));
|
||||
game_delete(g3x3);
|
||||
game g5x3 = game_new_ext(5, 3, test5x3, false);
|
||||
game_play_move(g5x3, 0, 0, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 2, 0, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 3, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 4, 1, S_LIGHTBULB);
|
||||
assert(game_is_over(g5x3));
|
||||
game_restart(g2x2);
|
||||
game_restart(g5x3);
|
||||
game_play_move(g2x2, 1, 0, S_MARK);
|
||||
assert(!game_is_over(g2x2));
|
||||
assert(game_has_error(g2x2, 0, 0));
|
||||
assert(counterF_ERROR(g2x2) == 1);
|
||||
game_delete(g2x2);
|
||||
game_play_move(g5x3, 0, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 1, 1, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 2, 0, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 2, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 3, 2, S_LIGHTBULB);
|
||||
game_play_move(g5x3, 4, 1, S_LIGHTBULB);
|
||||
assert(!game_is_over(g5x3));
|
||||
assert(game_has_error(g5x3, 1, 2));
|
||||
assert(game_has_error(g5x3, 2, 1));
|
||||
assert(game_has_error(g5x3, 2, 2));
|
||||
assert(game_has_error(g5x3, 3, 2));
|
||||
assert(counterF_ERROR(g5x3) == 4);
|
||||
game_delete(g5x3);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ****** game_play_move ****** */
|
||||
/**
|
||||
* @brief test if play move set square + update the flags + update history
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_play_move(void) {
|
||||
game game_play = game_new_empty();
|
||||
game game_set = game_new_empty();
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
for (uint index_list = 0; index_list <= USABLE_SQUARE; index_list++) {
|
||||
game_play_move(game_play, 0, 0, list[index_list]);
|
||||
game_set_square(game_set, 0, 0, list[index_list]);
|
||||
game_update_flags(game_set);
|
||||
assert(game_equal(game_play, game_set));
|
||||
}
|
||||
// undo / redo
|
||||
game_undo(game_play);
|
||||
game_set_square(game_set, 0, 0, list[USABLE_SQUARE - 1]); // take the before last usable element of list
|
||||
game_update_flags(game_set);
|
||||
assert(game_equal(game_play, game_set));
|
||||
// delete
|
||||
game_delete(game_play);
|
||||
game_delete(game_set);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ***** game_check_move ***** */
|
||||
/**
|
||||
* @brief test if we can place usable square (here : S_BLANK, S_LIGHTBULB, S_MARK) and nothing else + if we can place something over the limits
|
||||
*
|
||||
* @return EXIT_SUCCESS if there is no error
|
||||
*/
|
||||
bool test_game_check_move(void) {
|
||||
game g = game_new_empty();
|
||||
// put usable square at the start of the list
|
||||
square list[] = LIST_OF_SQUARE;
|
||||
// test limits
|
||||
for (uint i = 0; i < SIZE_LIMIT_GAME + 10; i++) {
|
||||
for (uint j = 0; j < SIZE_LIMIT_GAME + 10; j++) {
|
||||
for (uint index_list = 0; index_list < sizeof(list) / sizeof(list[0]); index_list++) {
|
||||
if (i >= game_nb_rows(g) || j >= game_nb_cols(g) || index_list > USABLE_SQUARE)
|
||||
assert(!game_check_move(g, i, j, list[index_list]));
|
||||
else
|
||||
assert(game_check_move(g, i, j, list[index_list]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// test if we can place something on a wall
|
||||
for (uint i = 0; i < S_BLACKU - S_BLACK0; i++) {
|
||||
game_set_square(g, 0, 0, S_BLACK + i);
|
||||
for (uint index_list = 0; index_list <= USABLE_SQUARE; index_list++) {
|
||||
assert(!game_check_move(g, 0, 0, list[index_list]));
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ********** USAGE ********** */
|
||||
|
||||
int usage(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Usage: %s <testname> [<...>]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* ********** MAIN ********** */
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 1) {
|
||||
usage(argc, argv);
|
||||
}
|
||||
fprintf(stderr, "=> Start test \"%s\"\n", argv[1]);
|
||||
bool ok = true;
|
||||
if (strcmp("dummy", argv[1]) == 0)
|
||||
ok = test_dummy();
|
||||
else if (strcmp("game_print", argv[1]) == 0)
|
||||
ok = test_game_print();
|
||||
else if (strcmp("game_default", argv[1]) == 0)
|
||||
ok = test_game_default();
|
||||
else if (strcmp("game_default_solution", argv[1]) == 0)
|
||||
ok = test_game_default_solution();
|
||||
else if (strcmp("game_new", argv[1]) == 0)
|
||||
ok = test_game_new();
|
||||
else if (strcmp("game_restart", argv[1]) == 0)
|
||||
ok = test_game_restart();
|
||||
else if (strcmp("game_get_square", argv[1]) == 0)
|
||||
ok = test_game_get_square();
|
||||
else if (strcmp("game_is_over", argv[1]) == 0)
|
||||
ok = test_game_is_over();
|
||||
else if (strcmp("game_update_flags", argv[1]) == 0)
|
||||
ok = test_game_update_flags();
|
||||
else if (strcmp("game_play_move", argv[1]) == 0)
|
||||
ok = test_game_play_move();
|
||||
else if (strcmp("game_check_move", argv[1]) == 0)
|
||||
ok = test_game_check_move();
|
||||
else if (strcmp("game_new_empty_ext", argv[1]) == 0)
|
||||
ok = test_game_new_empty_ext();
|
||||
else if (strcmp("game_new_ext", argv[1]) == 0)
|
||||
ok = test_game_new_ext();
|
||||
else {
|
||||
fprintf(stderr, "Error: test \"%s\" not found!\n", argv[1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// print test result
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Test \"%s\" finished: SUCCESS\n", argv[1]);
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Test \"%s\" finished: FAILURE\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "game.h"
|
||||
#include "game_aux.h"
|
||||
#include "game_ext.h"
|
||||
|
||||
#define TAB_SQUARE \
|
||||
{ S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU }
|
||||
|
||||
/* ********** DUMMY ********** */
|
||||
bool test_dummy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_get_black_number ********** */
|
||||
bool test_game_get_black_number() {
|
||||
square tab_square[] = TAB_SQUARE;
|
||||
game g = game_new_empty();
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
// check for each case given in tab_square if the function return the expected result
|
||||
for (int tab_index = 0; tab_index < (sizeof(tab_square) / sizeof(tab_square[0])); tab_index++) {
|
||||
game_set_square(g, i, j, tab_square[tab_index]);
|
||||
if (tab_square[tab_index] == S_BLACKU) {
|
||||
if (game_get_black_number(g, i, j) != -1) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
} else if (tab_square[tab_index] > S_MARK && game_get_black_number(g, i, j) != tab_square[tab_index] - S_BLACK) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_is_black ********** */
|
||||
bool test_game_is_black() {
|
||||
square tab_square[] = TAB_SQUARE;
|
||||
game g = game_new_empty();
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
// check for each case given in tab_square if the function return the expected result
|
||||
for (int tab_index = 0; tab_index < (sizeof(tab_square) / sizeof(tab_square[0])); tab_index++) {
|
||||
game_set_square(g, i, j, tab_square[tab_index]);
|
||||
if (tab_square[tab_index] <= S_MARK) {
|
||||
if (game_is_black(g, i, j)) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!((game_get_square(g, i, j) == tab_square[tab_index]) && game_is_black(g, i, j))) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_is_lightbulb ********** */
|
||||
bool test_game_is_lightbulb() {
|
||||
square tab_square[] = TAB_SQUARE;
|
||||
game g = game_new_empty();
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
// check for each case given in tab_square if the function return the expected result
|
||||
for (int tab_index = 0; tab_index < (sizeof(tab_square) / sizeof(tab_square[0])); tab_index++) {
|
||||
game_set_square(g, i, j, tab_square[tab_index]);
|
||||
if (tab_square[tab_index] == S_LIGHTBULB) {
|
||||
if (!game_is_lightbulb(g, i, j)) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
} else if (game_is_lightbulb(g, 0, 0)) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_is_blank ********** */
|
||||
bool test_game_is_blank() {
|
||||
square tab_square[] = {S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU};
|
||||
game g = game_new_empty();
|
||||
game_set_square(g, 0, 0, S_BLANK);
|
||||
if (!((game_get_square(g, 0, 0) == S_BLANK) && game_is_blank(g, 0, 0))) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
// check for each case given in tab_square if the function return the expected result
|
||||
for (int tab_index = 0; tab_index < (sizeof(tab_square) / sizeof(tab_square[0])); tab_index++) {
|
||||
game_set_square(g, i, j, tab_square[tab_index]);
|
||||
if (game_is_blank(g, i, j)) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_delete ********** */
|
||||
bool test_game_delete() {
|
||||
game g = game_new_empty();
|
||||
assert(g);
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_equal ********** */
|
||||
bool test_game_equal() {
|
||||
square tab_square[] = {S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU};
|
||||
bool wrap[] = {false, false, true, false, false, true, true, true};
|
||||
bool equal = true;
|
||||
uint index_tab = 0;
|
||||
for (int wrap_index = 0; wrap_index < sizeof(wrap) / sizeof(wrap[0]); wrap_index += 2) {
|
||||
game g1 = game_new_empty_ext(DEFAULT_SIZE, DEFAULT_SIZE, wrap[wrap_index]);
|
||||
game g2 = game_new_empty_ext(DEFAULT_SIZE, DEFAULT_SIZE, wrap[wrap_index + 1]);
|
||||
for (int i = 0; i < game_nb_rows(g1); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g1); j++) {
|
||||
// check if index_tab reach end of tab
|
||||
if (index_tab == sizeof(tab_square) / sizeof(tab_square[0])) {
|
||||
index_tab = 0;
|
||||
}
|
||||
game_set_square(g1, i, j, tab_square[index_tab]);
|
||||
game_set_square(g2, i, j, tab_square[index_tab]);
|
||||
index_tab++;
|
||||
}
|
||||
}
|
||||
// check if the two games have the same height, width, and if the two have the wrapping option or not
|
||||
if (game_nb_rows(g1) != game_nb_rows(g2) || game_nb_cols(g1) != game_nb_cols(g2) || game_is_wrapping(g1) != game_is_wrapping(g2)) {
|
||||
equal = false;
|
||||
}
|
||||
// check if each square is the same on each game
|
||||
else {
|
||||
for (int i = 0; i < game_nb_rows(g1); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g1); j++) {
|
||||
if (game_get_square(g1, i, j) != game_get_square(g2, i, j)) {
|
||||
equal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if game_equal return the expected result
|
||||
equal = (equal == game_equal(g1, g2));
|
||||
game_set_square(g1, 0, 0, S_LIGHTBULB);
|
||||
game_update_flags(g1);
|
||||
game_update_flags(g2);
|
||||
assert(!game_equal(g1, g2));
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
/* ********** game_new_empty ********** */
|
||||
bool test_game_new_empty() {
|
||||
game g = game_new_empty();
|
||||
// check if each square is a S_BLANK
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
if (game_get_square(g, i, j) != S_BLANK) {
|
||||
game_delete(g);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
game_delete(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_copy ********** */
|
||||
bool test_game_copy() {
|
||||
square tab_square[] = {S_BLANK, S_LIGHTBULB, S_MARK, S_BLACK0, S_BLACK1, S_BLACK2, S_BLACK3, S_BLACK4, S_BLACKU};
|
||||
uint index_tab = 0;
|
||||
for (int wrap = 0; wrap < 2 /*we only need to test two versions (with and without wrapping)*/; wrap++) {
|
||||
game g1 = game_new_empty_ext(DEFAULT_SIZE, DEFAULT_SIZE, wrap);
|
||||
for (int i = 0; i < game_nb_rows(g1); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g1); j++) {
|
||||
// check if index_tab reach end of tab
|
||||
if (index_tab == sizeof(tab_square) / sizeof(tab_square[0])) {
|
||||
index_tab = 0;
|
||||
}
|
||||
game_set_square(g1, i, j, tab_square[index_tab]);
|
||||
index_tab++;
|
||||
}
|
||||
}
|
||||
game g2 = game_copy(g1);
|
||||
// check if g2 is a correct copy of g1
|
||||
if (!game_equal(g1, g2)) {
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
return false;
|
||||
}
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_undo ********** */
|
||||
bool test_game_undo() {
|
||||
game g1 = game_new_empty();
|
||||
game g2 = game_copy(g1);
|
||||
// check if you can undo without playing a move
|
||||
game_undo(g2);
|
||||
if (!game_equal(g1, g2)) {
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
return false;
|
||||
}
|
||||
game_play_move(g1, 0, 0, S_LIGHTBULB);
|
||||
game_play_move(g1, 1, 1, S_MARK);
|
||||
game g3 = game_copy(g1);
|
||||
// check if the function undo correctly
|
||||
game_play_move(g3, 2, 2, S_LIGHTBULB);
|
||||
game_undo(g3);
|
||||
if (!game_equal(g1, g3)) {
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
game_delete(g3);
|
||||
return false;
|
||||
}
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
game_delete(g3);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** game_redo ********** */
|
||||
bool test_game_redo() {
|
||||
game g1 = game_new_empty();
|
||||
game_play_move(g1, 0, 0, S_LIGHTBULB);
|
||||
game_play_move(g1, 1, 1, S_MARK);
|
||||
game g2 = game_copy(g1);
|
||||
// check if you can redo a non existant move
|
||||
game_undo(g1);
|
||||
game_redo(g1);
|
||||
game_redo(g1);
|
||||
if (!game_equal(g1, g2)) {
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
return false;
|
||||
}
|
||||
game_play_move(g1, 2, 2, S_LIGHTBULB);
|
||||
game_play_move(g2, 2, 2, S_LIGHTBULB);
|
||||
// check if the function redo correctly
|
||||
game_undo(g1);
|
||||
game_redo(g1);
|
||||
if (!game_equal(g1, g2)) {
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
return false;
|
||||
}
|
||||
game_delete(g1);
|
||||
game_delete(g2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********** usage ********** */
|
||||
void usage(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Usage: %s <testname>\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* ********** main ********** */
|
||||
int main(int argc, char* argv[]) {
|
||||
bool success = false;
|
||||
if (argc != 2) {
|
||||
usage(argc, argv);
|
||||
} else if (strcmp("dummy", argv[1]) == 0) {
|
||||
success = test_dummy();
|
||||
} else if (strcmp("game_new_empty", argv[1]) == 0) {
|
||||
success = test_game_new_empty();
|
||||
} else if (strcmp("game_copy", argv[1]) == 0) {
|
||||
success = test_game_copy();
|
||||
} else if (strcmp("game_equal", argv[1]) == 0) {
|
||||
success = test_game_equal();
|
||||
} else if (strcmp("game_delete", argv[1]) == 0) {
|
||||
success = test_game_delete();
|
||||
} else if (strcmp("game_is_blank", argv[1]) == 0) {
|
||||
success = test_game_is_blank();
|
||||
} else if (strcmp("game_is_lightbulb", argv[1]) == 0) {
|
||||
success = test_game_is_lightbulb();
|
||||
} else if (strcmp("game_is_black", argv[1]) == 0) {
|
||||
success = test_game_is_black();
|
||||
} else if (strcmp("game_get_black_number", argv[1]) == 0) {
|
||||
success = test_game_get_black_number();
|
||||
} else if (strcmp("game_undo", argv[1]) == 0) {
|
||||
success = test_game_undo();
|
||||
} else if (strcmp("game_redo", argv[1]) == 0) {
|
||||
success = test_game_redo();
|
||||
} else {
|
||||
fprintf(stderr, "test \"%s\" is not a valid test name.\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (success) {
|
||||
fprintf(stderr, "test \"%s\" finished successfully\n", argv[1]);
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "test \"%s\" error\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "game.h"
|
||||
#include "game_aux.h"
|
||||
#include "game_ext.h"
|
||||
|
||||
#define NBCHARERR 4
|
||||
#define CHAR0ASCII 48
|
||||
|
||||
/**
|
||||
* @brief Edit the stringError with all errors of g
|
||||
* @param g the game to analyze
|
||||
* @param stringError A pointer toward a string allocated before
|
||||
* @pre @p stringError size must be at least height * width * NBCHARERR
|
||||
* @return true if there is an error on the game g and the stringError has been modified
|
||||
*/
|
||||
bool checkerrors(cgame g, char* stringError) {
|
||||
if (stringError == NULL || g == NULL) {
|
||||
return -1;
|
||||
}
|
||||
uint index_taberr = 0;
|
||||
// initialize stringError
|
||||
stringError[0] = '\0';
|
||||
for (int i = 0; i < game_nb_rows(g); i++) {
|
||||
for (int j = 0; j < game_nb_cols(g); j++) {
|
||||
// check each case
|
||||
if (game_has_error(g, i, j)) {
|
||||
// if error append stringError with coordinate of the error,
|
||||
stringError[index_taberr] = i + CHAR0ASCII;
|
||||
index_taberr++;
|
||||
stringError[index_taberr] = ':';
|
||||
index_taberr++;
|
||||
stringError[index_taberr] = j + CHAR0ASCII;
|
||||
index_taberr++;
|
||||
stringError[index_taberr] = ' ';
|
||||
index_taberr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if stringError changed return true
|
||||
if (stringError[0] != '\0') {
|
||||
stringError[index_taberr] = '\0';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief scan the coordinate and check if the move is possible if yes play it
|
||||
* @param g the game to check and play
|
||||
* @param s the square to update
|
||||
*/
|
||||
void checkPlayMove(game g, square s) {
|
||||
uint i;
|
||||
uint j;
|
||||
if (scanf(" %u %u", &i, &j) == 2) {
|
||||
if (game_check_move(g, i, j, s))
|
||||
game_play_move(g, i, j, s);
|
||||
else
|
||||
printf("Coordonnées invalide.\n");
|
||||
game_print(g);
|
||||
return;
|
||||
}
|
||||
printf("Commande inconnue.\n");
|
||||
}
|
||||
|
||||
void printhelp(void) {
|
||||
printf("Liste des différentes commandes :\n");
|
||||
printf("h : Affiche cette aide.\n");
|
||||
printf("r : Réinitialise la partie.\n");
|
||||
printf("q : Quitter la partie (abandon).\n");
|
||||
printf("z : Annulez le coup (undo).\n");
|
||||
printf("y : Annulez l'annulation du coup (redo).\n");
|
||||
printf("l <i> <j> : Place une ampoule (*) à la position (<i>,<j>).\n");
|
||||
printf("m <i> <j> : Place une marque (-) à la position (<i>,<j>).\n");
|
||||
printf("b <i> <j> : Place une case vide ( ) à la position (<i>,<j>).\n");
|
||||
}
|
||||
|
||||
void usage(int argc, char* argv[]) {
|
||||
printf("Usage : %s => Joue la partie par défaut\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
game g;
|
||||
if (argc == 1)
|
||||
// Create new game
|
||||
g = game_default();
|
||||
else
|
||||
usage(argc, argv);
|
||||
// init string for errors
|
||||
char stringError[game_nb_rows(g) * game_nb_cols(g) * NBCHARERR];
|
||||
char c;
|
||||
// print game
|
||||
game_print(g);
|
||||
// test if game is over
|
||||
while (!game_is_over(g)) {
|
||||
// print errors
|
||||
if (checkerrors(g, stringError))
|
||||
printf("Il y a un problème case(s): %s\n", stringError);
|
||||
printf("Entrez une commande (h pour afficher l'aide): ");
|
||||
// scan the first command without args
|
||||
if (scanf(" %c", &c)) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
printhelp();
|
||||
break;
|
||||
case 'r':
|
||||
game_restart(g);
|
||||
printf("Partie réinitialisé avec succes !\n");
|
||||
game_print(g);
|
||||
break;
|
||||
case 'q':
|
||||
printf("Solution: \n");
|
||||
game solution = game_default_solution();
|
||||
game_print(solution);
|
||||
game_delete(solution);
|
||||
game_delete(g);
|
||||
printf("shame\n");
|
||||
return EXIT_SUCCESS;
|
||||
break;
|
||||
case 'z':
|
||||
game_undo(g);
|
||||
game_print(g);
|
||||
break;
|
||||
case 'y':
|
||||
game_redo(g);
|
||||
game_print(g);
|
||||
break;
|
||||
case 'l':
|
||||
checkPlayMove(g, S_LIGHTBULB);
|
||||
break;
|
||||
case 'm':
|
||||
checkPlayMove(g, S_MARK);
|
||||
break;
|
||||
case 'b':
|
||||
checkPlayMove(g, S_BLANK);
|
||||
break;
|
||||
default:
|
||||
printf("Commande inconnue.\n");
|
||||
}
|
||||
} else {
|
||||
printf("Commande inconnue.\n");
|
||||
}
|
||||
}
|
||||
printf("congratulation\n");
|
||||
game_delete(g);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
#include "history.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void memoryError(void) {
|
||||
fprintf(stderr, "Not enought memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void errPointer(void) {
|
||||
fprintf(stderr, "Error on the given pointer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
history history_alloc(void) {
|
||||
history h = (history)malloc(sizeof(struct s_history));
|
||||
if (h == NULL)
|
||||
memoryError();
|
||||
h->i = 0;
|
||||
h->j = 0;
|
||||
h->next = NULL;
|
||||
h->prev = NULL;
|
||||
return h;
|
||||
}
|
||||
|
||||
void history_free(history h) {
|
||||
free(h);
|
||||
h = NULL;
|
||||
}
|
||||
|
||||
history history_create_empty(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool history_is_empty(history h) {
|
||||
return h == NULL;
|
||||
}
|
||||
|
||||
history history_next(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
return h->next;
|
||||
}
|
||||
|
||||
history history_prev(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
return h->prev;
|
||||
}
|
||||
|
||||
square history_state(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
return h->state;
|
||||
}
|
||||
|
||||
uint history_i(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
return h->i;
|
||||
}
|
||||
|
||||
uint history_j(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
return h->j;
|
||||
}
|
||||
|
||||
history history_last(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
if (history_is_empty(history_next(h)))
|
||||
return h;
|
||||
return history_last(history_next(h));
|
||||
}
|
||||
|
||||
history history_first(history h) {
|
||||
if (history_is_empty(h))
|
||||
errPointer();
|
||||
if (history_is_empty(history_prev(h)))
|
||||
return h;
|
||||
return history_first(history_prev(h));
|
||||
}
|
||||
|
||||
history history_insert_first(history h, square state, uint i, uint j) {
|
||||
history new = history_alloc();
|
||||
new->state = state;
|
||||
new->i = i;
|
||||
new->j = j;
|
||||
new->next = h;
|
||||
if (!history_is_empty(h)) {
|
||||
h = history_first(h);
|
||||
h->prev = new;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
history history_insert_after(history h, history p, square state, uint i, uint j) {
|
||||
if (history_is_empty(h) || history_is_empty(p))
|
||||
errPointer();
|
||||
history new = history_alloc();
|
||||
new->state = state;
|
||||
new->i = i;
|
||||
new->j = j;
|
||||
new->next = p->next;
|
||||
p->next = new;
|
||||
new->prev = p;
|
||||
if (!history_is_empty(history_next(new)))
|
||||
new->next->prev = new;
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_delete_after(history h, history p) {
|
||||
if (history_is_empty(p))
|
||||
errPointer();
|
||||
if (!history_is_empty(history_next(p))) {
|
||||
history to_be_deleted = p->next;
|
||||
if (!history_is_empty(history_next(to_be_deleted))) {
|
||||
to_be_deleted->next->prev = p;
|
||||
}
|
||||
p->next = to_be_deleted->next;
|
||||
history_free(to_be_deleted);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_insert_before(history h, history p, square state, uint i, uint j) {
|
||||
if (history_is_empty(h) || history_is_empty(p))
|
||||
errPointer();
|
||||
history new = history_alloc();
|
||||
new->state = state;
|
||||
new->i = i;
|
||||
new->j = j;
|
||||
new->next = p;
|
||||
new->prev = p->prev;
|
||||
p->prev = new;
|
||||
if (!history_is_empty(history_prev(new)))
|
||||
new->prev->next = new;
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_delete_before(history h, history p) {
|
||||
if (history_is_empty(h) || history_is_empty(p))
|
||||
errPointer();
|
||||
if (!history_is_empty(history_prev(p))) {
|
||||
history to_be_deleted = p->prev;
|
||||
if (!history_is_empty(history_prev(to_be_deleted))) {
|
||||
to_be_deleted->prev->next = p;
|
||||
}
|
||||
p->prev = to_be_deleted->prev;
|
||||
history_free(to_be_deleted);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_delete_first(history h) {
|
||||
if (!history_is_empty(h)) {
|
||||
h = history_first(h);
|
||||
history tmp = h->next;
|
||||
history_free(h);
|
||||
h = tmp;
|
||||
if (!history_is_empty(h)) {
|
||||
h->prev = NULL;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_append(history h, square state, uint i, uint j) {
|
||||
if (history_is_empty(h))
|
||||
return history_insert_first(h, state, i, j);
|
||||
if (history_is_empty(history_next(h)))
|
||||
return history_insert_after(h, h, state, i, j);
|
||||
history_append(history_next(h), state, i, j);
|
||||
return h;
|
||||
}
|
||||
|
||||
history history_delete_all_after(history h, history p) {
|
||||
if (history_is_empty(p))
|
||||
return h;
|
||||
if (history_is_empty(history_next(p)))
|
||||
return h;
|
||||
history_delete_all_after(h, history_next(p));
|
||||
return history_delete_after(h, p);
|
||||
}
|
||||
|
||||
void history_delete_entire_history(history h) {
|
||||
if (history_is_empty(h))
|
||||
return;
|
||||
if (history_is_empty(history_prev(h)))
|
||||
return history_free(history_delete_all_after(h, h));
|
||||
return history_delete_entire_history(history_prev(h));
|
||||
}
|
||||
|
||||
history history_copy(history h) {
|
||||
history copy_h = h;
|
||||
if (history_is_empty(h)) {
|
||||
return h;
|
||||
}
|
||||
h = history_first(h);
|
||||
uint index_h = 0;
|
||||
while (h != copy_h) {
|
||||
h = history_next(h);
|
||||
index_h++;
|
||||
}
|
||||
h = history_first(h);
|
||||
history h2 = history_insert_first(history_create_empty(), h->state, h->i, h->j);
|
||||
while (!history_is_empty(history_next(h))) {
|
||||
h = history_next(h);
|
||||
h2 = history_insert_after(h2, h2, h->state, h->i, h->j);
|
||||
h2 = history_next(h2);
|
||||
}
|
||||
h2 = history_first(h2);
|
||||
for (uint i = 0; i < index_h; i++) {
|
||||
h2 = history_next(h2);
|
||||
}
|
||||
return h2;
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
#ifndef __HISTORY_H__
|
||||
#define __HISTORY_H__
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct s_history* history;
|
||||
|
||||
#include "game.h"
|
||||
|
||||
struct s_history {
|
||||
square state;
|
||||
uint i;
|
||||
uint j;
|
||||
struct s_history* next;
|
||||
struct s_history* prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief fprintf not enought memory + exit
|
||||
**/
|
||||
void memoryError(void);
|
||||
|
||||
/**
|
||||
* @brief fprintf error on the given pointer + exit
|
||||
*/
|
||||
void errPointer(void);
|
||||
|
||||
/**
|
||||
* @brief Alloc a new empty history.
|
||||
* @return The allocated history.
|
||||
**/
|
||||
history history_alloc();
|
||||
|
||||
/**
|
||||
* @brief Free the given history.
|
||||
* @param h The history to be free.
|
||||
**/
|
||||
void history_free(history h);
|
||||
|
||||
/**
|
||||
* @brief Create a empty history object
|
||||
*
|
||||
* @return An empty history
|
||||
**/
|
||||
history history_create_empty(void);
|
||||
|
||||
/**
|
||||
* @brief Delete every element of h (before and after)
|
||||
*
|
||||
* @param h the head of the history
|
||||
*/
|
||||
void history_delete_entire_history(history h);
|
||||
|
||||
/**
|
||||
* @brief Test if the given history is empty or not.
|
||||
*
|
||||
* @param h the history to test.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return true if the history is empty
|
||||
* @return false if the history isn't empty
|
||||
*/
|
||||
bool history_is_empty(history h);
|
||||
|
||||
/**
|
||||
* @brief Gets the next element of the given history.
|
||||
*
|
||||
* @param h An history.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return the next of the given history.
|
||||
*/
|
||||
history history_next(history h);
|
||||
|
||||
/**
|
||||
* @brief Gets the previous element of the given history.
|
||||
*
|
||||
* @param h An history.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return the previous element of the given history.
|
||||
*/
|
||||
history history_prev(history h);
|
||||
|
||||
/**
|
||||
* @brief Gets the state of the given history
|
||||
*
|
||||
* @param h An history.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return the state of the given history
|
||||
*/
|
||||
square history_state(history h);
|
||||
|
||||
/**
|
||||
* @brief Get the coordinates i of the given history.
|
||||
*
|
||||
* @param h An history.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return the coordinates i.
|
||||
*/
|
||||
uint history_i(history h);
|
||||
|
||||
/**
|
||||
* @brief Get the coordinates j of the given history.
|
||||
*
|
||||
* @param h An history.
|
||||
* @pre @p h must be a valid pointer toward an history .
|
||||
* @return the coordinates j.
|
||||
*/
|
||||
uint history_j(history h);
|
||||
|
||||
/**
|
||||
* @brief Insert a new element a the beginning of the history.
|
||||
*
|
||||
* @param h An history (empty or not)
|
||||
* @param state state of the new element
|
||||
* @param i the coordinate i of the new element
|
||||
* @param j the coordinate j of the new element
|
||||
* @return The new first element of history
|
||||
*/
|
||||
history history_insert_first(history h, square state, uint i, uint j);
|
||||
/**
|
||||
* @brief Delete the first element of the history
|
||||
*
|
||||
* @param h An history
|
||||
* @return the new first element of the history
|
||||
*/
|
||||
history history_delete_first(history h);
|
||||
|
||||
/**
|
||||
* @brief Insert a new element after p
|
||||
*
|
||||
* @param h An history
|
||||
* @param p Where we insert after the new element
|
||||
* @param state The state of the new element
|
||||
* @param i the coordinate i of the new element
|
||||
* @param j the coordinate j of the new element
|
||||
* @pre @p h must be a valid pointer toward an history.
|
||||
* @pre @p p must be a valid pointer toward an history element.
|
||||
* @return h
|
||||
*/
|
||||
history history_insert_after(history h, history p, square state, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Delete the element after p
|
||||
*
|
||||
* @param h An history
|
||||
* @param p where we delete after
|
||||
* @pre @p h must be a valid pointer toward an history.
|
||||
* @pre @p p must be a valid pointer toward an history element.
|
||||
* @return h
|
||||
*/
|
||||
history history_delete_after(history h, history p);
|
||||
|
||||
/**
|
||||
* @brief Insert a new element before p
|
||||
*
|
||||
* @param h An history
|
||||
* @param p Where we insert before the new element
|
||||
* @param state The state of the new element
|
||||
* @param i the coordinate i of the new element
|
||||
* @param j the coordinate j of the new element
|
||||
* @pre @p h must be a valid pointer toward an history.
|
||||
* @pre @p p must be a valid pointer toward an history element.
|
||||
* @return h
|
||||
*/
|
||||
history history_insert_before(history h, history p, square state, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Delete the element before p
|
||||
*
|
||||
* @param h An history
|
||||
* @param p where we delete before
|
||||
* @pre @p h must be a valid pointer toward an history.
|
||||
* @pre @p p must be a valid pointer toward an history element.
|
||||
* @return h
|
||||
*/
|
||||
history history_delete_before(history h, history p);
|
||||
|
||||
/**
|
||||
* @brief Gets the last element of the history
|
||||
*
|
||||
* @param h An history
|
||||
* @return The last element of the given history
|
||||
*/
|
||||
history history_last(history h);
|
||||
|
||||
/**
|
||||
* @brief Gets the first element of the history
|
||||
*
|
||||
* @param h An history
|
||||
* @return The first element of the history.
|
||||
*/
|
||||
history history_first(history h);
|
||||
|
||||
/**
|
||||
* @brief Add an element at the end of the list.
|
||||
*
|
||||
* @param h an history
|
||||
* @param state the state of the new element
|
||||
* @param i the coordinate i of the new element
|
||||
* @param j the coordinate j of the new element
|
||||
* @return h
|
||||
*/
|
||||
history history_append(history h, square state, uint i, uint j);
|
||||
|
||||
/**
|
||||
* @brief Delete all the elements after p
|
||||
*
|
||||
* @param h an history
|
||||
* @param p an element of h
|
||||
* @return h
|
||||
*/
|
||||
history history_delete_all_after(history h, history p);
|
||||
|
||||
/**
|
||||
* @brief Copy history
|
||||
*
|
||||
* @param h an history
|
||||
* @return the new history
|
||||
*/
|
||||
history history_copy(history h);
|
||||
#endif
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
#include "history.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool test_history_alloc(void) {
|
||||
history new = history_alloc();
|
||||
assert(new);
|
||||
history_free(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_create_empty(void) {
|
||||
assert(history_create_empty() == NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_delete_entire_history(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history_insert_after(new, new, S_MARK, 3, 3);
|
||||
assert(new->next);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_is_empty(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
assert(!history_is_empty(new));
|
||||
assert(history_is_empty(history_create_empty()));
|
||||
history_free(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_next(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
new = history_insert_after(new, new, S_BLACKU, 2, 6);
|
||||
assert(new->next == history_next(new));
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_prev(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
new = history_insert_after(new, new, S_BLACKU, 2, 6);
|
||||
new = history_next(new);
|
||||
assert(new->prev == history_prev(new));
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_insert_first(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history_free(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_delete_first(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
new = history_insert_after(new, new, S_BLACK3, 2, 5);
|
||||
new = history_next(new);
|
||||
history_delete_first(new);
|
||||
assert(new->prev == NULL);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_insert_after(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
history_insert_after(new, new, S_BLACK2, 4, 3);
|
||||
assert(new->next->next == newafter);
|
||||
assert(new == newafter->prev->prev);
|
||||
assert(new->next->state == S_BLACK2);
|
||||
assert(new->next->i == 4);
|
||||
assert(new->next->j == 3);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_delete_after(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
history_insert_after(new, new, S_BLACK2, 4, 3);
|
||||
history_delete_after(new, new);
|
||||
assert(new->next == newafter);
|
||||
assert(new == newafter->prev);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_insert_before(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
history_insert_before(new, newafter, S_BLACK2, 4, 3);
|
||||
assert(new->next->next == newafter);
|
||||
assert(new == newafter->prev->prev);
|
||||
assert(new->next->state == S_BLACK2);
|
||||
assert(new->next->i == 4);
|
||||
assert(new->next->j == 3);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_delete_before(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
history_insert_after(new, new, S_BLACK2, 4, 3);
|
||||
history_delete_before(new, newafter);
|
||||
assert(new->next == newafter);
|
||||
assert(new == newafter->prev);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_last(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
assert(history_last(new) == newafter);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_first(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history newafter = history_alloc();
|
||||
newafter->prev = new;
|
||||
new->next = newafter;
|
||||
assert(history_first(newafter) == new);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_append(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
history_append(new, S_BLACK3, 2, 4);
|
||||
history last = history_last(new);
|
||||
assert(new->next == last);
|
||||
assert(last->state == S_BLACK3);
|
||||
assert(last->i == 2);
|
||||
assert(last->j == 4);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_history_copy(void) {
|
||||
history new = history_insert_first(history_create_empty(), S_LIGHTBULB, 4, 3);
|
||||
assert(new);
|
||||
new = history_insert_after(new, new, S_BLANK, 5, 8);
|
||||
history h2 = history_copy(new);
|
||||
assert(history_state(h2) == history_state(new));
|
||||
assert(history_state(history_next(h2)) == history_state(history_next(new)));
|
||||
history_delete_entire_history(h2);
|
||||
history_delete_entire_history(new);
|
||||
return true;
|
||||
}
|
||||
|
||||
int usage(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Usage: %s <testname> [<...>]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 1) {
|
||||
usage(argc, argv);
|
||||
}
|
||||
fprintf(stderr, "=> Start test \"%s\"\n", argv[1]);
|
||||
bool ok = true;
|
||||
if (strcmp("history_alloc", argv[1]) == 0)
|
||||
ok = test_history_alloc();
|
||||
else if (strcmp("history_create_empty", argv[1]) == 0)
|
||||
ok = test_history_create_empty();
|
||||
else if (strcmp("history_delete_entire_history", argv[1]) == 0)
|
||||
ok = test_history_delete_entire_history();
|
||||
else if (strcmp("history_is_empty", argv[1]) == 0)
|
||||
ok = test_history_is_empty();
|
||||
else if (strcmp("history_next", argv[1]) == 0)
|
||||
ok = test_history_next();
|
||||
else if (strcmp("history_prev", argv[1]) == 0)
|
||||
ok = test_history_prev();
|
||||
else if (strcmp("history_insert_first", argv[1]) == 0)
|
||||
ok = test_history_insert_first();
|
||||
else if (strcmp("history_delete_first", argv[1]) == 0)
|
||||
ok = test_history_delete_first();
|
||||
else if (strcmp("history_insert_after", argv[1]) == 0)
|
||||
ok = test_history_insert_after();
|
||||
else if (strcmp("history_delete_after", argv[1]) == 0)
|
||||
ok = test_history_delete_after();
|
||||
else if (strcmp("history_insert_before", argv[1]) == 0)
|
||||
ok = test_history_insert_before();
|
||||
else if (strcmp("history_delete_before", argv[1]) == 0)
|
||||
ok = test_history_delete_before();
|
||||
else if (strcmp("history_last", argv[1]) == 0)
|
||||
ok = test_history_last();
|
||||
else if (strcmp("history_first", argv[1]) == 0)
|
||||
ok = test_history_first();
|
||||
else if (strcmp("history_append", argv[1]) == 0)
|
||||
ok = test_history_append();
|
||||
else if (strcmp("history_copy", argv[1]) == 0)
|
||||
ok = test_history_copy();
|
||||
else {
|
||||
fprintf(stderr, "Error: test \"%s\" not found!\n", argv[1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// print test result
|
||||
if (ok) {
|
||||
fprintf(stderr, "Test \"%s\" finished: SUCCESS\n", argv[1]);
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Test \"%s\" finished: FAILURE\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user