halo
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
# Aufruf linux: make -f makefilename
|
||||
# Aufruf win: mingw32-make -f makefilename
|
||||
# -B: Build all; Alle Ziele ohne Bedingungen erstellen
|
||||
#
|
||||
automat.exe: automat.o checker.o view.o io.o main.o
|
||||
gcc -o automat.exe automat.o checker.o view.o io.o main.o
|
||||
|
||||
automat.o: automat.c automat.h
|
||||
gcc -c -Wall automat.c
|
||||
|
||||
checker.o: checker.c checker.h automat.h s_transaction_list.h
|
||||
gcc -c -Wall checker.c
|
||||
|
||||
view.o: view.c view.h automat.h io.h
|
||||
gcc -c -Wall view.c
|
||||
|
||||
io.o: io.c io.h
|
||||
gcc -c -Wall io.c
|
||||
|
||||
main.o: main.c view.h automat.h checker.h
|
||||
gcc -c -Wall main.c
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "automat.h"
|
||||
|
||||
typedef enum {A=0,B,C,D,E,F,H,I, NR_OF_STATES} state_t;
|
||||
|
||||
static state_t s_curstate = A;
|
||||
static int s_guthaben = 0;
|
||||
static bool s_kaffee_los = false;
|
||||
static bool s_muenz_rueck = false;
|
||||
static bool s_display = false;
|
||||
static const char* s_display_string = "Warten";
|
||||
|
||||
void automat_reset(void)
|
||||
{
|
||||
s_curstate = A;
|
||||
s_guthaben = 0;
|
||||
s_kaffee_los = false;
|
||||
s_muenz_rueck = false;
|
||||
s_display = false;
|
||||
s_display_string = "Warten";
|
||||
}
|
||||
|
||||
void automat_transition(BOOL becher, BOOL muenze, BOOL muenz_wert)
|
||||
{
|
||||
s_kaffee_los = false;
|
||||
s_muenz_rueck = false;
|
||||
s_display = false;
|
||||
|
||||
switch (s_curstate) {
|
||||
case A: case B: case C: case D:
|
||||
// Münzeinwurf
|
||||
if (muenze) {
|
||||
int wert = muenz_wert ? 2 : 1;
|
||||
if (s_guthaben + wert > 4) {
|
||||
s_muenz_rueck = true;
|
||||
s_display_string = "Zu viel! Münze zurück";
|
||||
} else {
|
||||
s_guthaben += wert;
|
||||
}
|
||||
}
|
||||
// *** Hier ist die Änderung ***
|
||||
if (s_guthaben < 4) {
|
||||
if (s_guthaben == 0) s_curstate = A, s_display_string = "Warten";
|
||||
else if (s_guthaben == 1) s_curstate = B, s_display_string = "1 Euro";
|
||||
else if (s_guthaben == 2) s_curstate = C, s_display_string = "2 Euro";
|
||||
else if (s_guthaben == 3) s_curstate = D, s_display_string = "3 Euro";
|
||||
} else if (s_guthaben == 4) {
|
||||
if (becher) {
|
||||
s_curstate = F;
|
||||
s_kaffee_los = true;
|
||||
s_display = true;
|
||||
s_display_string = "Kaffee wird ausgegeben";
|
||||
s_guthaben = 0; // Guthaben wird nach Ausgabe zurückgesetzt!
|
||||
} else {
|
||||
s_curstate = E;
|
||||
s_display = true;
|
||||
s_display_string = "Bitte Becher unterstellen!";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case E: // 4 Euro, warte auf Becher
|
||||
s_display = true;
|
||||
s_display_string = "Bitte Becher unterstellen!";
|
||||
if (becher) {
|
||||
s_curstate = F;
|
||||
s_kaffee_los = true;
|
||||
s_display_string = "Kaffee wird ausgegeben";
|
||||
s_guthaben = 0; // Guthaben wird nach Ausgabe zurückgesetzt!
|
||||
}
|
||||
break;
|
||||
|
||||
case F: // Kaffee läuft, warte auf Becherentnahme
|
||||
s_display = true;
|
||||
s_display_string = "Becher entnehmen";
|
||||
if (!becher) {
|
||||
s_curstate = A;
|
||||
s_display = false;
|
||||
s_display_string = "Warten";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
s_curstate = A;
|
||||
s_guthaben = 0;
|
||||
s_display = false;
|
||||
s_display_string = "Warten";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fsm_action_t automat_output(void)
|
||||
{
|
||||
return (fsm_action_t){
|
||||
.display = s_display,
|
||||
.muenz_rueck = s_muenz_rueck,
|
||||
.kaffee_los = s_kaffee_los,
|
||||
.guthaben = s_guthaben,
|
||||
.display_string = s_display_string
|
||||
};
|
||||
}
|
||||
//gcc automat.c view.c main.c io.c checker.c -o console_automat
|
||||
@@ -0,0 +1,44 @@
|
||||
/**********************************************************************\
|
||||
* Kurzbeschreibung: automat.h
|
||||
* Stellt Funktionen zur Realisierung eines Automaten zur Verfügung,
|
||||
* die über die in der automat.h vorgegebene C-Schnittstelle
|
||||
* mit einer grafischen Schnittstelle kommunizieren.
|
||||
*
|
||||
* Datum: Autor: Grund der Aenderung:
|
||||
*
|
||||
*
|
||||
\**********************************************************************/
|
||||
#ifndef AUTOMAT_H
|
||||
#define AUTOMAT_H
|
||||
|
||||
/*--- #defines -------------------------------------------------------*/
|
||||
#define true 1
|
||||
#define false 0
|
||||
/*--- Datentypen (typedef) -------------------------------------------*/
|
||||
typedef int BOOL;
|
||||
|
||||
typedef struct {
|
||||
BOOL display;
|
||||
BOOL muenz_rueck;
|
||||
BOOL kaffee_los;
|
||||
int guthaben;
|
||||
const char * display_string;
|
||||
} fsm_action_t;
|
||||
|
||||
/*--- Prototypen globaler Funktionen ---------------------------------*/
|
||||
/*--------------------------------------------------------------------*
|
||||
* Setzt den Automat in IDLE state *
|
||||
*--------------------------------------------------------------------*/
|
||||
extern void automat_reset(void);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
* Fuehrt Zustandsuebergaenge durch *
|
||||
*--------------------------------------------------------------------*/
|
||||
extern void automat_transition(BOOL becher, BOOL muenze, BOOL muenz_wert);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
* Gibt Informationen ueber aktuellen Zustand zurueck *
|
||||
*--------------------------------------------------------------------*/
|
||||
extern fsm_action_t automat_output(void);
|
||||
|
||||
#endif /* AUTOMAT_H */
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "checker.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
BOOL reset;
|
||||
BOOL muenz_wert;
|
||||
BOOL muenze;
|
||||
BOOL becher;
|
||||
} fsm_input_t;
|
||||
|
||||
typedef struct {
|
||||
fsm_input_t input;
|
||||
fsm_action_t output;
|
||||
} fsm_transaction_t;
|
||||
|
||||
#include "s_transaction_list.h"
|
||||
|
||||
static const int s_transaction_list_size =
|
||||
sizeof(s_transaction_list) / sizeof(*s_transaction_list);
|
||||
|
||||
#define ERROR_STRING_SIZE 1000
|
||||
static char s_error_string[ERROR_STRING_SIZE] = { 0 };
|
||||
|
||||
static void checker_propagate_input(fsm_input_t input);
|
||||
static BOOL checker_compare(fsm_action_t o1, fsm_action_t o2);
|
||||
static void checker_write_error_string(
|
||||
fsm_action_t current, fsm_input_t input,
|
||||
fsm_action_t actual, fsm_action_t expected);
|
||||
static void checker_clear_error_string(void);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* implementation of extern functions ****************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
BOOL checker_check()
|
||||
{
|
||||
fsm_action_t last_out;
|
||||
fsm_action_t new_out;
|
||||
int i;
|
||||
|
||||
automat_reset();
|
||||
|
||||
for (i = 0; i < s_transaction_list_size; i++) {
|
||||
|
||||
last_out = automat_output();
|
||||
|
||||
checker_propagate_input(s_transaction_list[i].input);
|
||||
|
||||
new_out = automat_output();
|
||||
|
||||
if (!checker_compare(new_out, s_transaction_list[i].output)) {
|
||||
checker_write_error_string(last_out, s_transaction_list[i].input,
|
||||
new_out, s_transaction_list[i].output);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
checker_clear_error_string();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * checker_error_string() { return s_error_string; }
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* implementation of static functions ****************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void checker_propagate_input(fsm_input_t input)
|
||||
{
|
||||
if (input.reset) automat_reset();
|
||||
else automat_transition(input.becher, input.muenze, input.muenz_wert);
|
||||
}
|
||||
|
||||
BOOL checker_compare(fsm_action_t o1, fsm_action_t o2)
|
||||
{
|
||||
return o1.display == o2.display &&
|
||||
o1.muenz_rueck == o2.muenz_rueck &&
|
||||
o1.kaffee_los == o2.kaffee_los &&
|
||||
o1.guthaben == o2.guthaben;
|
||||
}
|
||||
|
||||
void checker_write_error_string(
|
||||
fsm_action_t current, fsm_input_t input,
|
||||
fsm_action_t actual, fsm_action_t expected)
|
||||
{
|
||||
if (input.reset) {
|
||||
/* actually wanna use snprintf, but it's defined in c99 */
|
||||
sprintf(s_error_string,
|
||||
"Ausgangsvektor enthält nicht die erwarteten Werte:\n"
|
||||
"Letzter Zustand: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
|
||||
"Eingang: Reset\n"
|
||||
"Ausgang: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
|
||||
"Erwartet: disp:%d rueck:%d los:%d guthaben:%d",
|
||||
current.display, current.muenz_rueck, current.kaffee_los,
|
||||
current.guthaben, current.display_string,
|
||||
actual.display, actual.muenz_rueck, actual.kaffee_los,
|
||||
actual.guthaben, actual.display_string,
|
||||
expected.display, expected.muenz_rueck, expected.kaffee_los,
|
||||
expected.guthaben);
|
||||
} else {
|
||||
/* actually wanna use snprintf, but it's defined in c99 */
|
||||
sprintf(s_error_string,
|
||||
"Ausgangsvektor enthält nicht die erwarteten Werte:\n"
|
||||
"Letzter Zustand: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
|
||||
"Eingang: becher:%d muenze:%d muenz_wert:%d\n"
|
||||
"Ausgang: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
|
||||
"Erwartet: disp:%d rueck:%d los:%d guthaben:%d",
|
||||
current.display, current.muenz_rueck, current.kaffee_los,
|
||||
current.guthaben, current.display_string,
|
||||
input.becher, input.muenze, input.muenz_wert,
|
||||
actual.display, actual.muenz_rueck, actual.kaffee_los,
|
||||
actual.guthaben, actual.display_string,
|
||||
expected.display, expected.muenz_rueck, expected.kaffee_los,
|
||||
expected.guthaben);
|
||||
}
|
||||
}
|
||||
|
||||
void checker_clear_error_string()
|
||||
{
|
||||
s_error_string[0] = '\0';
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __CHECKER_H__
|
||||
#define __CHECKER_H__
|
||||
|
||||
#include "automat.h"
|
||||
|
||||
extern BOOL checker_check(void);
|
||||
extern const char * checker_error_string(void);
|
||||
|
||||
#endif /* __CHECKER_H__ */
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
#include "io.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/* Module intern macros *******************************************************/
|
||||
/******************************************************************************/
|
||||
/* unfortunatly can't write this code as function, because of stack management
|
||||
* => use makro instead */
|
||||
#define DO_PRINTING(output_str) \
|
||||
do { \
|
||||
if (output_str != NULL) { \
|
||||
va_list args; \
|
||||
va_start(args, output_str); \
|
||||
vprintf(output_str, args); \
|
||||
va_end(args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* Implementations ************************************************************/
|
||||
/******************************************************************************/
|
||||
char * io_read_string(char * read_buffer, size_t buffer_size,
|
||||
const char * output_str, ...)
|
||||
{
|
||||
char * ret, * ptr;
|
||||
|
||||
DO_PRINTING(output_str);
|
||||
ret = fgets(read_buffer, buffer_size, stdin);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
/* search for \n */
|
||||
ptr = strchr(read_buffer, '\n');
|
||||
/* if found write \0 instead of \n */
|
||||
if (ptr) *ptr = '\0';
|
||||
/* else buffer is not read completly => clear buffer */
|
||||
else while (getchar() != '\n');
|
||||
|
||||
return read_buffer;
|
||||
}
|
||||
|
||||
int io_read_signed_number(const char * output_str, ...)
|
||||
{
|
||||
int number;
|
||||
|
||||
while (1) {
|
||||
int ret;
|
||||
|
||||
DO_PRINTING(output_str);
|
||||
|
||||
ret = scanf("%d", &number);
|
||||
/* clear buffer */
|
||||
while (getchar() != '\n');
|
||||
|
||||
if (ret == 1) break;
|
||||
else printf("Eingabefehler!!!\n");
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
unsigned int io_read_unsigned_number(const char * output_str, ...)
|
||||
{
|
||||
unsigned int number;
|
||||
|
||||
while (1) {
|
||||
int ret;
|
||||
|
||||
DO_PRINTING(output_str);
|
||||
|
||||
ret = scanf("%u", &number);
|
||||
/* clear buffer */
|
||||
while (getchar() != '\n');
|
||||
|
||||
if (ret == 1) break;
|
||||
else printf("Eingabefehler!!!\n");
|
||||
}
|
||||
return number;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#ifndef __IO_H__
|
||||
#define __IO_H__
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
/* prints the given string (if not NULL) and reads a string from stdin and
|
||||
* removes \n
|
||||
* the functions returns the value of fgets */
|
||||
extern char * io_read_string(char * read_buffer, size_t buffer_size,
|
||||
const char * output_str, ...);
|
||||
|
||||
/* prints the given string (if not NULL) and reads signed number from stdin */
|
||||
extern int io_read_signed_number(const char * output_str, ...);
|
||||
|
||||
/* prints the given string (if not NULL) and reads unsigned number from stdin */
|
||||
extern unsigned int io_read_unsigned_number(const char * output_str, ...);
|
||||
|
||||
#endif /* __IO_H__ */
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include "view.h"
|
||||
#include "automat.h"
|
||||
#include "checker.h"
|
||||
|
||||
void insert_1_euro(void)
|
||||
{
|
||||
view_set_coin(1);
|
||||
automat_transition(view_has_cup(), true, false);
|
||||
}
|
||||
|
||||
void insert_2_euro(void)
|
||||
{
|
||||
view_set_coin(2);
|
||||
automat_transition(view_has_cup(), true, true);
|
||||
}
|
||||
|
||||
void toggle_cup(void)
|
||||
{
|
||||
view_set_coin(0);
|
||||
view_toggle_cup();
|
||||
automat_transition(view_has_cup(), false, false);
|
||||
}
|
||||
|
||||
void check(void)
|
||||
{
|
||||
printf("\n");
|
||||
|
||||
if (checker_check()) {
|
||||
|
||||
printf("Der Zustandsautomat ist correct\n");
|
||||
|
||||
} else {
|
||||
|
||||
printf("%s\n", checker_error_string());
|
||||
|
||||
}
|
||||
|
||||
printf("\nWeiter mit Return ...");
|
||||
while (getchar() != '\n');
|
||||
|
||||
automat_reset();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int finished = 0;
|
||||
|
||||
automat_reset();
|
||||
view_reset();
|
||||
|
||||
while (!finished) {
|
||||
view_menu_t selection;
|
||||
|
||||
view_show(automat_output());
|
||||
selection = view_menu();
|
||||
|
||||
switch (selection) {
|
||||
case VIEW_1_EURO: insert_1_euro(); break;
|
||||
case VIEW_2_EURO: insert_2_euro(); break;
|
||||
case VIEW_CUP: toggle_cup(); break;
|
||||
case VIEW_RESET: automat_reset(); view_reset(); break;
|
||||
case VIEW_CHECK: check(); break;
|
||||
case VIEW_EXIT: finished = 1; break;
|
||||
case VIEW_INVALID: break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+100002
File diff suppressed because it is too large
Load Diff
+115
@@ -0,0 +1,115 @@
|
||||
#include "view.h"
|
||||
#include "io.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define S_MACHINE_HEAD \
|
||||
" /-----------------------------------\\\n" \
|
||||
" | %33s |\n" \
|
||||
" \\-----------------------------------/\n" \
|
||||
" \n" \
|
||||
" /~~~~~~~~~~~/| \n" \
|
||||
" / /#########/ / |\n" \
|
||||
" / /_________/ / |\n" \
|
||||
" =============== /||\n" \
|
||||
" | %03d EUR |/ ||\n" \
|
||||
" |_____________|/ ||\n" \
|
||||
" | \\___..___/ ||\n" \
|
||||
" | || ||\n"
|
||||
|
||||
|
||||
#define S_MACHINE_NO_COFFEE \
|
||||
" | ||\n" \
|
||||
" | ||\n" \
|
||||
" | ||\n"
|
||||
|
||||
#define S_MACHINE_COFFEE \
|
||||
" | ) ( ||\n" \
|
||||
" | ( ) ) ||\n" \
|
||||
" | ) ( ( ||\n" \
|
||||
|
||||
#define S_MACHINE_NO_CUP \
|
||||
" _________ | ||\n" \
|
||||
" .-'---------| |_______________||\n" \
|
||||
" ( C|/\\/\\/\\/\\/| | / |\n" \
|
||||
" '-./\\/\\/\\/\\/| _|_ _ _ _ _ _ _/ |\n" \
|
||||
" '_________' | | / \n" \
|
||||
" '-------' |_______________|/ \n" \
|
||||
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n"
|
||||
|
||||
#define S_MACHINE_CUP \
|
||||
" | _________ ||\n" \
|
||||
" .-'---------|___||\n" \
|
||||
" ( C|/\\/\\/\\/\\/| / |\n" \
|
||||
" _'-./\\/\\/\\/\\/|_/ |\n" \
|
||||
" | '_________' | / \n" \
|
||||
" |____'-------'__|/ \n" \
|
||||
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n"
|
||||
|
||||
#define S_MACHINE_NO_COIN_RETURN "\n"
|
||||
|
||||
#define S_MACHINE_INVALID_COIN_RETURN \
|
||||
" -> keine Muenze verfuegbar !!!\n"
|
||||
|
||||
#define S_MACHINE_COIN_RETURN \
|
||||
" -> %0d Euro zurueck\n"
|
||||
|
||||
|
||||
/* machine status variables */
|
||||
static int s_has_cup = 0;
|
||||
static int s_coin_value = 0;
|
||||
|
||||
/* function implementations */
|
||||
void view_show(fsm_action_t out_vector)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 100; i++) printf("\n");
|
||||
|
||||
printf(S_MACHINE_HEAD, out_vector.display_string, out_vector.guthaben);
|
||||
|
||||
if (out_vector.kaffee_los) printf(S_MACHINE_COFFEE);
|
||||
else printf(S_MACHINE_NO_COFFEE);
|
||||
|
||||
if (s_has_cup) printf(S_MACHINE_CUP);
|
||||
else printf(S_MACHINE_NO_CUP);
|
||||
|
||||
if (out_vector.muenz_rueck) {
|
||||
if (s_coin_value) printf(S_MACHINE_COIN_RETURN, s_coin_value);
|
||||
else printf(S_MACHINE_INVALID_COIN_RETURN);
|
||||
} else {
|
||||
printf(S_MACHINE_NO_COIN_RETURN);
|
||||
}
|
||||
}
|
||||
|
||||
view_menu_t view_menu()
|
||||
{
|
||||
int read = io_read_signed_number(
|
||||
"\n"
|
||||
" 0) Einwurf 1 Euro\n"
|
||||
" 1) Einwurf 2 Euro\n"
|
||||
" 2) Becher verstellen\n"
|
||||
" 3) Reset\n"
|
||||
" 4) Automatischer Testlauf\n"
|
||||
" 5) Programm beenden\n"
|
||||
"\n"
|
||||
" Auswahl: ");
|
||||
|
||||
switch (read) {
|
||||
case 0: return VIEW_1_EURO;
|
||||
case 1: return VIEW_2_EURO;
|
||||
case 2: return VIEW_CUP;
|
||||
case 3: return VIEW_RESET;
|
||||
case 4: return VIEW_CHECK;
|
||||
case 5: return VIEW_EXIT;
|
||||
default: return VIEW_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void view_toggle_cup() { s_has_cup = s_has_cup ? 0 : 1; }
|
||||
int view_has_cup() { return s_has_cup; }
|
||||
void view_set_coin(int value) { s_coin_value = value; }
|
||||
|
||||
void view_reset()
|
||||
{
|
||||
s_has_cup = 0;
|
||||
s_coin_value = 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "automat.h"
|
||||
|
||||
typedef enum { VIEW_1_EURO, VIEW_2_EURO, VIEW_CUP, VIEW_RESET, VIEW_CHECK, VIEW_EXIT, VIEW_INVALID } view_menu_t;
|
||||
|
||||
extern void view_show(fsm_action_t out_vector);
|
||||
|
||||
extern view_menu_t view_menu(void);
|
||||
|
||||
extern void view_toggle_cup(void);
|
||||
extern int view_has_cup(void);
|
||||
|
||||
extern void view_set_coin(int value);
|
||||
|
||||
extern void view_reset(void);
|
||||
Reference in New Issue
Block a user