master > master: code go - interactive mode eingerichtet

This commit is contained in:
RD 2021-11-03 16:05:46 +01:00
parent 53978d584b
commit 324b8d2fcd
8 changed files with 409 additions and 67 deletions

View File

@ -8,15 +8,14 @@ import (
"ads/internal/core/logging" "ads/internal/core/logging"
"ads/internal/menus" "ads/internal/menus"
"ads/internal/setup" "ads/internal/setup"
"reflect"
// algorithm_search_binary "ads/internal/algorithms/search/binary" algorithm_search_binary "ads/internal/algorithms/search/binary"
// algorithm_search_interpol "ads/internal/algorithms/search/interpol" algorithm_search_interpol "ads/internal/algorithms/search/interpol"
// algorithm_search_ith_element "ads/internal/algorithms/search/ith_element" algorithm_search_ith_element "ads/internal/algorithms/search/ith_element"
// algorithm_search_jump "ads/internal/algorithms/search/jump" algorithm_search_jump "ads/internal/algorithms/search/jump"
// algorithm_search_poison "ads/internal/algorithms/search/poison" algorithm_search_poison "ads/internal/algorithms/search/poison"
algorithm_search_sequential "ads/internal/algorithms/search/sequential" algorithm_search_sequential "ads/internal/algorithms/search/sequential"
// algorithm_sum_maxsubsum "ads/internal/algorithms/sum/maxsubsum" algorithm_sum_maxsubsum "ads/internal/algorithms/sum/maxsubsum"
) )
/* ---------------------------------------------------------------- * /* ---------------------------------------------------------------- *
@ -43,6 +42,7 @@ var menuMain = menus.Menu{
}, },
Options: []menus.MenuOption{ Options: []menus.MenuOption{
{Label: "Version des Programms anzeigen", Action: actionShowVersion}, {Label: "Version des Programms anzeigen", Action: actionShowVersion},
{Label: "Programm auf config Datei ausführen.", Action: actionRunOnConfig},
{Label: "Suchalgorithmen", Submenu: &menuSearchAlgorithms}, {Label: "Suchalgorithmen", Submenu: &menuSearchAlgorithms},
{Label: "Summenalgorithmen", Submenu: &menuSumAlgorithms}, {Label: "Summenalgorithmen", Submenu: &menuSumAlgorithms},
}, },
@ -56,14 +56,14 @@ var menuSearchAlgorithms = menus.Menu{
"Algorithmus wählen", "Algorithmus wählen",
}, },
Options: []menus.MenuOption{ Options: []menus.MenuOption{
{Label: "Binärsuchalgorithmus"}, {Label: "Binärsuchalgorithmus", Action: actionAlgorithmSearchBinary},
{Label: "Interpolationsalgorithmus"}, {Label: "Interpolationsalgorithmus", Action: actionAlgorithmSearchInterpolation},
{Label: "Suche i. kleinstes Element"}, {Label: "Suche i. kleinstes Element", Action: actionAlgorithmSearchIthElement},
{Label: "Suche i. kleinstes Element", SubLabel: "D & C"}, {Label: "Suche i. kleinstes Element", SubLabel: "D & C", Action: actionAlgorithmSearchIthElementDc},
{Label: "Sprungsuche", SubLabel: "linear"}, {Label: "Sprungsuche", SubLabel: "linear", Action: actionAlgorithmSearchJump},
{Label: "Sprungsuche", SubLabel: "exponentiell"}, {Label: "Sprungsuche", SubLabel: "exponentiell", Action: actionAlgorithmSearchJumpExp},
{Label: "Giftsuche"}, {Label: "Giftsuche", Action: actionAlgorithmSearchPoison},
{Label: "Giftsuche", SubLabel: "optimiert"}, {Label: "Giftsuche", SubLabel: "optimiert", Action: actionAlgorithmSearchPoisonFast},
{Label: "Sequentiellsuchalgorithmus", Action: actionAlgorithmSearchSequential}, {Label: "Sequentiellsuchalgorithmus", Action: actionAlgorithmSearchSequential},
}, },
DefaultOption: -1, DefaultOption: -1,
@ -76,8 +76,8 @@ var menuSumAlgorithms = menus.Menu{
"Algorithmus wählen", "Algorithmus wählen",
}, },
Options: []menus.MenuOption{ Options: []menus.MenuOption{
{Label: "Maximale Teilsumme", SubLabel: "brute force"}, {Label: "Maximale Teilsumme", SubLabel: "brute force", Action: actionAlgorithmSumMaxsub},
{Label: "Maximale Teilsumme", SubLabel: "D & C"}, {Label: "Maximale Teilsumme", SubLabel: "D & C", Action: actionAlgorithmSumMaxsubDc},
}, },
DefaultOption: -1, DefaultOption: -1,
} }
@ -86,23 +86,259 @@ var menuSumAlgorithms = menus.Menu{
* ACTIONS - basic * ACTIONS - basic
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
func actionShowVersion() error { func actionShowVersion() (bool, error) {
logging.LogInfo("Version des Programms") logging.LogInfo("Version des Programms")
Version() Version()
return nil return false, nil
} }
/* ---------------------------------------------------------------- * /* ---------------------------------------------------------------- *
* ACTIONS - Algorithmen * ACTIONS - Algorithmen
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
// TODO func actionRunOnConfig() (bool, error) {
func actionAlgorithmSearchSequential() error { path, cancel, err := logging.Prompt("Pfad zur Configdatei bitte eingeben:")
input_L := []int{45, 67} if cancel {
input_x := 6 err = nil
menus.PromptValue("L", "Liste von Integers", "z.B. \033[1m5 73 42\033[0m", reflect.TypeOf([]int{})) } else if err == nil {
err = RunNonInteractive(path)
}
return cancel, err
}
func actionAlgorithmSearchBinary() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{
"muss aufsteigend sortiert sein",
})
if cancel || err != nil {
return cancel, err
}
input_x, cancel, err := PromptInputInteger("x", "Suchwert", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_binary.FancyBinarySearch(input_L, input_x)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchInterpolation() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{
"muss aufsteigend sortiert sein",
"sollte (idealerweise) nicht uniform verteilt sein",
})
if cancel || err != nil {
return cancel, err
}
input_x, cancel, err := PromptInputInteger("x", "Suchwert", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_interpol.FancyInterpolationSearch(input_L, input_x, 0, len(input_L)-1)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchIthElement() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
input_i, cancel, err := PromptInputInteger("i", "Suchindex in sortierter Liste", []string{
"sollte zw. 1 und len(L) liegen",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_ith_element.FancyFindIthSmallest(input_L, input_i)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchIthElementDc() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
input_i, cancel, err := PromptInputInteger("i", "Suchindex in sortierter Liste", []string{
"sollte zw. 1 und len(L) liegen",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_ith_element.FancyFindIthSmallestDC(input_L, input_i)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchJump() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{
"muss aufsteigend sortiert sein",
"sollte (idealerweise) nicht uniform verteilt sein",
"sollte (idealerweise) keine Duplikate enthalten",
})
if cancel || err != nil {
return cancel, err
}
input_x, cancel, err := PromptInputInteger("x", "Suchwert", []string{})
if cancel || err != nil {
return cancel, err
}
input_m, cancel, err := PromptInputInteger("m", "Sprunggröße", []string{
"sollte >= 2 sein",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_jump.FancyJumpSearchLinear(input_L, input_x, input_m)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchJumpExp() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{
"muss aufsteigend sortiert sein",
"sollte (idealerweise) nicht uniform verteilt sein",
"sollte (idealerweise) keine Duplikate enthalten",
})
if cancel || err != nil {
return cancel, err
}
input_x, cancel, err := PromptInputInteger("x", "Suchwert", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_jump.FancyJumpSearchExponentiell(input_L, input_x)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchPoison() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{
"muss genau eine 1 enthalten",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_poison.FancyFindPoison(input_L)
logging.Prompt("hallo")
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchPoisonFast() (bool, error) {
input_L, cancel, err := PromptInputListOfZeroOnes("L", "Liste von Getränken", []string{
"muss genau eine 1 enthalten",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_search_poison.FancyFindPoisonFast(input_L)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchSequential() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
input_x, cancel, err := PromptInputInteger("x", "Suchwert", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank() setup.DisplayStartOfCaseBlank()
algorithm_search_sequential.FancySequentialSearch(input_L, input_x) algorithm_search_sequential.FancySequentialSearch(input_L, input_x)
setup.DisplayEndOfCase() setup.DisplayEndOfCase()
return nil return cancel, nil
}
func actionAlgorithmSumMaxsub() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_sum_maxsubsum.FancyMaxSubSum(input_L)
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSumMaxsubDc() (bool, error) {
input_L, cancel, err := PromptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
algorithm_sum_maxsubsum.FancyMaxSubSumDC(input_L)
setup.DisplayEndOfCase()
return cancel, nil
}
/* ---------------------------------------------------------------- *
* CUSTOM PROMPTS für besondere Inputs
* ---------------------------------------------------------------- */
func PromptInputInteger(name string, descr string, requirements []string) (int, bool, error) {
type responseType struct {
Response int `yaml:"response"`
}
var response = responseType{}
var query = menus.PromptValueQuery{
Description: descr,
Name: name,
Type: "Integer",
Requirements: &requirements,
Response: &response,
}
cancel, err := query.Prompt()
return response.Response, cancel, err
}
func PromptInputListOfInt(name string, descr string, requirements []string) ([]int, bool, error) {
type responseType struct {
Response []int `yaml:"response"`
}
var response = responseType{}
var query = menus.PromptValueQuery{
Description: descr,
Name: name,
Type: "Integerliste",
ValidExamples: &[]string{
"[1, 2, 7, 8, 5]",
"[1000, 0, 4]",
},
Requirements: &requirements,
Response: &response,
}
cancel, err := query.Prompt()
return response.Response, cancel, err
}
func PromptInputListOfZeroOnes(name string, descr string, requirements []string) ([]int, bool, error) {
type responseType struct {
Response []int `yaml:"response"`
}
var response = responseType{}
var query = menus.PromptValueQuery{
Description: descr,
Name: name,
Type: "Liste von 0er und 1er",
ValidExamples: &[]string{
"[0, 0, 0, 1, 0]",
"[1, 0, 1, 1]",
},
Requirements: &requirements,
Response: &response,
}
cancel, err := query.Prompt()
return response.Response, cancel, err
} }

