Merge branch 'main' of gitlab.emi.u-bordeaux.fr:pt2/teams-s4/tm07/lightup-07c

This commit is contained in:
Théophyl Hoguet committed 2022-02-07 21:48:13 +01:00
commit 3e370a8696
21 files changed
+3255

No files matched your search

+148
View File
@@ -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
...
+2
View File
@@ -0,0 +1,2 @@
build/
.vscode/
+114
View File
@@ -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"
},
]
}
+9
View File
@@ -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"
}
+87
View File
@@ -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)
+72
View File
@@ -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> |
+291
View File
@@ -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);
}
+316
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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__
+15
View File
@@ -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);
}
}
+31
View File
@@ -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
+219
View File
@@ -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;
}
}
+522
View File
@@ -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;
}
}
+323
View File
@@ -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
View File
@@ -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;
}
+218
View File
@@ -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;
}
+219
View File
@@ -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
View File
@@ -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;
}
}