Initial commit

This commit is contained in:
github-classroom[bot] 2025-01-14 11:07:40 +00:00 committed by GitHub
commit 87dcb960bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 6733 additions and 0 deletions

1566
Doxyfile Normal file

File diff suppressed because it is too large Load diff

6
README.md Normal file
View file

@ -0,0 +1,6 @@
### if.03.22 Procedural Programming
# Assignment Recursion and Abstract Data Type
## Tower of Hanoi
With this assignment you shall implement abstract data types and a recursive algorithm in C.
Clone this assignment, open the index.html, read the assignment instructions and try to make all unit tests green.

23
config.h Normal file
View file

@ -0,0 +1,23 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Exercise Number: n/a
* Title: Configuration Options
* Author: S. Schraml
* Date: n/a
* ----------------------------------------------------------
* Description:
* Global application configuration options
* ----------------------------------------------------------
*/
#ifndef ___CONFIGURATION_H
#define ___CONFIGURATION_H
/** Configures the maximum number of supported disks */
#define MAX_DISKS 64
/** Configures to visual left offset of the board (in characters) */
#define VIS_BOARD_OFFSET 12
/** Configures the delay per move in 0.1 seconds */
#define MOVE_DELAY 4
#endif

14
doxygen_extra.css Normal file
View file

@ -0,0 +1,14 @@
code {
background: #eaeaea;
padding: 0 0.3em;
border-radius: 4px;
}
div.fragment {
padding: 0.5em;
border-radius: 4px;
margin: 1em 0;
}
div.line {
line-height: 1.4;
}

21
general.h Normal file
View file

@ -0,0 +1,21 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Exercise Number: n/a
* Title: general.h
* Author: P. Bauer
* Date: n/a
* ----------------------------------------------------------
* Description:
* General usable definitions.
* ----------------------------------------------------------
*/
#ifndef ___GENERAL_H
#define ___GENERAL_H
/** Convenience macro do get maximum of two numbers */
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/** Convenience macro do get maximum of two numbers */
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif

BIN
html/bc_s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
html/bdwn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

BIN
html/closed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

BIN
html/doc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

1730
html/doxygen.css Normal file

File diff suppressed because it is too large Load diff

BIN
html/doxygen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

14
html/doxygen_extra.css Normal file
View file

@ -0,0 +1,14 @@
code {
background: #eaeaea;
padding: 0 0.3em;
border-radius: 4px;
}
div.fragment {
padding: 0.5em;
border-radius: 4px;
margin: 1em 0;
}
div.line {
line-height: 1.4;
}

121
html/dynsections.js Normal file
View file

@ -0,0 +1,121 @@
/*
@licstart The following is the entire license notice for the JavaScript code in this file.
The MIT License (MIT)
Copyright (C) 1997-2020 by Dimitri van Heesch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@licend The above is the entire license notice for the JavaScript code in this file
*/
function toggleVisibility(linkObj)
{
var base = $(linkObj).attr('id');
var summary = $('#'+base+'-summary');
var content = $('#'+base+'-content');
var trigger = $('#'+base+'-trigger');
var src=$(trigger).attr('src');
if (content.is(':visible')===true) {
content.hide();
summary.show();
$(linkObj).addClass('closed').removeClass('opened');
$(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');
} else {
content.show();
summary.hide();
$(linkObj).removeClass('closed').addClass('opened');
$(trigger).attr('src',src.substring(0,src.length-10)+'open.png');
}
return false;
}
function updateStripes()
{
$('table.directory tr').
removeClass('even').filter(':visible:even').addClass('even');
}
function toggleLevel(level)
{
$('table.directory tr').each(function() {
var l = this.id.split('_').length-1;
var i = $('#img'+this.id.substring(3));
var a = $('#arr'+this.id.substring(3));
if (l<level+1) {
i.removeClass('iconfopen iconfclosed').addClass('iconfopen');
a.html('&#9660;');
$(this).show();
} else if (l==level+1) {
i.removeClass('iconfclosed iconfopen').addClass('iconfclosed');
a.html('&#9658;');
$(this).show();
} else {
$(this).hide();
}
});
updateStripes();
}
function toggleFolder(id)
{
// the clicked row
var currentRow = $('#row_'+id);
// all rows after the clicked row
var rows = currentRow.nextAll("tr");
var re = new RegExp('^row_'+id+'\\d+_$', "i"); //only one sub
// only match elements AFTER this one (can't hide elements before)
var childRows = rows.filter(function() { return this.id.match(re); });
// first row is visible we are HIDING
if (childRows.filter(':first').is(':visible')===true) {
// replace down arrow by right arrow for current row
var currentRowSpans = currentRow.find("span");
currentRowSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
currentRowSpans.filter(".arrow").html('&#9658;');
rows.filter("[id^=row_"+id+"]").hide(); // hide all children
} else { // we are SHOWING
// replace right arrow by down arrow for current row
var currentRowSpans = currentRow.find("span");
currentRowSpans.filter(".iconfclosed").removeClass("iconfclosed").addClass("iconfopen");
currentRowSpans.filter(".arrow").html('&#9660;');
// replace down arrows by right arrows for child rows
var childRowsSpans = childRows.find("span");
childRowsSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
childRowsSpans.filter(".arrow").html('&#9658;');
childRows.show(); //show all children
}
updateStripes();
}
function toggleInherit(id)
{
var rows = $('tr.inherit.'+id);
var img = $('tr.inherit_header.'+id+' img');
var src = $(img).attr('src');
if (rows.filter(':first').is(':visible')===true) {
rows.css('display','none');
$(img).attr('src',src.substring(0,src.length-8)+'closed.png');
} else {
rows.css('display','table-row'); // using show() causes jump in firefox
$(img).attr('src',src.substring(0,src.length-10)+'open.png');
}
}
/* @license-end */

82
html/files.html Normal file
View file

@ -0,0 +1,82 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tower of Hanoi: File List</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen_extra.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Tower of Hanoi
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.18 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
</div><!-- top -->
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="header">
<div class="headertitle">
<div class="title">File List</div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock">Here is a list of all files with brief descriptions:</div><div class="directory">
<table class="directory">
<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a href="mainpage_8h_source.html"><span class="icondoc"></span></a><a class="el" href="mainpage_8h.html" target="_self">mainpage.h</a></td><td class="desc"></td></tr>
</table>
</div><!-- directory -->
</div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Dec 19 2020 12:38:17 for Tower of Hanoi by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.18
</small></address>
</body>
</html>

BIN
html/folderclosed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

BIN
html/folderopen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

137
html/index.html Normal file
View file

@ -0,0 +1,137 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tower of Hanoi: Main Page</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen_extra.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Tower of Hanoi
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.18 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
</div><!-- top -->
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="PageDoc"><div class="header">
<div class="headertitle">
<div class="title">Tower of Hanoi Documentation</div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1><a class="anchor" id="intro"></a>
Introduction</h1>
<p>The Tower of Hanoi is a mathematical game or puzzle. The board consists of three rods and a number of disks of different sizes, which can slide onto any rod. At the beginning, all disks are placed on the left rod in ascending order of their size, the smallest disk at the top.</p>
<p>The objective of the puzzle is to move the entire stack of disks from the left to the right rod, obeying the following rules:</p><ul>
<li>Only one disk can be moved at a time.</li>
<li>Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty rod.</li>
<li>No larger disk may be placed on top of a smaller disk.</li>
</ul>
<p>The minimal number of moves required to solve a Tower of Hanoi puzzle is 2n 1, where n is the number of disks. (source: Wikipedia)</p>
<h1><a class="anchor" id="objective"></a>
Assignment Objective</h1>
<p>In this assignment the recursiver solver for the Tower of Hanoi puzzle shall be implemented together with the required Abstract Data Types.</p>
<p>Abstract Data Types for single disks (<code>toh_disc.*</code>) and the 'Tower of Hanoi' board (<code>toh_board.*</code>) are required. The 'Tower of Hanoi' solver (<code>toh_solver.*</code>) is not an ADT but a function library.</p>
<p><b>Configuration</b></p>
<p>A configurable number of disk instances shall be available, this number is configered in <code>config.c</code> <code>MAX_DISKS</code>. There shall be exactly one instance of a board available.</p>
<p>Other configuration options affects the visualization only, but has no effect on the game.</p>
<p><b>Setup and Execution</b></p>
<p>The solver shall initialize the board with a given number of disks. This number must be less the configured maximum number of disks. Whereas the <code>MAX_DISKS</code> defines the number of avialable disk instances, the number of disks applied to the initialization function of the solver defines the number of disks for the next game.</p>
<p>After the board is initialized via solver, the solver shall solve that game using the following recursive algorithm:</p><ol type="1">
<li>move (n-1) disks from source rod to intermediate rod using target rod as buffer</li>
<li>move remaining (1) disk from source rod to target rod</li>
<li>move (n-1) disks from intermediate rod to target rod using source rod as buffer until all disks are moved from the left to the right rod.</li>
</ol>
<p><b>Visualization</b></p>
<p>The solver uses the ready-to-use Tower of Hanoi visualizer (<code>toh_visualizer.h</code>) to present the ANSI graphic of the game. A printout using function <code>toh_visualize(...)</code> is required</p><ul>
<li>after the board is initialized</li>
<li>after the move of a single disk</li>
<li>after the game is completely solved, a message telling about success or error can be applied to this viusalization step.</li>
</ul>
<h1><a class="anchor" id="assignment"></a>
Assignment</h1>
<ol type="1">
<li>Complete forward declarations, types, and function for ADTs in <code>toh_disk.h</code> and <code>toh_board.h</code> as well as in <code>toh_solver.h</code>.<ul>
<li>Types in template files may be marked as <code>&lt;type&gt;</code> within header and source files or may be omitted completely. Replace <code>&lt;type&gt;</code> with the correct type and complete missing types.</li>
<li>Parameter lists of function in a template files may be missing or incomplete</li>
</ul>
</li>
<li>Make the program and tests compile: Implement all functions declared in the headers EMTPY (return nothing, 0, false as required)<ul>
<li>All unit tests shall run but FAIL after this step</li>
<li><b>&ndash;COMMIT&ndash;</b></li>
</ul>
</li>
<li>Implement the empty functions one by one to make the unit tests pass one by one.<ul>
<li>Proposed order: disk, board, solver.</li>
<li>The purpose of a function is specified as API documentation within the header files.</li>
<li>Obey comments in source files.</li>
<li><b>&ndash;COMMIT&ndash; after each implemented function.</b></li>
</ul>
</li>
<li>Implement the missing parts to run the game in <code>toh_main_driver.c</code> methods</li>
<li>Run the game and enjoy</li>
</ol>
<h1><a class="anchor" id="notes"></a>
Notes</h1>
<ol type="1">
<li>This program requires compile option <code>-std=gnu11</code> becuase timer functions, please don't change. gnu11 extends c11 and is expected not to cause an troubles or differences in implementation</li>
<li>Visualization is implemented for Linux shell, it will not work on Windows.</li>
<li>Sometimes changes are not properly detected by incremental builds. If something very strange happens during compilation, try to run <code>make clean</code> followed by <code>make</code> to start a clean build. This approach is also recommended after everthing is done, because some compiler warning appears only in clean builds. </li>
</ol>
</div></div><!-- PageDoc -->
</div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Dec 19 2020 12:38:17 for Tower of Hanoi by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.18
</small></address>
</body>
</html>

35
html/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

79
html/mainpage_8h.html Normal file
View file

@ -0,0 +1,79 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tower of Hanoi: mainpage.h File Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen_extra.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Tower of Hanoi
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.18 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">mainpage.h File Reference</div> </div>
</div><!--header-->
<div class="contents">
<p><a href="mainpage_8h_source.html">Go to the source code of this file.</a></p>
</div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Dec 19 2020 12:38:17 for Tower of Hanoi by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.18
</small></address>
</body>
</html>

View file

@ -0,0 +1,78 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tower of Hanoi: mainpage.h Source File</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen_extra.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Tower of Hanoi
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.18 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
</div><!-- top -->
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="header">
<div class="headertitle">
<div class="title">mainpage.h</div> </div>
</div><!--header-->
<div class="contents">
<a href="mainpage_8h.html">Go to the documentation of this file.</a><div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160; </div>
</div><!-- fragment --></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Dec 19 2020 12:38:17 for Tower of Hanoi by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.18
</small></address>
</body>
</html>

51
html/menu.js Normal file
View file

@ -0,0 +1,51 @@
/*
@licstart The following is the entire license notice for the JavaScript code in this file.
The MIT License (MIT)
Copyright (C) 1997-2020 by Dimitri van Heesch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@licend The above is the entire license notice for the JavaScript code in this file
*/
function initMenu(relPath,searchEnabled,serverSide,searchPage,search) {
function makeTree(data,relPath) {
var result='';
if ('children' in data) {
result+='<ul>';
for (var i in data.children) {
result+='<li><a href="'+relPath+data.children[i].url+'">'+
data.children[i].text+'</a>'+
makeTree(data.children[i],relPath)+'</li>';
}
result+='</ul>';
}
return result;
}
$('#main-nav').append(makeTree(menudata,relPath));
$('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu');
if (searchEnabled) {
if (serverSide) {
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><div class="left"><form id="FSearchBox" action="'+relPath+searchPage+'" method="get"><img id="MSearchSelect" src="'+relPath+'search/mag.png" alt=""/><input type="text" id="MSearchField" name="query" value="'+search+'" size="20" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)"></form></div><div class="right"></div></div></li>');
} else {
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><span class="left"><img id="MSearchSelect" src="'+relPath+'search/mag_sel.png" onmouseover="return searchBox.OnSearchSelectShow()" onmouseout="return searchBox.OnSearchSelectHide()" alt=""/><input type="text" id="MSearchField" value="'+search+'" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)" onkeyup="searchBox.OnSearchFieldChange(event)"/></span><span class="right"><a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="'+relPath+'search/close.png" alt=""/></a></span></div></li>');
}
}
$('#main-menu').smartmenus();
}
/* @license-end */

