feat(cmat): add cmake build for course material

Add a CMakeLists.txt to each exercise directory, included from
cmat/CMakeLists.txt, so every exercise and solution becomes a buildable
target. GUI exercises link the curses-based DOS_Unix implementations on
Unix-like systems; the Windows-specific DOS variants are not compiled.
Exercises without a portable path or with missing dependencies (Boost)
are reported as not available at configure time.

Targets are excluded from the default build and built by name, e.g.
`cmake --build build --target Ex11`, so intentionally buggy exercises
such as Ex21 do not break the default build.

Also fix two portability issues: rename Ex11bug/pole.h to Pole.h for
case-sensitive filesystems and drop the extra Light:: qualification in
SolutionEx71A/Light.h. Document build commands and layout in AGENTS.md.

Co-authored-by: Qwen 3.8 27B <qwen3.8_27b-q3_k_xl@lmstudio.local>
This commit is contained in:
2026-10-05 11:55:00 +02:00
co-authored by Qwen 3.8 27B
parent e8241fd1ff
commit e09540c2b2
701 changed files with 27282 additions and 16 deletions
+15
View File
@@ -0,0 +1,15 @@
# SolutionEx71ABonus
cmat_add_exercise(SolutionEx71ABonus
GUI
SOURCES
ConsolePoleVisitor.cpp
Light.cpp
main.cpp
Pelican.cpp
Pole.cpp
PowerVisitor.cpp
Subject.cpp
Timer.cpp
TimerSet.cpp
)
@@ -0,0 +1,14 @@
// ======================================================
// ConsolePole.cpp
// ======================================================
#include "ConsolePoleVisitor.h"
#include "Light.h"
#include "Pole.h"
#include "Screen.h"
void ConsolePoleVisitor::update(const Hint &h) { MyPole.accept(*this); }
ConsolePoleVisitor::ConsolePoleVisitor(Pole &p) : MyPole(p) { MyPole.accept(*this); }
void ConsolePoleVisitor::visit(Light &l) { Screen::write(l.getString(), l.getX(), l.getY(), l.getColor()); }
@@ -0,0 +1,23 @@
// ======================================================
// ConsolePole.h
// ======================================================
#ifndef CONSOLEPOLEVISITOR_H
#define CONSOLEPOLEVISITOR_H
#include "Observer.h"
class Pole;
#include "PoleVisitor.h"
class ConsolePoleVisitor : public Observer, public PoleVisitor {
public:
ConsolePoleVisitor(Pole &);
virtual void update(const Hint &);
virtual void visit(Light &);
private:
Pole &MyPole;
};
#endif
+20
View File
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ex71", "Ex71.vcxproj", "{3D7880AE-E251-9B65-4D9A-70B4E2BCB93C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3D7880AE-E251-9B65-4D9A-70B4E2BCB93C}.Debug|Win32.ActiveCfg = Debug|Win32
{3D7880AE-E251-9B65-4D9A-70B4E2BCB93C}.Debug|Win32.Build.0 = Debug|Win32
{3D7880AE-E251-9B65-4D9A-70B4E2BCB93C}.Release|Win32.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+154
View File
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<ProjectGuid>{3D7880AE-E251-9B65-4D9A-70B4E2BCB93C}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<PrecompiledHeaderOutputFile>.\Release/Ex71.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
<ObjectFileName>.\Release/</ObjectFileName>
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release/Ex71.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ProgramDatabaseFile>.\Release/Ex71.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
<Midl>
<TypeLibraryName>.\Release/Ex71.tlb</TypeLibraryName>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderOutputFile>.\Debug/Ex71.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
<ObjectFileName>.\Debug/</ObjectFileName>
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\course\397\DOS_Unix;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug/Ex71.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/Ex71.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
<Midl>
<TypeLibraryName>.\Debug/Ex71.tlb</TypeLibraryName>
</Midl>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ConsolePoleVisitor.cpp" />
<ClCompile Include="Light.cpp" />
<ClCompile Include="Pelican.cpp" />
<ClCompile Include="Pole.cpp" />
<ClCompile Include="PowerVisitor.cpp" />
<ClCompile Include="Subject.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="TimerSet.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="..\DOS_Unix\Keyboard_DOS.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\DOS_Unix\Screen_DOS.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ConsolePoleVisitor.h" />
<ClInclude Include="Light.h" />
<ClInclude Include="Observer.h" />
<ClInclude Include="Pelican.h" />
<ClInclude Include="Pole.h" />
<ClInclude Include="PoleVisitor.h" />
<ClInclude Include="PowerVisitor.h" />
<ClInclude Include="Subject.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="TimerSet.h" />
<ClInclude Include="..\DOS_Unix\Keyboard.h" />
<ClInclude Include="..\DOS_Unix\Screen.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{0b227cf9-5391-4e90-8d9f-fc451731aeee}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{da5f2d9c-de70-4bec-afc6-e895bd2dad8c}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl</Extensions>
</Filter>
<Filter Include="DOS_Unix">
<UniqueIdentifier>{a539e3af-b783-430f-b157-9886e19d62cc}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Light.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Pelican.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Pole.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Subject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TimerSet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\DOS_Unix\Keyboard_DOS.cpp">
<Filter>DOS_Unix</Filter>
</ClCompile>
<ClCompile Include="..\DOS_Unix\Screen_DOS.cpp">
<Filter>DOS_Unix</Filter>
</ClCompile>
<ClCompile Include="ConsolePoleVisitor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PowerVisitor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Light.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Observer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Pelican.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Pole.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Subject.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TimerSet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\DOS_Unix\Keyboard.h">
<Filter>DOS_Unix</Filter>
</ClInclude>
<ClInclude Include="..\DOS_Unix\Screen.h">
<Filter>DOS_Unix</Filter>
</ClInclude>
<ClInclude Include="ConsolePoleVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PoleVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PowerVisitor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
+28
View File
@@ -0,0 +1,28 @@
// ======================================================
// Light.cpp
// ======================================================
#include "Light.h"
#include "PoleVisitor.h"
#include <iostream>
Light::Light(std::string name, int x, int y, int color) : x(x), y(y), c(color), name(name) {}
Light::~Light() {
std::cout << "Deleting light (" << name << ", " << x << ", " << y << ", " << c << ")"
<< "\n";
}
void Light::accept(PoleVisitor &pv) { pv.visit(*this); }
void Light::set(LightState new_state) { state = new_state; }
Light::LightState Light::get(void) { return state; }
int Light::getColor(void) { return state == OFF ? 0 : (state == FLASH ? 128 + c : c); }
std::string Light::getString() { return name; }
int Light::getX() { return x; }
int Light::getY() { return y; }
+36
View File
@@ -0,0 +1,36 @@
// ======================================================
// Light.h
// ======================================================
#ifndef LIGHT_H
#define LIGHT_H
#include <string>
class PoleVisitor;
class Light {
public:
Light(std::string name, int x, int y, int color);
~Light();
enum LightState { ON, OFF, FLASH };
int getColor();
std::string getString();
int getX();
int getY();
void set(LightState newState); // now just sets the state
LightState get(void);
void accept(PoleVisitor &);
private:
int c; // light color
int x, y;
std::string name;
LightState state;
};
#endif
+15
View File
@@ -0,0 +1,15 @@
// ======================================================
// Observer.h
// ======================================================
#ifndef OBSERVER_H
#define OBSERVER_H
#include "Subject.h"
class Observer {
public:
virtual void update(const Hint &) = 0;
};
#endif
+61
View File
@@ -0,0 +1,61 @@
// ======================================================
// Pelican.cpp
// ======================================================
#include "Pelican.h"
#include "Pole.h"
#include "Timer.h"
Pelican::Pelican() : pressed(false), RED_TIME(4), YELLOW_TIME(2), GREEN_TIME(3), FLASH_TIME(5), state(GREEN_IDLE) {
myTimer = new Timer([this] { timerExpired(); });
}
void Pelican::press(void) {
if (state == GREEN_IDLE) {
state = YELLOW_STATE;
myTimer->timeoutRequest(YELLOW_TIME);
pressed = true;
notify(WaitHint(pressed));
notify(LightHint(state));
} else if (state != RED_STATE) {
pressed = true;
notify(WaitHint(pressed));
}
}
void Pelican::timerExpired(void) {
switch (state) {
case RED_STATE:
state = YELLOW_FLASHING;
myTimer->timeoutRequest(FLASH_TIME);
break;
case YELLOW_FLASHING:
state = GREEN_TIMING;
myTimer->timeoutRequest(GREEN_TIME);
break;
case GREEN_TIMING:
if (pressed) {
state = YELLOW_STATE;
myTimer->timeoutRequest(YELLOW_TIME);
} else {
state = GREEN_IDLE;
}
break;
case GREEN_IDLE:
// should never happen
break;
case YELLOW_STATE:
state = RED_STATE;
pressed = false;
notify(WaitHint(pressed));
myTimer->timeoutRequest(RED_TIME);
break;
}
notify(LightHint(state));
}
+65
View File
@@ -0,0 +1,65 @@
// ======================================================
// Pelican.h
//
// Represents a Pelican crossing
//
// ======================================================
#ifndef PELICAN_H
#define PELICAN_H
#include "Subject.h"
#include "Timer.h"
class Pelican : public Subject {
public:
Pelican();
// call when the WAIT button has been pressed
void press(void);
// states that a Pelican can be in
enum PelicanState { RED_STATE, YELLOW_FLASHING, GREEN_TIMING, GREEN_IDLE, YELLOW_STATE };
bool isPressed() const { return pressed; }
PelicanState getState() const { return state; }
private:
// state that this Pelican is in
PelicanState state;
// called by PeleicanTimer when the lights need to change
void timerExpired(void);
const unsigned int RED_TIME;
const unsigned int YELLOW_TIME;
const unsigned int GREEN_TIME;
const unsigned int FLASH_TIME;
// indicates whether the WAIT light should be on
bool pressed;
// Timer that indicates when the lights should change
Timer *myTimer;
private:
// prevent general use of copy ctor and operator=
Pelican(const Pelican &);
Pelican &operator=(const Pelican &);
};
class LightHint : public Hint {
public:
LightHint(Pelican::PelicanState s) : state(s) {}
Pelican::PelicanState state;
};
class WaitHint : public Hint {
public:
WaitHint(bool p) : pressed(p) {}
bool pressed;
};
#endif
+95
View File
@@ -0,0 +1,95 @@
// ======================================================
// Pole.cpp
// ======================================================
#include <iostream>
#include "Pelican.h"
#include "Pole.h"
#include "PoleVisitor.h"
#include "Screen.h"
void Pole::accept(PoleVisitor &pv) {
for (int i = RED_LIGHT; i <= RED_MAN; i++) {
lights[i]->accept(pv);
}
waitLight->accept(pv);
}
Pole::Pole(int x, int y, Pelican &pelican)
: waitLight(new Light("WAIT", x + 6, y + 12, Screen::WHITE)), myPelican(pelican) {
using namespace Screen;
lights[RED_LIGHT] = new Light("*", x + 11, y + 3, RED);
lights[RED_MAN] = new Light("*<-=", x + 6, y + 4, RED);
lights[YELLOW_LIGHT] = new Light("*", x + 11, y + 5, YELLOW);
lights[GREEN_LIGHT] = new Light("*", x + 11, y + 7, GREEN);
lights[GREEN_MAN] = new Light("*|-<", x + 6, y + 7, GREEN);
write(" _____ ", x, ++y, GRAY);
write(" /___ /| ", x, ++y, GRAY);
write(" | | | ", x, ++y, GRAY);
write(" | |/| ", x, ++y, GRAY);
write(" |____| | ", x, ++y, GRAY);
write(" | |/| ", x, ++y, GRAY);
write(" | | | ", x, ++y, GRAY);
write(" |____|/ ", x, ++y, GRAY);
write(" _||__ ", x, ++y, GRAY);
write(" /___ /| ", x, ++y, GRAY);
write(" | | | ", x, ++y, GRAY);
write(" | | | ", x, ++y, GRAY);
write(" |____|/ ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write(" || ", x, ++y, GRAY);
write("========||===========", x, ++y, GRAY);
write(" / || / ", x, ++y, GRAY);
write("_ /_________ /_ ", x, ++y, GRAY);
write("/ / ", x, ++y, GRAY);
// the only time we need to ask the Pelican its state is at start up
update(Hint());
}
Pole::~Pole() {
for (int i = 0; i < sizeof lights / sizeof(lights[0]); ++i)
delete lights[i];
delete waitLight;
}
void Pole::update(const Hint &h) {
if (typeid(h) == typeid(WaitHint)) {
const WaitHint *whPtr = dynamic_cast<const WaitHint *>(&h);
setWaitLight(whPtr->pressed);
} else if (typeid(h) == typeid(LightHint)) {
const LightHint &lh = dynamic_cast<const LightHint &>(h);
setTrafficLights(lh.state);
} else {
// get the state and update everything
setWaitLight(myPelican.isPressed());
setTrafficLights(myPelican.getState());
notify(Hint());
}
notify(h);
}
void Pole::setTrafficLights(Pelican::PelicanState state) {
static const Light::LightState LightStates[Pelican::YELLOW_STATE + 1][RED_MAN + 1] = {
// red yellow green green man red man
{Light::ON, Light::OFF, Light::OFF, Light::ON, Light::OFF}, // red
{Light::OFF, Light::FLASH, Light::OFF, Light::FLASH, Light::OFF}, // y flash
{Light::OFF, Light::OFF, Light::ON, Light::OFF, Light::ON}, // g time
{Light::OFF, Light::OFF, Light::ON, Light::OFF, Light::ON}, // g idle
{Light::OFF, Light::ON, Light::OFF, Light::OFF, Light::ON} // yellow
};
for (int i = RED_LIGHT; i <= RED_MAN; i++) {
lights[i]->set(LightStates[state][i]);
}
}
void Pole::setWaitLight(bool state) { waitLight->set(state ? Light::ON : Light::OFF); }
+37
View File
@@ -0,0 +1,37 @@
// ======================================================
// Pole.h
// ======================================================
#ifndef POLE_H
#define POLE_H
#include "Light.h"
#include "Observer.h"
#include "Pelican.h"
#include "Subject.h"
class Hint;
class PoleVisitor;
class Pole : public Observer, public Subject {
public:
void update(const Hint &);
void accept(PoleVisitor &);
Pole(int x, int y, Pelican &p);
~Pole();
private:
Pelican &myPelican;
void setTrafficLights(Pelican::PelicanState);
void setWaitLight(bool);
enum LightName { RED_LIGHT, YELLOW_LIGHT, GREEN_LIGHT, GREEN_MAN, RED_MAN };
Light *lights[RED_MAN + 1];
Light *waitLight;
};
#endif
+15
View File
@@ -0,0 +1,15 @@
// ======================================================
// PoleVisitor.h
// ======================================================
#ifndef POLEVISITOR_H
#define POLEVISITOR_H
class Light;
class PoleVisitor {
public:
virtual void visit(Light &) = 0;
};
#endif
+23
View File
@@ -0,0 +1,23 @@
#include "PowerVisitor.h"
#include "Light.h"
#include "Pole.h"
#include <iostream>
void PowerVisitor::visit(Light &l) {
switch (l.get()) {
case Light::ON:
runningTotal += 60;
break;
case Light::FLASH:
runningTotal += 30;
break;
}
}
void PowerVisitor::calculatePower(Pole &p) {
runningTotal = 0;
p.accept(*this);
std::cout << "Power usage is " << runningTotal << " watts.\n";
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "PoleVisitor.h"
class Pole;
class PowerVisitor : public PoleVisitor {
private:
int runningTotal;
public:
void visit(Light &l);
void calculatePower(Pole &p);
};
+14
View File
@@ -0,0 +1,14 @@
// ======================================================
// Subject.cpp
// ======================================================
#include "Subject.h"
#include "Observer.h"
void Subject::attach(Observer &obs) { myObservers.insert(&obs); }
void Subject::notify(const Hint &h) const {
for (ObsList::const_iterator iter = myObservers.begin(); iter != myObservers.end(); ++iter) {
(*iter)->update(h);
}
}
+29
View File
@@ -0,0 +1,29 @@
// ======================================================
// Subject.h
// ======================================================
#ifndef SUBJECT_H
#define SUBJECT_H
class Observer;
#include <set>
class Hint {
public:
virtual ~Hint() {}
};
class Subject {
public:
typedef std::set<Observer *> ObsList;
void attach(Observer &obs);
protected:
void notify(const Hint &) const;
private:
ObsList myObservers;
};
#endif
+27
View File
@@ -0,0 +1,27 @@
// ======================================================
// timer.cpp
// ======================================================
#include "Timer.h"
#include "TimerSet.h"
void Timer::timeoutRequest(int seconds) { timeToGo = seconds; }
Timer::Timer(std::function<void(void)> action) : timeToGo(-1), doExpired(action) {
TimerSet::Instance().addATimer(this);
}
void Timer::tick() {
if (isExpired()) {
doExpired();
}
}
bool Timer::isExpired() {
if (timeToGo > 0) {
if (--timeToGo == 0) {
return true;
}
}
return false;
}
+34
View File
@@ -0,0 +1,34 @@
// ======================================================
// Timer.h
//
// A general-purpose countdown timer
// To use this class, specialize it
// and override tick()
//
// ======================================================
#ifndef timer_H
#define timer_H
#include <ctime>
#include <functional>
class Timer {
public:
Timer(std::function<void(void)> action);
void timeoutRequest(int seconds);
// template method
void tick();
protected:
bool isExpired();
private:
std::function<void(void)> doExpired;
int timeToGo;
};
#endif
+37
View File
@@ -0,0 +1,37 @@
#include "TimerSet.h"
#include "Timer.h"
#include <iostream>
// Member functions
TimerSet::TimerSet()
: previousTime(time(&previousTime)), pollingThread([this]() { poll10Hz(); }) // Exercise 5.1 start thread
{
pollingThread.detach(); // let it die on its own, without join
}
// Exercise 5.1 new function
void TimerSet::poll10Hz() {
std::chrono::duration<int, std::milli> pause(100);
while (true) {
std::this_thread::sleep_for(pause);
pollAllTimers();
}
}
void TimerSet::addATimer(Timer *t) { timers.push_back(t); }
void TimerSet::pollAllTimers() {
std::time_t timeNow;
if (time(&timeNow) > previousTime) {
previousTime = timeNow;
for (auto it = timers.begin(); it != timers.end(); it++) {
(*it)->tick();
}
}
}
TimerSet &TimerSet::Instance() {
static TimerSet pInstance;
return pInstance;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef TIMERSET_H
#define TIMERSET_H
#include <ctime>
#include <thread>
#include <vector>
class Timer;
class TimerSet {
public:
void pollAllTimers();
void addATimer(Timer *);
private:
TimerSet();
std::vector<Timer *> timers;
std::time_t previousTime;
// Exercise 5.1 Threading two new members
std::thread pollingThread;
void poll10Hz();
// Meyer's Singleton
public:
static TimerSet &Instance();
private:
TimerSet(const TimerSet &);
TimerSet &operator=(const TimerSet &);
};
#endif
+43
View File
@@ -0,0 +1,43 @@
// =================================================================
// main.cpp (for pelican crossing program)
// =================================================================
#include "ConsolePoleVisitor.h"
#include "Keyboard.h"
#include "Pelican.h"
#include "Pole.h"
#include "PowerVisitor.h"
#include "TimerSet.h"
#include <cctype> // provides toupper()
int main() {
Keyboard kbd;
Pelican thePelican;
Pole pole1(20, 0, thePelican);
thePelican.attach(pole1);
ConsolePoleVisitor cp1(pole1);
pole1.attach(cp1);
Pole pole2(40, 0, thePelican);
thePelican.attach(pole2);
ConsolePoleVisitor cp2(pole2);
pole2.attach(cp2);
char c = 0;
while (std::toupper(c) != 'Q') { // loop until 'Q' is pressed
c = kbd.getChar(); // get the character
if (c == ' ') {
// it's a space, so press the WAIT button
thePelican.press();
} else if (c == 'p') {
PowerVisitor pv;
pv.calculatePower(pole1);
}
}
return 0;
}