View File

@ -24,12 +24,10 @@ import (
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
// Liest Config Datei ein und führt Algorithmen auf Fälle durch // Liest Config Datei ein und führt Algorithmen auf Fälle durch
func RunNoninteractive(path string) error { func RunNonInteractive(path string) error {
var err error var err error
var err_case error var err_case error
logging.LogPlain(setup.Logo())
// extrahiere user config // extrahiere user config
config := setup.NewUserConfig() config := setup.NewUserConfig()
err = setup.GetUserConfig(path, &config) err = setup.GetUserConfig(path, &config)
@ -37,6 +35,8 @@ func RunNoninteractive(path string) error {
return err return err
} }
logging.LogPlain(setup.Logo())
// Fälle extrahieren // Fälle extrahieren
cases := []types.UserConfigCase{} cases := []types.UserConfigCase{}
if config.Parts != nil && config.Parts.Cases != nil { if config.Parts != nil && config.Parts.Cases != nil {

View File

@ -6,10 +6,13 @@ package menus
import ( import (
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
"ads/internal/core/logging" "ads/internal/core/logging"
"gopkg.in/yaml.v3"
) )
/* ---------------------------------------------------------------- * /* ---------------------------------------------------------------- *
@ -22,6 +25,8 @@ func (menu Menu) ShowMenu() (bool, error) {
index int index int
meta bool meta bool
quit bool quit bool
cancel bool
err error
) )
var promptMessages []string var promptMessages []string
var options [][2]string var options [][2]string
@ -79,12 +84,18 @@ func (menu Menu) ShowMenu() (bool, error) {
opt := menu.Options[index] opt := menu.Options[index]
// Entweder Untermenü öffnen oder Action ausführen // Entweder Untermenü öffnen oder Action ausführen
if opt.Submenu != nil { if opt.Submenu != nil {
quit, _ = opt.Submenu.ShowMenu() quit, err = opt.Submenu.ShowMenu()
if quit { if quit {
return true, nil return true, err
} }
} else if opt.Action != nil { } else if opt.Action != nil {
opt.Action() cancel, err = opt.Action()
if err != nil {
logging.LogError(err)
}
if cancel {
continue
}
quit := logging.PromptAnyKeyToContinue() quit := logging.PromptAnyKeyToContinue()
// Falls während der Action der User Meta+D klickt, -> quit: // Falls während der Action der User Meta+D klickt, -> quit:
if quit { if quit {
@ -100,3 +111,69 @@ func (menu Menu) ShowMenu() (bool, error) {
} }
} }
} }
/* ---------------------------------------------------------------- *
* METHOD prompt values
* ---------------------------------------------------------------- */
func (query *PromptValueQuery) Prompt() (bool, error) {
var lines = []interface{}{}
var responsePtr = query.Response
var (
line string
cancel bool
err error
)
// prüfen, dass response ein Ptr auf eine Struct ist:
if !(reflect.ValueOf(responsePtr).Kind() == reflect.Ptr) || !(reflect.ValueOf(responsePtr).Elem().Kind() == reflect.Struct) {
panic("Input muss ein Pointer auf einen struct sein")
}
// prompt message vorbereiten:
lines = append(lines, fmt.Sprintf("%s, \033[1;3m%s\033[0m, als \033[1m%s\033[0m bitte eingeben.", query.Description, query.Name, query.Type))
if query.ValidExamples != nil && len(*query.ValidExamples) > 0 {
if len(*query.ValidExamples) == 1 {
example := (*query.ValidExamples)[0]
lines = append(lines, fmt.Sprintf(" \033[3;4mBeispiel von Input im gültigen Format:\033[0m \033[2m%s\033[0m", example))
} else {
lines = append(lines, fmt.Sprintf(" \033[3;4mBeispiele von Inputs im gültigen Format:\033[0m"))
for _, example := range *query.ValidExamples {
lines = append(lines, fmt.Sprintf(" - \033[2m%s\033[0m", example))
}
lines = append(lines, fmt.Sprintf(" - \033[2;3metc.\033[0m"))
}
}
if query.Requirements != nil && len(*query.Requirements) > 0 {
if len(*query.Requirements) == 1 {
requirement := (*query.Requirements)[0]
lines = append(lines, fmt.Sprintf(" \033[3;4mInput muss erfüllen:\033[0m \033[2m%s\033[0m", requirement))
} else {
lines = append(lines, fmt.Sprintf(" \033[3;4mInput muss erfüllen:\033[0m"))
for _, requirement := range *query.Requirements {
lines = append(lines, fmt.Sprintf(" - \033[2m%s\033[0m", requirement))
}
}
}
// prompt Eingabe eines Werts:
for {
line, cancel, err = logging.Prompt(lines...)
if cancel {
return true, nil
}
if err != nil {
logging.LogError(err, "")
continue
}
line = fmt.Sprintf("\"response\": %s", line)
err = yaml.Unmarshal([]byte(line), query.Response)
if err != nil {
logging.LogError(err, "")
continue
}
break
}
return cancel, err
}

View File

@ -6,7 +6,6 @@ package menus
import ( import (
"fmt" "fmt"
"reflect"
"ads/internal/core/logging" "ads/internal/core/logging"
"ads/internal/core/utils" "ads/internal/core/utils"
@ -76,16 +75,3 @@ func PromptListOfOptions(messages []string, options [][2]string, breaks []int, d
} }
return choice, false return choice, false
} }
/* ---------------------------------------------------------------- *
* METHOD prompt values
* ---------------------------------------------------------------- */
func PromptValue(varname string, typename string, example string, t reflect.Type) (bool, error) {
_, cancel, err := logging.Prompt(
fmt.Sprintf("Bitte den Wert von \033[1m%s\033[0m als \033[1m%s\033[0m eingeben.", varname, typename),
example,
)
// TODO: input parsen
return cancel, err
}

View File

@ -14,7 +14,7 @@ type MenuOption struct {
Label string Label string
SubLabel string SubLabel string
Submenu *Menu Submenu *Menu
Action func() error // NOTE: in go, this is automatically a pointer type Action func() (bool, error) // NOTE: in go, this is automatically a pointer type
} }
type Menu struct { type Menu struct {
@ -24,3 +24,34 @@ type Menu struct {
Options []MenuOption Options []MenuOption
DefaultOption int DefaultOption int
} }
/* ---------------------------------------------------------------- *
* TYPES - prompt
* ---------------------------------------------------------------- */
/*
Usage
- Name: Variablenname
- Description: Kurze Beschreibung der Variablen
- Type: Beschreiben des erwarteten Types der Variablen.
- Requirements: Liste von Anforderungen.
- Response: Ptr zur Struct, d. h. &responseType{}, wobei responseType eine struct der folgenden Form ist:
type responseType struct { Response #### `yaml:"response"` }
wobei #### = ein Typ
*/
type PromptValueQuery struct {
Name string
Description string
Type string
ValidExamples *[]string
Requirements *[]string
// Response muss ein Ptr auf eine Struct sein:
Response interface{}
}

View File

@ -39,6 +39,12 @@ var optionsDebug = argparse.Options{
Default: false, Default: false,
} }
var optionsInteractive = argparse.Options{
Help: "Startet die App im interaktiven Modus.",
Required: false,
Default: false,
}
var optionsColour = argparse.Options{ var optionsColour = argparse.Options{
Help: "Ob Logging färblich angezeigt wird.", Help: "Ob Logging färblich angezeigt wird.",
Required: false, Required: false,
@ -60,15 +66,15 @@ func ParseCli(args []string) (*types.CliArguments, error) {
var err error var err error
Parser = argparse.NewParser("cli parser", "Liest Optionen + Flags von Kommandozeile.") Parser = argparse.NewParser("cli parser", "Liest Optionen + Flags von Kommandozeile.")
arguments := types.CliArguments{ arguments := types.CliArguments{
ModeHelp: Parser.NewCommand("help", ""), ModeHelp: Parser.NewCommand("help", ""),
ModeVersion: Parser.NewCommand("version", "Ruft Endpunkt auf, der die Version anzeigt."), ModeVersion: Parser.NewCommand("version", "Ruft Endpunkt auf, der die Version anzeigt."),
ModeRun: Parser.NewCommand("run", "Ruft Endpunkt auf, der die Algorithmen laufen lässt."), ModeRun: Parser.NewCommand("run", "Ruft Endpunkt auf, der die Algorithmen laufen lässt."),
ModeInteractive: Parser.NewCommand("it", "Startet die App im interaktiven Modus."), Quiet: Parser.Flag("q", "quiet", &optionsQuiet),
Quiet: Parser.Flag("q", "quiet", &optionsQuiet), Debug: Parser.Flag("", "debug", &optionsDebug),
Debug: Parser.Flag("", "debug", &optionsDebug), Interactive: Parser.Flag("", "it", &optionsInteractive),
Checks: Parser.String("", "checks", &optionsChecks), Checks: Parser.String("", "checks", &optionsChecks),
Colour: Parser.String("", "colour", &optionsColour), Colour: Parser.String("", "colour", &optionsColour),
ConfigFile: Parser.String("", "config", &optionsConfigFile), ConfigFile: Parser.String("", "config", &optionsConfigFile),
} }
err = Parser.Parse(args) err = Parser.Parse(args)
return &arguments, err return &arguments, err

View File

@ -15,15 +15,15 @@ import (
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
type CliArguments struct { type CliArguments struct {
ModeHelp *argparse.Command ModeHelp *argparse.Command
ModeVersion *argparse.Command ModeVersion *argparse.Command
ModeRun *argparse.Command ModeRun *argparse.Command
ModeInteractive *argparse.Command Quiet *bool
Quiet *bool Debug *bool
Debug *bool Interactive *bool
Checks *string Checks *string
Colour *string Colour *string
ConfigFile *string ConfigFile *string
} }
/* ---------------------------------------------------------------- * /* ---------------------------------------------------------------- *
@ -38,6 +38,10 @@ func (arguments CliArguments) DebugModeOn() bool {
return *arguments.Debug return *arguments.Debug
} }
func (arguments CliArguments) InteractiveMode() bool {
return *arguments.Interactive
}
func (arguments CliArguments) ShowChecks() bool { func (arguments CliArguments) ShowChecks() bool {
return !utils.IsFalse(*arguments.Checks) return !utils.IsFalse(*arguments.Checks)
} }

View File

@ -66,9 +66,11 @@ func main() {
if arguments.ModeVersion.Happened() { if arguments.ModeVersion.Happened() {
endpoints.Version() endpoints.Version()
} else if arguments.ModeRun.Happened() { } else if arguments.ModeRun.Happened() {
err = endpoints.RunNoninteractive(arguments.GetConfigFile()) if arguments.InteractiveMode() {
} else if arguments.ModeInteractive.Happened() { err = endpoints.RunInteractive()
err = endpoints.RunInteractive() } else {
err = endpoints.RunNonInteractive(arguments.GetConfigFile())
}
} else { // } else if arguments.Help.Happened() { } else { // } else if arguments.Help.Happened() {
endpoints.Help() endpoints.Help()
} }