28
html/menudata.js Normal file
View file

@ -0,0 +1,28 @@
/*
@licstart The following is the entire license notice for the JavaScript code in this file.
The MIT License (MIT)
Copyright (C) 1997-2020 by Dimitri van Heesch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@licend The above is the entire license notice for the JavaScript code in this file
*/
var menudata={children:[
{text:"Main Page",url:"index.html"},
{text:"Files",url:"files.html",children:[
{text:"File List",url:"files.html"}]}]}

BIN
html/nav_f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

BIN
html/nav_g.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

BIN
html/nav_h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

BIN
html/open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

36
html/search/all_0.html Normal file
View file

@ -0,0 +1,36 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head><title></title>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<link rel="stylesheet" type="text/css" href="search.css"/>
<script type="text/javascript" src="all_0.js"></script>
<script type="text/javascript" src="search.js"></script>
</head>
<body class="SRPage">
<div id="SRIndex">
<div class="SRStatus" id="Loading">Loading...</div>
<div id="SRResults"></div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
createResults();
/* @license-end */
--></script>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
document.getElementById("Loading").style.display="none";
document.getElementById("NoMatches").style.display="none";
var searchResults = new SearchResults("searchResults");
searchResults.Search();
window.addEventListener("message", function(event) {
if (event.data == "take_focus") {
var elem = searchResults.NavNext(0);
if (elem) elem.focus();
}
});
/* @license-end */
--></script>
</div>
</body>
</html>

4
html/search/all_0.js Normal file
View file

@ -0,0 +1,4 @@
var searchData=
[
['mainpage_2eh_0',['mainpage.h',['../mainpage_8h.html',1,'']]]
];

BIN
html/search/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

36
html/search/files_0.html Normal file
View file

@ -0,0 +1,36 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head><title></title>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<link rel="stylesheet" type="text/css" href="search.css"/>
<script type="text/javascript" src="files_0.js"></script>
<script type="text/javascript" src="search.js"></script>
</head>
<body class="SRPage">
<div id="SRIndex">
<div class="SRStatus" id="Loading">Loading...</div>
<div id="SRResults"></div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
createResults();
/* @license-end */
--></script>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
<script type="text/javascript"><!--
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
document.getElementById("Loading").style.display="none";
document.getElementById("NoMatches").style.display="none";
var searchResults = new SearchResults("searchResults");
searchResults.Search();
window.addEventListener("message", function(event) {
if (event.data == "take_focus") {
var elem = searchResults.NavNext(0);
if (elem) elem.focus();
}
});
/* @license-end */
--></script>
</div>
</body>
</html>

4
html/search/files_0.js Normal file
View file

@ -0,0 +1,4 @@
var searchData=
[
['mainpage_2eh_1',['mainpage.h',['../mainpage_8h.html',1,'']]]
];

BIN
html/search/mag_sel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

View file

@ -0,0 +1,12 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head><title></title>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="search.css"/>
<script type="text/javascript" src="search.js"></script>
</head>
<body class="SRPage">
<div id="SRIndex">
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</body>
</html>

271
html/search/search.css Normal file
View file

@ -0,0 +1,271 @@
/*---------------- Search Box */
#FSearchBox {
float: left;
}
#MSearchBox {
white-space : nowrap;
float: none;
margin-top: 8px;
right: 0px;
width: 170px;
height: 24px;
z-index: 102;
}
#MSearchBox .left
{
display:block;
position:absolute;
left:10px;
width:20px;
height:19px;
background:url('search_l.png') no-repeat;
background-position:right;
}
#MSearchSelect {
display:block;
position:absolute;
width:20px;
height:19px;
}
.left #MSearchSelect {
left:4px;
}
.right #MSearchSelect {
right:5px;
}
#MSearchField {
display:block;
position:absolute;
height:19px;
background:url('search_m.png') repeat-x;
border:none;
width:115px;
margin-left:20px;
padding-left:4px;
color: #909090;
outline: none;
font: 9pt Arial, Verdana, sans-serif;
-webkit-border-radius: 0px;
}
#FSearchBox #MSearchField {
margin-left:15px;
}
#MSearchBox .right {
display:block;
position:absolute;
right:10px;
top:8px;
width:20px;
height:19px;
background:url('search_r.png') no-repeat;
background-position:left;
}
#MSearchClose {
display: none;
position: absolute;
top: 4px;
background : none;
border: none;
margin: 0px 4px 0px 0px;
padding: 0px 0px;
outline: none;
}
.left #MSearchClose {
left: 6px;
}
.right #MSearchClose {
right: 2px;
}
.MSearchBoxActive #MSearchField {
color: #000000;
}
/*---------------- Search filter selection */
#MSearchSelectWindow {
display: none;
position: absolute;
left: 0; top: 0;
border: 1px solid #90A5CE;
background-color: #F9FAFC;
z-index: 10001;
padding-top: 4px;
padding-bottom: 4px;
-moz-border-radius: 4px;
-webkit-border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
-webkit-border-bottom-left-radius: 4px;
-webkit-border-bottom-right-radius: 4px;
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
}
.SelectItem {
font: 8pt Arial, Verdana, sans-serif;
padding-left: 2px;
padding-right: 12px;
border: 0px;
}
span.SelectionMark {
margin-right: 4px;
font-family: monospace;
outline-style: none;
text-decoration: none;
}
a.SelectItem {
display: block;
outline-style: none;
color: #000000;
text-decoration: none;
padding-left: 6px;
padding-right: 12px;
}
a.SelectItem:focus,
a.SelectItem:active {
color: #000000;
outline-style: none;
text-decoration: none;
}
a.SelectItem:hover {
color: #FFFFFF;
background-color: #3D578C;
outline-style: none;
text-decoration: none;
cursor: pointer;
display: block;
}
/*---------------- Search results window */
iframe#MSearchResults {
width: 60ex;
height: 15em;
}
#MSearchResultsWindow {
display: none;
position: absolute;
left: 0; top: 0;
border: 1px solid #000;
background-color: #EEF1F7;
z-index:10000;
}
/* ----------------------------------- */
#SRIndex {
clear:both;
padding-bottom: 15px;
}
.SREntry {
font-size: 10pt;
padding-left: 1ex;
}
.SRPage .SREntry {
font-size: 8pt;
padding: 1px 5px;
}
body.SRPage {
margin: 5px 2px;
}
.SRChildren {
padding-left: 3ex; padding-bottom: .5em
}
.SRPage .SRChildren {
display: none;
}
.SRSymbol {
font-weight: bold;
color: #425E97;
font-family: Arial, Verdana, sans-serif;
text-decoration: none;
outline: none;
}
a.SRScope {
display: block;
color: #425E97;
font-family: Arial, Verdana, sans-serif;
text-decoration: none;
outline: none;
}
a.SRSymbol:focus, a.SRSymbol:active,
a.SRScope:focus, a.SRScope:active {
text-decoration: underline;
}
span.SRScope {
padding-left: 4px;
}
.SRPage .SRStatus {
padding: 2px 5px;
font-size: 8pt;
font-style: italic;
}
.SRResult {
display: none;
}
DIV.searchresults {
margin-left: 10px;
margin-right: 10px;
}
/*---------------- External search page results */
.searchresult {
background-color: #F0F3F8;
}
.pages b {
color: white;
padding: 5px 5px 3px 5px;
background-image: url("../tab_a.png");
background-repeat: repeat-x;
text-shadow: 0 1px 1px #000000;
}
.pages {
line-height: 17px;
margin-left: 4px;
text-decoration: none;
}
.hl {
font-weight: bold;
}
#searchresults {
margin-bottom: 20px;
}
.searchpages {
margin-top: 10px;
}

814
html/search/search.js Normal file
View file

@ -0,0 +1,814 @@
/*
@licstart The following is the entire license notice for the JavaScript code in this file.
The MIT License (MIT)
Copyright (C) 1997-2020 by Dimitri van Heesch
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@licend The above is the entire license notice for the JavaScript code in this file
*/
function convertToId(search)
{
var result = '';
for (i=0;i<search.length;i++)
{
var c = search.charAt(i);
var cn = c.charCodeAt(0);
if (c.match(/[a-z0-9\u0080-\uFFFF]/))
{
result+=c;
}
else if (cn<16)
{
result+="_0"+cn.toString(16);
}
else
{
result+="_"+cn.toString(16);
}
}
return result;
}
function getXPos(item)
{
var x = 0;
if (item.offsetWidth)
{
while (item && item!=document.body)
{
x += item.offsetLeft;
item = item.offsetParent;
}
}
return x;
}
function getYPos(item)
{
var y = 0;
if (item.offsetWidth)
{
while (item && item!=document.body)
{
y += item.offsetTop;
item = item.offsetParent;
}
}
return y;
}
/* A class handling everything associated with the search panel.
Parameters:
name - The name of the global variable that will be
storing this instance. Is needed to be able to set timeouts.
resultPath - path to use for external files
*/
function SearchBox(name, resultsPath, inFrame, label)
{
if (!name || !resultsPath) { alert("Missing parameters to SearchBox."); }
// ---------- Instance variables
this.name = name;
this.resultsPath = resultsPath;
this.keyTimeout = 0;
this.keyTimeoutLength = 500;
this.closeSelectionTimeout = 300;
this.lastSearchValue = "";
this.lastResultsPage = "";
this.hideTimeout = 0;
this.searchIndex = 0;
this.searchActive = false;
this.insideFrame = inFrame;
this.searchLabel = label;
// ----------- DOM Elements
this.DOMSearchField = function()
{ return document.getElementById("MSearchField"); }
this.DOMSearchSelect = function()
{ return document.getElementById("MSearchSelect"); }
this.DOMSearchSelectWindow = function()
{ return document.getElementById("MSearchSelectWindow"); }
this.DOMPopupSearchResults = function()
{ return document.getElementById("MSearchResults"); }
this.DOMPopupSearchResultsWindow = function()
{ return document.getElementById("MSearchResultsWindow"); }
this.DOMSearchClose = function()
{ return document.getElementById("MSearchClose"); }
this.DOMSearchBox = function()
{ return document.getElementById("MSearchBox"); }
// ------------ Event Handlers
// Called when focus is added or removed from the search field.
this.OnSearchFieldFocus = function(isActive)
{
this.Activate(isActive);
}
this.OnSearchSelectShow = function()
{
var searchSelectWindow = this.DOMSearchSelectWindow();
var searchField = this.DOMSearchSelect();
if (this.insideFrame)
{
var left = getXPos(searchField);
var top = getYPos(searchField);
left += searchField.offsetWidth + 6;
top += searchField.offsetHeight;
// show search selection popup
searchSelectWindow.style.display='block';
left -= searchSelectWindow.offsetWidth;
searchSelectWindow.style.left = left + 'px';
searchSelectWindow.style.top = top + 'px';
}
else
{
var left = getXPos(searchField);
var top = getYPos(searchField);
top += searchField.offsetHeight;
// show search selection popup
searchSelectWindow.style.display='block';
searchSelectWindow.style.left = left + 'px';
searchSelectWindow.style.top = top + 'px';
}
// stop selection hide timer
if (this.hideTimeout)
{
clearTimeout(this.hideTimeout);
this.hideTimeout=0;
}
return false; // to avoid "image drag" default event
}
this.OnSearchSelectHide = function()
{
this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()",
this.closeSelectionTimeout);
}
// Called when the content of the search field is changed.
this.OnSearchFieldChange = function(evt)
{
if (this.keyTimeout) // kill running timer
{
clearTimeout(this.keyTimeout);
this.keyTimeout = 0;
}
var e = (evt) ? evt : window.event; // for IE
if (e.keyCode==40 || e.keyCode==13)
{
if (e.shiftKey==1)
{
this.OnSearchSelectShow();
var win=this.DOMSearchSelectWindow();
for (i=0;i<win.childNodes.length;i++)
{
var child = win.childNodes[i]; // get span within a
if (child.className=='SelectItem')
{
child.focus();
return;
}
}
return;
}
else
{
window.frames.MSearchResults.postMessage("take_focus", "*");
}
}
else if (e.keyCode==27) // Escape out of the search field
{
this.DOMSearchField().blur();
this.DOMPopupSearchResultsWindow().style.display = 'none';
this.DOMSearchClose().style.display = 'none';
this.lastSearchValue = '';
this.Activate(false);
return;
}
// strip whitespaces
var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
if (searchValue != this.lastSearchValue) // search value has changed
{
if (searchValue != "") // non-empty search
{
// set timer for search update
this.keyTimeout = setTimeout(this.name + '.Search()',
this.keyTimeoutLength);
}
else // empty search field
{
this.DOMPopupSearchResultsWindow().style.display = 'none';
this.DOMSearchClose().style.display = 'none';
this.lastSearchValue = '';
}
}
}
this.SelectItemCount = function(id)
{
var count=0;
var win=this.DOMSearchSelectWindow();
for (i=0;i<win.childNodes.length;i++)
{
var child = win.childNodes[i]; // get span within a
if (child.className=='SelectItem')
{
count++;
}
}
return count;
}
this.SelectItemSet = function(id)
{
var i,j=0;
var win=this.DOMSearchSelectWindow();
for (i=0;i<win.childNodes.length;i++)
{
var child = win.childNodes[i]; // get span within a
if (child.className=='SelectItem')
{
var node = child.firstChild;
if (j==id)
{
node.innerHTML='&#8226;';
}
else
{
node.innerHTML='&#160;';
}
j++;
}
}
}
// Called when an search filter selection is made.
// set item with index id as the active item
this.OnSelectItem = function(id)
{
this.searchIndex = id;
this.SelectItemSet(id);
var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
if (searchValue!="" && this.searchActive) // something was found -> do a search
{
this.Search();
}
}
this.OnSearchSelectKey = function(evt)
{
var e = (evt) ? evt : window.event; // for IE
if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down
{
this.searchIndex++;
this.OnSelectItem(this.searchIndex);
}
else if (e.keyCode==38 && this.searchIndex>0) // Up
{
this.searchIndex--;
this.OnSelectItem(this.searchIndex);
}
else if (e.keyCode==13 || e.keyCode==27)
{
this.OnSelectItem(this.searchIndex);
this.CloseSelectionWindow();
this.DOMSearchField().focus();
}
return false;
}
// --------- Actions
// Closes the results window.
this.CloseResultsWindow = function()
{
this.DOMPopupSearchResultsWindow().style.display = 'none';
this.DOMSearchClose().style.display = 'none';
this.Activate(false);
}
this.CloseSelectionWindow = function()
{
this.DOMSearchSelectWindow().style.display = 'none';
}
// Performs a search.
this.Search = function()
{
this.keyTimeout = 0;
// strip leading whitespace
var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
var code = searchValue.toLowerCase().charCodeAt(0);
var idxChar = searchValue.substr(0, 1).toLowerCase();
if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair
{
idxChar = searchValue.substr(0, 2);
}
var resultsPage;
var resultsPageWithSearch;
var hasResultsPage;
var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar);
if (idx!=-1)
{
var hexCode=idx.toString(16);
resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
hasResultsPage = true;
}
else // nothing available for this search term
{
resultsPage = this.resultsPath + '/nomatches.html';
resultsPageWithSearch = resultsPage;
hasResultsPage = false;
}
window.frames.MSearchResults.location = resultsPageWithSearch;
var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
if (domPopupSearchResultsWindow.style.display!='block')
{
var domSearchBox = this.DOMSearchBox();
this.DOMSearchClose().style.display = 'inline';
if (this.insideFrame)
{
var domPopupSearchResults = this.DOMPopupSearchResults();
domPopupSearchResultsWindow.style.position = 'relative';
domPopupSearchResultsWindow.style.display = 'block';
var width = document.body.clientWidth - 8; // the -8 is for IE :-(
domPopupSearchResultsWindow.style.width = width + 'px';
domPopupSearchResults.style.width = width + 'px';
}
else
{
var domPopupSearchResults = this.DOMPopupSearchResults();
var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;
var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1;
domPopupSearchResultsWindow.style.display = 'block';
left -= domPopupSearchResults.offsetWidth;
domPopupSearchResultsWindow.style.top = top + 'px';
domPopupSearchResultsWindow.style.left = left + 'px';
}
}
this.lastSearchValue = searchValue;
this.lastResultsPage = resultsPage;
}
// -------- Activation Functions
// Activates or deactivates the search panel, resetting things to
// their default values if necessary.
this.Activate = function(isActive)
{
if (isActive || // open it
this.DOMPopupSearchResultsWindow().style.display == 'block'
)
{
this.DOMSearchBox().className = 'MSearchBoxActive';
var searchField = this.DOMSearchField();
if (searchField.value == this.searchLabel) // clear "Search" term upon entry
{
searchField.value = '';
this.searchActive = true;
}
}
else if (!isActive) // directly remove the panel
{
this.DOMSearchBox().className = 'MSearchBoxInactive';
this.DOMSearchField().value = this.searchLabel;
this.searchActive = false;
this.lastSearchValue = ''
this.lastResultsPage = '';
}
}
}
// -----------------------------------------------------------------------
// The class that handles everything on the search results page.
function SearchResults(name)
{
// The number of matches from the last run of <Search()>.
this.lastMatchCount = 0;
this.lastKey = 0;
this.repeatOn = false;
// Toggles the visibility of the passed element ID.
this.FindChildElement = function(id)
{
var parentElement = document.getElementById(id);
var element = parentElement.firstChild;
while (element && element!=parentElement)
{
if (element.nodeName == 'DIV' && element.className == 'SRChildren')
{
return element;
}
if (element.nodeName == 'DIV' && element.hasChildNodes())
{
element = element.firstChild;
}
else if (element.nextSibling)
{
element = element.nextSibling;
}
else
{
do
{
element = element.parentNode;
}
while (element && element!=parentElement && !element.nextSibling);
if (element && element!=parentElement)
{
element = element.nextSibling;
}
}
}
}
this.Toggle = function(id)
{
var element = this.FindChildElement(id);
if (element)
{
if (element.style.display == 'block')
{
element.style.display = 'none';
}
else
{
element.style.display = 'block';
}
}
}
// Searches for the passed string. If there is no parameter,
// it takes it from the URL query.
//
// Always returns true, since other documents may try to call it
// and that may or may not be possible.
this.Search = function(search)
{
if (!search) // get search word from URL
{
search = window.location.search;
search = search.substring(1); // Remove the leading '?'
search = unescape(search);
}
search = search.replace(/^ +/, ""); // strip leading spaces
search = search.replace(/ +$/, ""); // strip trailing spaces
search = search.toLowerCase();
search = convertToId(search);
var resultRows = document.getElementsByTagName("div");
var matches = 0;
var i = 0;
while (i < resultRows.length)
{
var row = resultRows.item(i);
if (row.className == "SRResult")
{
var rowMatchName = row.id.toLowerCase();
rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_'
if (search.length<=rowMatchName.length &&
rowMatchName.substr(0, search.length)==search)
{
row.style.display = 'block';
matches++;
}
else
{
row.style.display = 'none';
}
}
i++;
}
document.getElementById("Searching").style.display='none';
if (matches == 0) // no results
{
document.getElementById("NoMatches").style.display='block';
}
else // at least one result
{
document.getElementById("NoMatches").style.display='none';
}
this.lastMatchCount = matches;
return true;
}
// return the first item with index index or higher that is visible
this.NavNext = function(index)
{
var focusItem;
while (1)
{
var focusName = 'Item'+index;
focusItem = document.getElementById(focusName);
if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
{
break;
}
else if (!focusItem) // last element
{
break;
}
focusItem=null;
index++;
}
return focusItem;
}
this.NavPrev = function(index)
{
var focusItem;
while (1)
{
var focusName = 'Item'+index;
focusItem = document.getElementById(focusName);
if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
{
break;
}
else if (!focusItem) // last element
{
break;
}
focusItem=null;
index--;
}
return focusItem;
}
this.ProcessKeys = function(e)
{
if (e.type == "keydown")
{
this.repeatOn = false;
this.lastKey = e.keyCode;
}
else if (e.type == "keypress")
{
if (!this.repeatOn)
{
if (this.lastKey) this.repeatOn = true;
return false; // ignore first keypress after keydown
}
}
else if (e.type == "keyup")
{
this.lastKey = 0;
this.repeatOn = false;
}
return this.lastKey!=0;
}
this.Nav = function(evt,itemIndex)
{
var e = (evt) ? evt : window.event; // for IE
if (e.keyCode==13) return true;
if (!this.ProcessKeys(e)) return false;
if (this.lastKey==38) // Up
{
var newIndex = itemIndex-1;
var focusItem = this.NavPrev(newIndex);
if (focusItem)
{
var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
if (child && child.style.display == 'block') // children visible
{
var n=0;
var tmpElem;
while (1) // search for last child
{
tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
if (tmpElem)
{
focusItem = tmpElem;
}
else // found it!
{
break;
}
n++;
}
}
}
if (focusItem)
{
focusItem.focus();
}
else // return focus to search field
{
parent.document.getElementById("MSearchField").focus();
}
}
else if (this.lastKey==40) // Down
{
var newIndex = itemIndex+1;
var focusItem;
var item = document.getElementById('Item'+itemIndex);
var elem = this.FindChildElement(item.parentNode.parentNode.id);
if (elem && elem.style.display == 'block') // children visible
{
focusItem = document.getElementById('Item'+itemIndex+'_c0');
}
if (!focusItem) focusItem = this.NavNext(newIndex);
if (focusItem) focusItem.focus();
}
else if (this.lastKey==39) // Right
{
var item = document.getElementById('Item'+itemIndex);
var elem = this.FindChildElement(item.parentNode.parentNode.id);
if (elem) elem.style.display = 'block';
}
else if (this.lastKey==37) // Left
{
var item = document.getElementById('Item'+itemIndex);
var elem = this.FindChildElement(item.parentNode.parentNode.id);
if (elem) elem.style.display = 'none';
}
else if (this.lastKey==27) // Escape
{
parent.searchBox.CloseResultsWindow();
parent.document.getElementById("MSearchField").focus();
}
else if (this.lastKey==13) // Enter
{
return true;
}
return false;
}
this.NavChild = function(evt,itemIndex,childIndex)
{
var e = (evt) ? evt : window.event; // for IE
if (e.keyCode==13) return true;
if (!this.ProcessKeys(e)) return false;
if (this.lastKey==38) // Up
{
if (childIndex>0)
{
var newIndex = childIndex-1;
document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
}
else // already at first child, jump to parent
{
document.getElementById('Item'+itemIndex).focus();
}
}
else if (this.lastKey==40) // Down
{
var newIndex = childIndex+1;
var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
if (!elem) // last child, jump to parent next parent
{
elem = this.NavNext(itemIndex+1);
}
if (elem)
{
elem.focus();
}
}
else if (this.lastKey==27) // Escape
{
parent.searchBox.CloseResultsWindow();
parent.document.getElementById("MSearchField").focus();
}
else if (this.lastKey==13) // Enter
{
return true;
}
return false;
}
}
function setKeyActions(elem,action)
{
elem.setAttribute('onkeydown',action);
elem.setAttribute('onkeypress',action);
elem.setAttribute('onkeyup',action);
}
function setClassAttr(elem,attr)
{
elem.setAttribute('class',attr);
elem.setAttribute('className',attr);
}
function createResults()
{
var results = document.getElementById("SRResults");
for (var e=0; e<searchData.length; e++)
{
var id = searchData[e][0];
var srResult = document.createElement('div');
srResult.setAttribute('id','SR_'+id);
setClassAttr(srResult,'SRResult');
var srEntry = document.createElement('div');
setClassAttr(srEntry,'SREntry');
var srLink = document.createElement('a');
srLink.setAttribute('id','Item'+e);
setKeyActions(srLink,'return searchResults.Nav(event,'+e+')');
setClassAttr(srLink,'SRSymbol');
srLink.innerHTML = searchData[e][1][0];
srEntry.appendChild(srLink);
if (searchData[e][1].length==2) // single result
{
srLink.setAttribute('href',searchData[e][1][1][0]);
if (searchData[e][1][1][1])
{
srLink.setAttribute('target','_parent');
}
var srScope = document.createElement('span');
setClassAttr(srScope,'SRScope');
srScope.innerHTML = searchData[e][1][1][2];
srEntry.appendChild(srScope);
}
else // multiple results
{
srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")');
var srChildren = document.createElement('div');
setClassAttr(srChildren,'SRChildren');
for (var c=0; c<searchData[e][1].length-1; c++)
{
var srChild = document.createElement('a');
srChild.setAttribute('id','Item'+e+'_c'+c);
setKeyActions(srChild,'return searchResults.NavChild(event,'+e+','+c+')');
setClassAttr(srChild,'SRScope');
srChild.setAttribute('href',searchData[e][1][c+1][0]);
if (searchData[e][1][c+1][1])
{
srChild.setAttribute('target','_parent');
}
srChild.innerHTML = searchData[e][1][c+1][2];
srChildren.appendChild(srChild);
}
srEntry.appendChild(srChildren);
}
srResult.appendChild(srEntry);
results.appendChild(srResult);
}
}
function init_search()
{
var results = document.getElementById("MSearchSelectWindow");
for (var key in indexSectionLabels)
{
var link = document.createElement('a');
link.setAttribute('class','SelectItem');
link.setAttribute('onclick','searchBox.OnSelectItem('+key+')');
link.href='javascript:void(0)';
link.innerHTML='<span class="SelectionMark">&#160;</span>'+indexSectionLabels[key];
results.appendChild(link);
}
searchBox.OnSelectItem(0);
}
/* @license-end */

BIN
html/search/search_l.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

BIN
html/search/search_m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

BIN
html/search/search_r.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

18
html/search/searchdata.js Normal file
View file

@ -0,0 +1,18 @@
var indexSectionsWithContent =
{
0: "m",
1: "m"
};
var indexSectionNames =
{
0: "all",
1: "files"
};
var indexSectionLabels =
{
0: "All",
1: "Files"
};

BIN
html/splitbar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

BIN
html/sync_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

BIN
html/sync_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

BIN
html/tab_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

BIN
html/tab_b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

BIN
html/tab_h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

BIN
html/tab_s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

1
html/tabs.css Normal file

File diff suppressed because one or more lines are too long

75
mainpage.h Normal file
View file

@ -0,0 +1,75 @@
/**
* @mainpage
* @section intro Introduction
* The Tower of Hanoi is a mathematical game or puzzle.
* The board consists of three rods and a number of disks of different sizes, which can slide onto any rod.
* At the beginning, all disks are placed on the left rod in ascending order of their size, the smallest disk at the top.
*
* The objective of the puzzle is to move the entire stack of disks from the left to the right rod, obeying the following rules:
* + Only one disk can be moved at a time.
* + Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty rod.
* + No larger disk may be placed on top of a smaller disk.
*
* The minimal number of moves required to solve a Tower of Hanoi puzzle is 2n 1, where n is the number of disks.
* (source: Wikipedia)
*
* @section objective Assignment Objective
* In this assignment the recursiver solver for the Tower of Hanoi puzzle shall be implemented together with
* the required Abstract Data Types.
* Abstract Data Types for single disks (`toh_disc.*`) and the 'Tower of Hanoi' board (`toh_board.*`) are required.
* The 'Tower of Hanoi' solver (`toh_solver.*`) is not an ADT but a function library.
*
* **Configuration**
* A configurable number of disk instances shall be available, this number is configered in `config.c` `MAX_DISKS`.
* There shall be exactly one instance of a board available.
*
* Other configuration options affects the visualization only, but has no effect on the game.
*
* **Setup and Execution**
* The solver shall initialize the board with a given number of disks. This number must be less the configured
* maximum number of disks. Whereas the `MAX_DISKS` defines the number of avialable disk instances,
* the number of disks applied to the initialization function of the solver defines the number of disks for the
* next game.
*
* After the board is initialized via solver, the solver shall solve that game using the following recursive algorithm:
* -# move (n-1) disks from source rod to intermediate rod using target rod as buffer
* -# move remaining (1) disk from source rod to target rod
* -# move (n-1) disks from intermediate rod to target rod using source rod as buffer
* until all disks are moved from the left to the right rod.
*
* **Visualization**
* The solver uses the ready-to-use Tower of Hanoi visualizer (`toh_visualizer.h`) to present the ANSI graphic of the game.
* A printout using function `toh_visualize(...)` is required
* + after the board is initialized
* + after the move of a single disk
* + after the game is completely solved, a message telling about success or error can be applied to this viusalization step.
*
* @section assignment Assignment
* -# Complete forward declarations, types, and function for ADTs in `toh_disk.h` and `toh_board.h` as well as in `toh_solver.h`.
* - Types in template files may be marked as `<type>` within header and source files or may be omitted completely. Replace `<type>`
* with the correct type and complete missing types.
* - Parameter lists of function in a template files may be missing or incomplete
* -# Make the program and tests compile: Implement all functions declared in the headers EMTPY (return nothing, 0, false as required)
* - All unit tests shall run but FAIL after this step
* - **--COMMIT--**
* -# Implement the empty functions one by one to make the unit tests pass one by one.
* - Proposed order: disk, board, solver.
* - The purpose of a function is specified as API documentation within the header files.
* - Obey comments in source files.
* - **--COMMIT-- after each implemented function.**
* -# Implement the missing parts to run the game in `toh_main_driver.c` methods
* -# Run the game and enjoy
*
* @section notes Notes
* -# This program requires compile option `-std=gnu11` becuase timer functions, please don't change.
* gnu11 extends c11 and is expected not to cause an troubles or differences in implementation
* -# Visualization is implemented for Linux shell, it will not work on Windows.
* -# Sometimes changes are not properly detected by incremental builds. If something very strange
* happens during compilation, try to run `make clean` followed by `make` to start a clean build.
* This approach is also recommended after everthing is done, because some compiler warning appears
* only in clean builds.
*/

85
makefile Normal file
View file

@ -0,0 +1,85 @@
CC = gcc
CCLINK = g++
LIBS =
CCOPTIONS = -Wall -pedantic -std=gnu11 -g
LDOPTIONS =
TEST = test_tower_of_hanoi
PROGRAM = tower_of_hanoi
COMMON_HDRS = config.h general.h
LIBRARY_FILES = toh_visualizer shortcut
ASSIGNMENT_FILES = toh_board toh_disk toh_solver
MAIN_DRIVER = toh_main_driver
TEST_DRIVER = toh_test_driver
LIBRARY_H = $(addsuffix .h, $(LIBRARY_FILES))
ASSIGNMENT_H = $(addsuffix .h, $(ASSIGNMENT_FILES))
ASSIGNMENT_C = $(addsuffix .c, $(ASSIGNMENT_FILES)) $(MAIN_DRIVER).c
HDRS = $(ASSIGNEMT_H) $(SHARED_HDRS) $(COMMON_HDRS) $(LIBRARY_H)
TESTOBJECT = $(TEST_DRIVER).o
MAINOBJECT = $(MAIN_DRIVER).o
LIBRARY_OBJS = $(addsuffix .o, $(LIBRARY_FILES))
TEST_OBJS = $(addprefix test_, $(addsuffix .o, $(ASSIGNMENT_FILES)))
MAIN_OBJ = $(addsuffix .o, $(ASSIGNMENT_FILES))
OBJS = $(LIBRARY_OBJS) $(MAIN_OBJ) $(TEST_OBJS)
DOXY = doxygen
all: $(PROGRAM)
./$(PROGRAM)
$(TEST): $(OBJS) $(TESTOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(TESTOBJECT)
$(PROGRAM): $(OBJS) $(MAINOBJECT)
$(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) $(MAINOBJECT)
.PHONY: clean cleanall doxy test setsample setassignment definesample defineassignment assignmentfolder
clean:
rm -f $(PROGRAM) $(TEST) $(TESTOBJECT) $(MAINOBJECT) $(OBJS)
cleanall:
rm -f $(PROGRAM) $(TEST) $(TESTOBJECT) $(MAINOBJECT) $(OBJS) index.html
rm -R html
doxy:
$(DOXY)
rm -f index.html
ln -s html/index.html index.html
test: $(TEST)
./$(TEST)
%.o: %.c
$(CC) $(CCOPTIONS) -c $<
#sets project as sample solution
setsample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).sample $(name);)
#sets project as assignment
setassignment:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name).assignment $(name);)
# defines current state of project as sample solution
definesample:
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).sample;)
# defines current sate of project as assignment
defineassignment :
$(foreach name, $(ASSIGNMENT_H) $(ASSIGNMENT_C), cp $(name) $(name).assignment;)
# creates a folder which can serve as a publishable assignment
assignmentfolder:
make setassignment
make doxy
rm -rf ../assignment
mkdir ../assignment
cp -R * ../assignment
cp .gitignore ../assignment
rm ../assignment/*.sample
rm ../assignment/*.assignment
make cleanall

151
shortcut.c Normal file
View file

@ -0,0 +1,151 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut.c
* Author: P. Bauer
* Date: November 08, 2010
* ----------------------------------------------------------
* Description:
* Test driver.
* ----------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "shortcut.h"
#define MAX_TEST_FUNCTIONS 256
static char assert_msg_buffer[1024];
static int tc_count = 0;
static int tc_fail_count = 0;
static struct TestCase test_cases[MAX_TEST_FUNCTIONS];
const char* version()
{
return "ShortCut v. 1.3.0";
}
char* format_msg(char* format, ...) {
va_list args;
va_start (args, format);
vsprintf(assert_msg_buffer, format, args);
return assert_msg_buffer;
}
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
if (!bool_expr) {
if (tc->success) {
tc->success = false;
tc_fail_count++;
}
printf("\n\tFailure (file: %s, line %d): %s: %s", file, line, tc->name, msg);
}
}
void assert_false(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line)
{
assert_true(!bool_expr, tc, msg, file, line);
}
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line);
void assert_equals_str(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
if (expected == actual) {
return;
}
if (expected == 0 || actual == 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
if (strcmp(actual, expected) != 0) {
assert_string_failure(expected, actual, tc, msg, file, line);
return;
}
}
#define MAX_MSG_LEN 128
static void assert_string_failure(const char *expected, char *actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected \"%s\", actual \"%s\". %s", expected, actual, msg);
assert_true(false, tc, new_msg, file, line);
}
void assert_equals(int expected, int actual, struct TestCase *tc,
const char *msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %d, actual %d. %s", expected, actual, msg);
assert_true(expected == actual, tc, new_msg, file, line);
}
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line)
{
char new_msg[MAX_MSG_LEN];
sprintf(new_msg, "Expected %f, actual %f. %s", expected, actual, msg);
double min_val = expected - tolerance;
double max_val = expected + tolerance;
assert_true(min_val <= actual && actual <= max_val, tc, new_msg, file, line);
}
int get_test_count()
{
return tc_count;
}
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_name)
{
if (tc_count == MAX_TEST_FUNCTIONS) {
return false;
}
else {
test_cases[tc_count].success = true;
test_cases[tc_count].name = test_name;
test_cases[tc_count].test_function = test_function;
tc_count++;
return true;
}
}
void run_tests()
{
int i;
printf("\n%s: Running tests\n", version());
for (i = 0; i < get_test_count(); i++) {
printf("Running test %s ...", test_cases[i].name);
test_cases[i].test_function(&test_cases[i]);
if (test_cases[i].success) {
printf("\033[32m OK\033[m");
}
else {
printf("\033[31m ... FAIL\033[m");
}
printf("\n");
}
printf("\nTotal tests run: %d\n", tc_count);
if (tc_fail_count > 0) {
printf("\033[31mTests failed: %d\033[m\n", tc_fail_count);
}
else {
printf("\033[32mAll tests run successfully\033[m\n");
}
}

110
shortcut.h Normal file
View file

@ -0,0 +1,110 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Title: shortcut
* Author: P. Bauer
* Date: November 03, 2010
* ----------------------------------------------------------
* Description:
* A simple unit testing frame work for C.
* ----------------------------------------------------------
*/
#ifndef ___SHORTCUT_H
#define ___SHORTCUT_H
#include <stdbool.h>
/** TestCase is the struct to define one test case. A test case can
*** be added to a test. If the test is run all added test cases are
*** run and the result of the run of each test case is checked automatically.
*/
struct TestCase {
const char *name;
/** true if the test passed, false otherwise. */
bool success;
/** The test function which is executed by the test framework. */
void (*test_function)(struct TestCase *tc);
};
/**
*** @return Version of shortcut as string
***/
const char* version();
/**
*** @return The fromated string as generated using sprintf(format, ...)
***/
char* format_msg(char* format, ...);
/** assert_true checks, whether a boolean expression passed is true or false.
*** in case it is false the test case stating the assertion is marked
*** as failed and msg is printed.
*** @param bool_expr Expression which is evaluated.
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*/
void assert_true(bool bool_expr, struct TestCase *tc, const char *msg,
const char* file, int line);
/** assert_false does the same as assert() but the boolean expression
*** has to evaluate to false. If it evaluates to true the assertion
*** fails.
*** @see assert
*/
void assert_false(bool bool_expr, struct TestCase* tc, const char* msg,
const char* file, int line);
/** assert_equals checks whether two values are equal. Currently the following
*** data formats are supported:
*** - strings
*** - integer
*** @param expected The expected string value
*** @param actual The actual string value
*** @param tc Pointer to the test case which states this assertion.
*** @param msg Message to be printed if assertion evaluates to false.
*** @param file File in which the assert is given.
*** @param line Line in which the assert is given.
*** @see assert
*/
void assert_equals(int expected, int actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_str(const char* expected, char* actual, struct TestCase* tc,
const char* msg, const char* file, int line);
void assert_equals_f(double expected, double actual, double tolerance, struct TestCase* tc,
const char* msg, const char* file, int line);
/** @return The total number of test cases added to the test.
*/
int get_test_count();
/** add_test creates a new test case and adds the a test function to
*** this test case.
*** @param test_function Pointer to the test function to be added
*** to the newly created test case.
*** @param test_case_name Name which should be assigned to the newly
*** created test case.
*/
bool add_test(void (*test_function)(struct TestCase *tc), const char *test_case_name);
void run_tests();
#define TEST(testname) void testname(struct TestCase *tc)
#define MSG(format, ...) format_msg(format, ##__VA_ARGS__)
#define ASSERT_TRUE(condition, msg) assert_true(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_FALSE(condition, msg) assert_false(condition, tc, msg, __FILE__, __LINE__)
#define ASSERT_EQUALS(expected, actual) assert_equals(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_STR(expected, actual) assert_equals_str(expected, actual, tc, "", __FILE__, __LINE__)
#define ASSERT_EQUALS_TOLERANCE(expected, actual, tolerance) assert_equals_f(expected, actual, tolerance, tc, "", __FILE__, __LINE__)
#define ADD_TEST(testfunction) add_test(testfunction, #testfunction)
#endif

201
test_toh_board.c Normal file
View file

@ -0,0 +1,201 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Implementation of UTs for Tower of Hanoi Borad
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Board.
* ----------------------------------------------------------
*/
#include "test_toh_disk.h"
#include <stdio.h>
#include <string.h>
#include "shortcut.h"
#include "config.h"
#include "toh_board.h"
#include "toh_disk.h"
#define ASSERT_VALID_DISK_BY_SIZE(disk, exp_size, rod_label) _assert_valid_disk_by_size(tc, disk, exp_size, rod_label)
void _assert_valid_disk_by_size(struct TestCase* tc, Disk disk, unsigned short exp_size, const char* rod_label) {
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk from %s rod", rod_label));
unsigned short act_size = td_get_size(disk);
ASSERT_TRUE(act_size == exp_size, MSG("Incorrect disk size, expected [%u] but was [%u]", exp_size, act_size));
}
TEST(test_tb_get_board__shall_provide_valid_board) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
}
TEST(test_tb_get_board__shall_provide_the_same_board_each_time) {
TohBoard ref_board = tb_get_board();
for (int i = 0; i <= MAX_DISKS; i++) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
ASSERT_TRUE(board == ref_board, MSG("Expected same board"));
}
}
TEST(test_tb_clear_board__shall_ignore_invalid_board) {
tb_clear_board(0);
}
TEST(test_tb_is_valid__shall_be_invalid_for_0_board) {
ASSERT_FALSE(tb_is_valid(0), MSG("Expected board to be invalid"));
}
TEST(test_tb_push_disk__shall_push_valid_disks_on_each_rod) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
Disk disk = 0;
for (int size = MAX_DISKS; size > 0; size--) {
disk = td_get_disk(size);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", size));
ASSERT_TRUE(tb_push_disk(board, LEFT, disk), MSG("Expected valid disk push on left rod of disk with size [%u]", size));
ASSERT_TRUE(tb_push_disk(board, MIDDLE, disk), MSG("Expected valid disk push on middle rod of disk with size [%u]", size));
ASSERT_TRUE(tb_push_disk(board, RIGHT, disk), MSG("Expected valid disk push on right rod of disk with size [%u]", size));
}
}
TEST(test_tb_push_disk__shall_not_push_on_invalid_board) {
Disk disk = td_get_disk(1);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk"));
ASSERT_FALSE(tb_push_disk(0, LEFT, disk), MSG("Expected invalid disk push on left rod of invalid board"));
ASSERT_FALSE(tb_push_disk(0, MIDDLE, disk), MSG("Expected invalid disk push on middle rod of invalid board"));
ASSERT_FALSE(tb_push_disk(0, RIGHT, disk), MSG("Expected invalid disk push on right rod of invalid board"));
}
TEST(test_tb_push_disk__shall_not_push_invalid_disks_on_each_rod) {
TohBoard board = tb_get_board();
tb_clear_board(board);
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
ASSERT_FALSE(tb_push_disk(board, LEFT, 0), MSG("Expected invalid disk push on left rod for invalid disk"));
ASSERT_FALSE(tb_push_disk(board, MIDDLE, 0), MSG("Expected invalid disk push on middle rod for invalid disk"));
ASSERT_FALSE(tb_push_disk(board, RIGHT, 0), MSG("Expected invalid disk push on right rod for invalid disk"));
}
TEST(test_tb_push_disk__shall_not_push_wrong_disks_on_any_rod) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
Disk disk = td_get_disk(1);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk"));
tb_push_disk(board, LEFT, disk);
tb_push_disk(board, MIDDLE, disk);
tb_push_disk(board, RIGHT, disk);
for (int size = 2; size <= MAX_DISKS; size++) {
disk = td_get_disk(size);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", size));
ASSERT_FALSE(tb_push_disk(board, LEFT, disk), MSG("Expected invalid disk push on left rod of disk with size [%u]", size));
ASSERT_FALSE(tb_push_disk(board, MIDDLE, disk), MSG("Expected invalid disk push on middle rod of disk with size [%u]", size));
ASSERT_FALSE(tb_push_disk(board, RIGHT, disk), MSG("Expected invalid disk push on right rod of disk with size [%u]", size));
}
}
TEST(test_tb_pop_disk__shall_pop_valid_disks_from_each_rod) {
unsigned short larger = 2;
unsigned short smaller = 1;
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
Disk disk = td_get_disk(larger);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", larger));
tb_push_disk(board, LEFT, disk);
tb_push_disk(board, MIDDLE, disk);
tb_push_disk(board, RIGHT, disk);
disk = td_get_disk(1);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", smaller));
tb_push_disk(board, RIGHT, disk);
ASSERT_VALID_DISK_BY_SIZE(tb_pop_disk(board, LEFT), larger, "left");
ASSERT_TRUE(tb_pop_disk(board, LEFT) == 0, MSG("Did not disk from empty left rod"));
ASSERT_VALID_DISK_BY_SIZE(tb_pop_disk(board, MIDDLE), larger, "middle");
ASSERT_TRUE(tb_pop_disk(board, MIDDLE) == 0, MSG("Did not disk from empty middle rod"));
ASSERT_VALID_DISK_BY_SIZE(tb_pop_disk(board, RIGHT), smaller, "right");
ASSERT_VALID_DISK_BY_SIZE(tb_pop_disk(board, RIGHT), larger, "right");
ASSERT_TRUE(tb_pop_disk(board, RIGHT) == 0, MSG("Did not disk from empty right rod"));
}
TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_each_empty_rod) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
ASSERT_TRUE(tb_pop_disk(board, LEFT) == 0, MSG("Did not disk from empty left rod"));
ASSERT_TRUE(tb_pop_disk(board, MIDDLE) == 0, MSG("Did not disk from empty middle rod"));
ASSERT_TRUE(tb_pop_disk(board, RIGHT) == 0, MSG("Did not disk from empty right rod"));
}
TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_invalid_board) {
ASSERT_TRUE(tb_pop_disk(0, LEFT) == 0, MSG("Did not disk from empty board"));
ASSERT_TRUE(tb_pop_disk(0, MIDDLE) == 0, MSG("Did not disk from empty board"));
ASSERT_TRUE(tb_pop_disk(0, RIGHT) == 0, MSG("Did not disk from empty board"));
}
TEST(test_tb_get_disk__shall_provide_valid_disks_from_each_rod) {
unsigned short larger = 3;
unsigned short large = 2;
unsigned short small = 1;
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
Disk disk = td_get_disk(larger);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", larger));
tb_push_disk(board, RIGHT, disk);
disk = td_get_disk(large);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", larger));
tb_push_disk(board, MIDDLE, disk);
tb_push_disk(board, RIGHT, disk);
disk = td_get_disk(small);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk [%u]", larger));
tb_push_disk(board, LEFT, disk);
tb_push_disk(board, MIDDLE, disk);
tb_push_disk(board, RIGHT, disk);
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, LEFT, 0), small, "left");
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, MIDDLE, 0), large, "middle");
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, MIDDLE, 1), small, "middle");
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, RIGHT, 0), larger, "left");
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, RIGHT, 1), large, "left");
ASSERT_VALID_DISK_BY_SIZE(tb_get_disk(board, RIGHT, 2), small, "right");
}
TEST(test_tb_get_disk__shall_provide_0_for_invalid_board) {
ASSERT_TRUE(tb_get_disk(0, LEFT, 0) == 0, MSG("Expected 0 disk for invalid board"));
ASSERT_TRUE(tb_get_disk(0, MIDDLE, 0) == 0, MSG("Expected 0 disk for invalid board"));
ASSERT_TRUE(tb_get_disk(0, RIGHT, 0) == 0, MSG("Expected 0 disk for invalid board"));
}
TEST(test_tb_get_disk__shall_provide_0_for_empty_rod_positions) {
TohBoard board = tb_get_board();
ASSERT_TRUE(tb_is_valid(board), MSG("Expected valid board"));
tb_clear_board(board);
for (int i = 0; i < MAX_DISKS + 10; i++) {
ASSERT_TRUE(tb_get_disk(board, LEFT, i) == 0, MSG("Expected 0 disk for empty rod"));
ASSERT_TRUE(tb_get_disk(board, MIDDLE, i) == 0, MSG("Expected 0 disk for empty rod"));
ASSERT_TRUE(tb_get_disk(board, RIGHT, i) == 0, MSG("Expected 0 disk for empty rod"));
}
}

35
test_toh_board.h Normal file
View file

@ -0,0 +1,35 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Unit Tests for Tower of Hanoi Board
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Board.
* ----------------------------------------------------------
*/
#ifndef ___TEST_TOH_BOARD_H
#define ___TEST_TOH_BOARD_H
#include "shortcut.h"
TEST(test_tb_get_board__shall_provide_valid_board);
TEST(test_tb_get_board__shall_provide_the_same_board_each_time);
TEST(test_tb_is_valid__shall_be_invalid_for_0_board);
TEST(test_tb_push_disk__shall_push_valid_disks_on_each_rod);
TEST(test_tb_push_disk__shall_not_push_on_invalid_board);
TEST(test_tb_push_disk__shall_not_push_invalid_disks_on_each_rod);
TEST(test_tb_push_disk__shall_not_push_wrong_disks_on_any_rod);
TEST(test_tb_pop_disk__shall_pop_valid_disks_from_each_rod);
TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_each_empty_rod);
TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_invalid_board);
TEST(test_tb_get_disk__shall_provide_valid_disks_from_each_rod);
TEST(test_tb_get_disk__shall_provide_0_for_invalid_board);
TEST(test_tb_get_disk__shall_provide_0_for_empty_rod_positions);
#endif

110
test_toh_disk.c Normal file
View file

@ -0,0 +1,110 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Implementation of UTs for Tower of Hanoi Disk
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Disk.
* ----------------------------------------------------------
*/
#include "test_toh_disk.h"
#include <stdio.h>
#include <string.h>
#include "shortcut.h"
#include "config.h"
#include "toh_disk.h"
TEST(test_td_get_disk__shall_provide_valid_disk_for_each_size) {
Disk disk = 0;
for (int size = 1; size <= MAX_DISKS; size++) {
disk = td_get_disk(size);
ASSERT_TRUE(disk != 0, MSG("Valid disk expected for size [%u]", size));
}
}
TEST(test_td_get_disk__shall_provide_0_for_invalid_size) {
int sizes[] = {0, MAX_DISKS + 1};
Disk disk = 0;
for (int i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) {
disk = td_get_disk(sizes[i]);
ASSERT_TRUE(disk == 0, MSG("0 disk expected for size [%u]", 0));
}
}
TEST(test_td_is_valid__shall_be_valid_for_valid_disks) {
Disk disk = 0;
for (int size = 1; size <= MAX_DISKS; size++) {
disk = td_get_disk(size);
ASSERT_TRUE(td_is_valid(disk), MSG("Valid expected for disk of size [%u]", size));
}
}
TEST(test_td_is_valid__shall_be_invalid_for_0_disks) {
Disk disk = 0;
ASSERT_FALSE(td_is_valid(disk), MSG("Invalid expected for 0 disk"));
}
TEST(test_td_is_valid__shall_be_invalid_for_disks_with_invalid_sizes) {
/* size cannot be set via public API */
}
TEST(test_td_get_size__shall_provide_size_of_valid_disk) {
Disk disk = 0;
for (int size = 1; size <= MAX_DISKS; size++) {
disk = td_get_disk(size);
ASSERT_TRUE(td_is_valid(disk), MSG("Valid expected for disk of size [%u]", size));
unsigned short act_size = td_get_size(disk);
ASSERT_TRUE(act_size == size, MSG("Incorrect size, expected [%u] but was [%u]", size, act_size));
}
}
TEST(test_td_get_size__shall_provide_0_for_invalid_disk) {
unsigned short act_size = td_get_size(0);
ASSERT_TRUE(act_size == 0, MSG("Incorrect size for 0 disk, expected [%u] but was [%u]", 0, act_size));
}
TEST(test_td_is_smaller__shall_be_true_for_smaller_disks) {
Disk disk = td_get_disk(MAX_DISKS);
Disk candidate = 0;
for (int size = MAX_DISKS - 1; size > 0; size--) {
candidate = td_get_disk(size);
ASSERT_TRUE(td_is_smaller(disk, candidate), MSG("Disk of size [%u] is expected being smaller than disk of size [%u]", td_get_size(disk), td_get_size(candidate)));
disk = candidate;
}
}
TEST(test_td_is_smaller__shall_be_false_for_larger_disks) {
Disk disk = td_get_disk(1);
Disk candidate = 0;
for (int size = 2; size <= MAX_DISKS; size++) {
candidate = disk;
ASSERT_FALSE(td_is_smaller(disk, candidate), MSG("Disk of size [%u] is NOT expected being smaller than disk of size [%u]", td_get_size(disk), td_get_size(candidate)));
candidate = td_get_disk(size);
ASSERT_FALSE(td_is_smaller(disk, candidate), MSG("Disk of size [%u] is NOT expected being smaller than disk of size [%u]", td_get_size(disk), td_get_size(candidate)));
disk = candidate;
}
}
TEST(test_td_is_smaller__shall_be_false_for_invalid_disk) {
Disk disk = td_get_disk(1);
ASSERT_TRUE(td_is_valid(disk), MSG("Valid disk expected"));
ASSERT_FALSE(td_is_smaller(0, disk), MSG("False expected for invalid target disk"));
}
TEST(test_td_is_smaller__shall_be_false_for_invalid_candidates) {
Disk disk = td_get_disk(1);
ASSERT_TRUE(td_is_valid(disk), MSG("Valid disk expected"));
ASSERT_FALSE(td_is_smaller(disk, 0), MSG("False expected for invalid candidate disk"));
}
TEST(test_td_is_smaller__shall_be_false_for_invalid_attributes) {
ASSERT_FALSE(td_is_smaller(0, 0), MSG("False expected for invalid disks"));
}

34
test_toh_disk.h Normal file
View file

@ -0,0 +1,34 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Unit Tests for Boolean Term
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Disk.
* ----------------------------------------------------------
*/
#ifndef ___TEST_TOH_DISK_H
#define ___TEST_TOH_DISK_H
#include "shortcut.h"
TEST(test_td_get_disk__shall_provide_valid_disk_for_each_size);
TEST(test_td_get_disk__shall_provide_0_for_invalid_size);
TEST(test_td_is_valid__shall_be_valid_for_valid_disks);
TEST(test_td_is_valid__shall_be_invalid_for_0_disks);
TEST(test_td_is_valid__shall_be_invalid_for_disks_with_invalid_sizes);
TEST(test_td_get_size__shall_provide_size_of_valid_disk);
TEST(test_td_get_size__shall_provide_0_for_invalid_disk);
TEST(test_td_is_smaller__shall_be_true_for_smaller_disks);
TEST(test_td_is_smaller__shall_be_false_for_larger_disks);
TEST(test_td_is_smaller__shall_be_false_for_invalid_disk);
TEST(test_td_is_smaller__shall_be_false_for_invalid_candidates);
TEST(test_td_is_smaller__shall_be_false_for_invalid_attributes);
#endif

102
test_toh_solver.c Normal file
View file

@ -0,0 +1,102 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Implementation of UTs for Tower of Hanoi Disk
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Disk.
* ----------------------------------------------------------
*/
#include "test_toh_solver.h"
#include <stdio.h>
#include <string.h>
#include "shortcut.h"
#include "config.h"
#include "toh_solver.h"
#include "toh_disk.h"
#include "toh_visualizer.h"
#define ASSERT_DISK_PILE_ON_ROD(board, rod_name, count, rod_label) _assert_disk_pile_on_rod(tc, board, rod_name, count, rod_label)
void _assert_disk_pile_on_rod(struct TestCase* tc, TohBoard board, RodName rod_name, unsigned short count, const char* rod_label) {
Disk disk = 0;
int idx = 0;
/* check for expected disks */
for (; idx < count; idx++) {
disk = tb_get_disk(board, rod_name, idx);
ASSERT_TRUE(td_is_valid(disk), MSG("Expected valid disk on position [%u] on %s rod", idx, rod_label));
unsigned short act_size = td_get_size(disk);
unsigned short exp_size = count - idx;
ASSERT_TRUE(act_size == exp_size, MSG("Incorrect disk size on position [%u] on %s rod, expected [%u] but was [%u]", idx, rod_label, exp_size, act_size));
}
/* check empty positions */
for (; idx < MAX_DISKS; idx++) {
disk = tb_get_disk(board, rod_name, idx);
ASSERT_FALSE(td_is_valid(disk), MSG("Expected invalid disk on position [%u] on %s rod", idx, rod_label));
}
}
#define TEST_SOLVE(disk_count) _test_solve(tc, disk_count)
void _test_solve(struct TestCase* tc, unsigned short disk_count) {
ts_init(disk_count);
toh_disable_visualizer(true);
TohBoard board = tb_get_board();
ASSERT_DISK_PILE_ON_ROD(board, LEFT, disk_count, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, 0, "right");
ts_solve();
ASSERT_DISK_PILE_ON_ROD(board, LEFT, 0, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, disk_count, "right");
}
/* ===================================================================== */
TEST(test_ts_init__with_one_disk) {
ts_init(1);
TohBoard board = tb_get_board();
ASSERT_DISK_PILE_ON_ROD(board, LEFT, 1, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, 0, "right");
}
TEST(test_ts_init__with_many_disks) {
ts_init(MAX_DISKS);
TohBoard board = tb_get_board();
ASSERT_DISK_PILE_ON_ROD(board, LEFT, MAX_DISKS, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, 0, "right");
}
TEST(test_ts_init__subsequent_inits) {
ts_init(MAX_DISKS);
TohBoard board = tb_get_board();
ASSERT_DISK_PILE_ON_ROD(board, LEFT, MAX_DISKS, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, 0, "right");
ts_init(2);
ASSERT_DISK_PILE_ON_ROD(board, LEFT, 2, "left");
ASSERT_DISK_PILE_ON_ROD(board, MIDDLE, 0, "middle");
ASSERT_DISK_PILE_ON_ROD(board, RIGHT, 0, "right");
}
TEST(test_ts_solve__one) {
TEST_SOLVE(3);
}
TEST(test_ts_solve__two) {
TEST_SOLVE(5);
}
TEST(test_ts_solve__three) {
TEST_SOLVE(11);
}

26
test_toh_solver.h Normal file
View file

@ -0,0 +1,26 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Unit Tests for Boolean Term
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Test functions for ADT ToH Disk.
* ----------------------------------------------------------
*/
#ifndef ___TEST_TOH_SOLVER_H
#define ___TEST_TOH_SOLVER_H
#include "shortcut.h"
TEST(test_ts_init__with_one_disk);
TEST(test_ts_init__with_many_disks);
TEST(test_ts_init__subsequent_inits);
TEST(test_ts_solve__one);
TEST(test_ts_solve__two);
TEST(test_ts_solve__three);
#endif

20
toh_board.c Normal file
View file

@ -0,0 +1,20 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Disk ADT implementation
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* Implementation of toh_board.h.
* ----------------------------------------------------------
*/
#include "toh_board.h"
#include "config.h"
#include "toh_disk.h"
/** Abstraction of a rod type */
/* Hint: Define a type 'Rod' as a pointer to Disk
for usage in exchange with Disk array */

78
toh_board.h Normal file
View file

@ -0,0 +1,78 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Board / Game
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* The declaration of an Abstract Data Type representing
* a game board for Tower of Hanoi.
*
* @see toh_solver.h for details regarding *Tower of Hanoi*.
* ----------------------------------------------------------
*/
/* == !Include guard and required includes need to be added */
/** The enumeration of available rods: LEFT, MIDDLE, RIGHT. */
/** Declares type for the 'Tower of Hanoi' board */
/**
* Provides the instance of the 'Tower of Hanoi' board.
* Exactly one instance is supported.
*
* @return TohBoard The board instance.
*/
<type> tb_get_board();
/**
* Removes all disks from any rod of the given board.
*
* @param board The board instance in focus.
*/
<type> tb_clear_board(<params>);
/**
* Determines whether or not the given board is valid.
* A board is NOT valid, if it is 0.
*
* @param board The board to evaluate.
* @return If the given board is valid, false otherwise.
*/
<type> tb_is_valid(<params>);
/**
* Provides the top-most disk of the given rod and removes it from this rod.
*
* @param board The board instance in focus.
* @param rodName The rod from which the disk shall be taken and removed.
* @return The removed disk or 0, if no disk was on the rod.
*/
<type> tb_pop_disk(<params>);
/**
* Applies the given disk to the given rod, if this
* is allowed according to the rules.
*
* @param board The board instance in focus.
* @param rodName The rod on which the disk shall be placed.
* @param disk The disk to place on the rod.
* @return True if the disk could be legally placed on the rod
* (move is allowed and disk is valid), false otherwise.
*/
<type> tb_push_disk(<params>);
/**
* Provides the disk from the named rod at the given position.
*
* @param board The board instance in focus.
* @param rodName The rod on which the disk shall be placed.
* @param idx The index of the desired disk on the named rod.
* Index 0 addresses the bottom-most disk.
* @return The addressed disk or 0, if not disk is located on the
* index position of the named rod.
*/
<type> tb_get_disk(<params>);

11
toh_disk.c Normal file
View file

@ -0,0 +1,11 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Disk ADT Implemenation
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* Implementation of toh_disk.h.
* ----------------------------------------------------------
*/

56
toh_disk.h Normal file
View file

@ -0,0 +1,56 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Disk ADT
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* The declaration of an Abstract Data Type representing
* a single disk of the Tower of Hanoi.
*
* @see toh_solver.h for details regarding *Tower of Hanoi*.
* ----------------------------------------------------------
*/
/* == !Include guard and required includes need to be added */
/** Declares a disk. */
/**
* Provides the instance of the disk with the given size.
* Valid disk sizes are from 1 to MAX_DISKS.
*
* @param size The size of the desired disk.
* @return The disk of the given size or 0,
* if no such disk is available.
*/
<type> td_get_disk(unsigned short <params>);
/**
* Determines whether or not the given disk is valid.
* It is valid if it is not 0 and has a size between 1 and MAX_DISKS.
*
* @param disk The disk in focus of this ADT.
* @return True if the disk is valid, false otherwise.
*/
<type> td_is_valid(<params>);
/**
* Provides the size of the given disk.
*
* @param disk The disk in focus of this ADT.
* @return The size of the disk, if it is valid or 0 otherwise.
*/
unsigned short td_get_size(<params>);
/**
* Compares the size of the candidate disk with size of the given disk.
*
* @param disk The disk in focus of this ADT.
* @param smaller_candidate The disk to evaluate.
* @return True if the 'smaller_candidate' disk is smaller than the
* given disk of this ADT and both disks are valid, false otherwise.
*/
<type> td_is_smaller(<params>);

77
toh_main_driver.c Normal file
View file

@ -0,0 +1,77 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Klasse: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Truth Table
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* Truth Table Generator Application.
* ----------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "toh_solver.h"
#include "toh_visualizer.h"
/* Forward declaration, required for test mode only. */
void toh_visualize_last();
/**
* Prompts the user for the number of disk of the next game.
* and returns that value.
*/
unsigned short ui_prompt_for_disk_count();
/**
* ui_branch handles the user interface mode of the application.
* @see main, test_branch.
*/
void ui_branch(unsigned short disk_count);
/* Main function evaluates the number of command line arguments.
* If the user passed one main switches into test mode, i.e., that
* the function test_branch() is called and the command line argument
* is handed over to this function. If no command line argument is given
* main switches into user interface mode and delegates the handling
* of this to the function ui_branch().
* @see test_branch, ui_branch.
*/
int main(int argc, char *argv[])
{
char* tmp;
unsigned short disk_count = 1;
/* NOTE: Don't change this function, required for auto. testing */
/* Implement ui_branch and ui_prompt_for_disk_count instead */
if (argc > 1) {
disk_count = strtoul(argv[1], &tmp, 10);
toh_disable_visualizer(true);
} else {
disk_count = ui_prompt_for_disk_count();
}
ui_branch(disk_count);
if (argc > 1) {
toh_visualize_last();
}
return 0;
}
unsigned short ui_prompt_for_disk_count() {
/* == YOUT IMPLEMENTATION GOES HERE == */
/* Hint: scanf for interactive disk count */
}
void ui_branch(unsigned short disk_count) {
/* == YOUT IMPLEMENTATION GOES HERE == */
/* initialize the solver */
/* solve the game */
}

47
toh_solver.c Normal file
View file

@ -0,0 +1,47 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Disk ADT implementation
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* Implementation of toh_board.h.
* ----------------------------------------------------------
*/
/* Includes, definitions and instanciations */
/* ========================================================= */
/* Private functions */
/**
* Moves a single disk from the top of the 'source' rod to the 'target' rod.
* The move shall only be performed if it is allowed.
*
* @param source The rod from which the disk shall be moved.
* @param target The rod to which the disk shall be moved.
* @return True if the move was successful and according to the rules, false otherwise.
*/
static <type> ts_move_disk(<params>) {
}
/**
* Moves a stack of disks of the given size form the 'source' rod to the 'target' rod
* using the 'intermediate' rod as intermediate disk buffer.
* The move shall only be performed if it is valid. The move is valid, if each
* move of affected disks is allowed.
*
* @param size The size of the disk stack to move.
* @param source The rod from which the disks shall be moved.
* @param intermediate The rod that serves as intermediate buffer for the disks.
* @param target The rod to which the disks shall be moved.
* @return True if the move was successful and according to the rules, false otherwise.
*/
static <type> ts_move_stack(<params>) {
}
/* ========================================================= */
/* Public functions */

45
toh_solver.h Normal file
View file

@ -0,0 +1,45 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: <your class>
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Board / Game
* Author: */<your name>/*
* ----------------------------------------------------------
* Description:
* The Tower of Hanoi is a mathematical game or puzzle.
* The board consists of three rods and a number of disks of different sizes, which can slide onto any rod.
* At the beginning, all disks are placed on the left rod in ascending order of their size, the smallest disk at the top.
*
* The objective of the puzzle is to move the entire stack of disks from the left to the right rod, obeying the following rules:
* + Only one disk can be moved at a time.
* + Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty rod.
* + No larger disk may be placed on top of a smaller disk.
*
* The minimal number of moves required to solve a Tower of Hanoi puzzle is 2n 1, where n is the number of disks.
* (source: Wikipedia)
* ----------------------------------------------------------
*/
/* == !Include guard and required includes need to be added */
/**
* Initials a 'Tower of Hanoi' board with the given number of disks.
* To initialize the board, all reqired disks are placed on the left rod
* in ascending order of their size, the smallest disk at the top.
* The middle and right rod are empty.
*
* All disks are initialized accordingly.
*
* @param disk_count The number of disks to use. Must be less than 'MAX_DISKS'.
*/
<type> ts_init(<params>);
/**
* Solves the puzzle by moving all disks from the left rod to the right rod.
* In fact, this is the only function needed to 'play' the game after the
* board was initialized.
*
*/
<type> ts_solve();
#endif

65
toh_test_driver.c Normal file
View file

@ -0,0 +1,65 @@
/*----------------------------------------------------------
* HTBLA-Leonding
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Test Driver for Truth Table Generator
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Executes all unit tests of Truth Table Generator.
* ----------------------------------------------------------
*/
#include "shortcut.h"
#include "test_toh_disk.h"
#include "test_toh_board.h"
#include "test_toh_solver.h"
int main(int argc, char *argv[])
{
ADD_TEST(test_td_get_disk__shall_provide_valid_disk_for_each_size);
ADD_TEST(test_td_get_disk__shall_provide_0_for_invalid_size);
ADD_TEST(test_td_is_valid__shall_be_valid_for_valid_disks);
ADD_TEST(test_td_is_valid__shall_be_invalid_for_0_disks);
ADD_TEST(test_td_is_valid__shall_be_invalid_for_disks_with_invalid_sizes);
ADD_TEST(test_td_get_size__shall_provide_size_of_valid_disk);
ADD_TEST(test_td_get_size__shall_provide_0_for_invalid_disk);
ADD_TEST(test_td_is_smaller__shall_be_true_for_smaller_disks);
ADD_TEST(test_td_is_smaller__shall_be_false_for_larger_disks);
ADD_TEST(test_td_is_smaller__shall_be_false_for_invalid_disk);
ADD_TEST(test_td_is_smaller__shall_be_false_for_invalid_candidates);
ADD_TEST(test_td_is_smaller__shall_be_false_for_invalid_attributes);
ADD_TEST(test_tb_get_board__shall_provide_valid_board);
ADD_TEST(test_tb_get_board__shall_provide_the_same_board_each_time);
ADD_TEST(test_tb_is_valid__shall_be_invalid_for_0_board);
ADD_TEST(test_tb_push_disk__shall_push_valid_disks_on_each_rod);
ADD_TEST(test_tb_push_disk__shall_not_push_on_invalid_board);
ADD_TEST(test_tb_push_disk__shall_not_push_invalid_disks_on_each_rod);
ADD_TEST(test_tb_push_disk__shall_not_push_wrong_disks_on_any_rod);
ADD_TEST(test_tb_pop_disk__shall_pop_valid_disks_from_each_rod);
ADD_TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_each_empty_rod);
ADD_TEST(test_tb_pop_disk__shall_pop_invalid_disks_from_invalid_board);
ADD_TEST(test_tb_get_disk__shall_provide_valid_disks_from_each_rod);
ADD_TEST(test_tb_get_disk__shall_provide_0_for_invalid_board);
ADD_TEST(test_tb_get_disk__shall_provide_0_for_empty_rod_positions);
ADD_TEST(test_ts_init__with_one_disk);
ADD_TEST(test_ts_init__with_many_disks);
ADD_TEST(test_ts_init__subsequent_inits);
ADD_TEST(test_ts_solve__one);
ADD_TEST(test_ts_solve__two);
ADD_TEST(test_ts_solve__three);
run_tests();
return 0;
}

163
toh_visualizer.c Normal file
View file

@ -0,0 +1,163 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Visualizer
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Implementation of ToH Visualizer.
* ----------------------------------------------------------
*/
#include "toh_visualizer.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "config.h"
/* The encapsulated visualizer data */
struct VisData {
bool disabled;
unsigned short refresh_line_count;
unsigned short disk_count;
int offset;
int board_oversize;
int left_rod_pos;
int middle_rod_pos;
int right_rod_pos;
int last_move_count;
int total_move_count;
char* last_msg;
unsigned short last_disk_count_left;
unsigned short last_disk_count_middle;
unsigned short last_disk_count_right;
};
/* The visualizer instance */
static struct VisData vis_data = {0};
/* Provides the number output lines for a configured game. */
static void _print_new_line() {
vis_data.refresh_line_count++;
printf("\n");
}
/* Prints the given disk on the given rod or a 'rod' marker if no disk is given */
static void _print_centered_disk(Disk disk, int center) {
char symbol = '|';
int width = 1;
/* determine disk properties */
if (td_is_valid(disk)) {
width = 2 * td_get_size(disk) - 1;
symbol = '#';
}
printf("\033[%dG", center - (width / 2)); /* set the cursor to the left border of the disk */
for (int c = 0; c < width; c++) {
printf("%c", symbol);
}
}
/* Prints the bottom line of the board. */
static void _print_board() {
if (vis_data.disk_count > 0) {
printf("\033[2K"); /* clear current line */
printf("\033[%dG", vis_data.offset); /* set cursor to end of offset */
int board_width = vis_data.left_rod_pos + vis_data.right_rod_pos + 2 * vis_data.board_oversize;
for (int i = 0; i < board_width; i++) {
printf("=");
}
_print_new_line();
}
}
/* Prints the status line */
static void _print_status_line(unsigned int move_count) {
printf("\033[2K"); /* clear current line */
printf("\033[%dG", vis_data.offset); /* set cursor to end of offset */
printf("Move %4u of %u", move_count, vis_data.total_move_count);
_print_new_line();
}
/* Prints the message line */
static void _print_message(char* msg) {
printf("\033[2K"); /* clear current line */
printf("\033[%dG", vis_data.offset); /* set cursor to end of offset */
if (msg != 0) {
printf("%s", msg);
}
_print_new_line();
}
/* Prints the game: disks and board */
static void _print_game(TohBoard board, unsigned int move_count, char* msg) {
printf("\033[%dA", vis_data.refresh_line_count); /* move cursor to the first line of the game output */
vis_data.refresh_line_count = 0;
_print_new_line(); /* print an empty heading line */
for (int disk_idx = vis_data.disk_count; disk_idx >= 0; disk_idx--) {
printf("\033[2K"); /* clear current line */
int offset = vis_data.offset + vis_data.board_oversize;
_print_centered_disk(tb_get_disk(board, LEFT, disk_idx), offset + vis_data.left_rod_pos);
_print_centered_disk(tb_get_disk(board, MIDDLE, disk_idx), offset + vis_data.middle_rod_pos);
_print_centered_disk(tb_get_disk(board, RIGHT, disk_idx), offset + vis_data.right_rod_pos);
_print_new_line();
}
_print_board(vis_data.disk_count + 2);
_print_status_line(move_count);
_print_message(msg);
_print_new_line(); /* blank line */
}
void toh_init_visualizer(unsigned short disk_count) {
if (disk_count > 0) {
vis_data.refresh_line_count = 0;
vis_data.disk_count = disk_count;
vis_data.total_move_count = pow(2, disk_count) - 1;
vis_data.offset = VIS_BOARD_OFFSET;
vis_data.board_oversize = 2;
int rod_distance = 2 * disk_count - 1 + 2; /* width of the largest disk + 1 gap on each side */
vis_data.left_rod_pos = rod_distance / 2 ;
vis_data.middle_rod_pos = vis_data.left_rod_pos + rod_distance;
vis_data.right_rod_pos = vis_data.middle_rod_pos + rod_distance;
}
}
void toh_disable_visualizer(bool disable) {
vis_data.disabled = disable;
}
void toh_visualize(TohBoard board, unsigned int move_count) {
toh_visualize_with_msg(board, move_count, 0);
}
void toh_visualize_with_msg(TohBoard board, unsigned int move_count, char* msg) {
vis_data.last_move_count = move_count;
vis_data.last_msg = msg;
if (!vis_data.disabled) {
if (!tb_is_valid(board)) {
printf("invalid board given!");
} else {
_print_game(board, move_count, msg);
if (MOVE_DELAY > 0) {
usleep(MOVE_DELAY * 100 * 1000);
}
}
}
}
void toh_visualize_last() {
bool disabled = vis_data.disabled;
vis_data.disabled = false;
TohBoard board = tb_get_board();
toh_visualize_with_msg(board, vis_data.last_move_count, vis_data.last_msg);
vis_data.disabled = disabled;
}

61
toh_visualizer.h Normal file
View file

@ -0,0 +1,61 @@
/*----------------------------------------------------------
* HTBLA-Leonding / Class: n/a
* ---------------------------------------------------------
* Exercise Number: 09
* Title: Tower of Hanoi Visualizer
* Author: S. Schraml
* Due Date: n/a
* ----------------------------------------------------------
* Description:
* Prints the Tower of Hanoi to standard output
* ----------------------------------------------------------
*/
#ifndef ___TOH_VISUALIZER_H
#define ___TOH_VISUALIZER_H
#include <stdbool.h>
#include "toh_board.h"
#include "toh_disk.h"
/**
* Initializes the ToH visualization with required attributes.
*
* @param disk_count The total number of disks on the board.
*/
void toh_init_visualizer(unsigned short disk_count);
/**
* Specifies whether or not visualization is enabled.
* With enabled visualization, ToH board is shown on
* standard output and each visualization step adds a delay.
* Disabled visualization does neither print the board
* nor does it add a delay.
*
* Default value is enabled. This feature is intended for
* automatic testing.
*
* @param disable True to disable, false to enable the visualizer.
*/
void toh_disable_visualizer(bool disable);
/**
* Prints the current configuration of the Tower of Hanoi board.
*
* @param TohBoard The Tower of Hanoi Board to print.
* @param move_count The number of moves so far.
* @param msg The status message to print, may be 0 or empty.
*/
void toh_visualize(TohBoard board, unsigned int move_count);
/**
* Same as function `toh_visualize(board, move_count)` but is
* capable of printing an additional text message.
*
* @param TohBoard The Tower of Hanoi Board to print.
* @param move_count The number of moves so far.
* @param msg The status message to print, may be 0 or empty.
*/
void toh_visualize_with_msg(TohBoard board, unsigned int move_count, char* msg);
#endif