Compare commits

..

No commits in common. "master" and "4c13c5ff4751483ca61524d7b4fe1f6b0308b880" have entirely different histories.

128 changed files with 38 additions and 8221 deletions

12
.env
View File

@ -1,12 +0,0 @@
# General
NAME_OF_APP="ads"
REQUIREMENTS_PY="code/python/requirements"
REQUIREMENTS_GO="code/golang/requirements"
TEST_TIMEOUT="10s"
# Logging
CONSOLE_OUT=/dev/stdout
CONSOLE_ERR=/dev/stderr
CONSOLE_VERBOSE=/dev/null
CONSOLE_PATH_LOGS=logs
CONSOLE_FILENAME_LOGS_DEBUG=debug.log

10
.gitignore vendored
View File

@ -5,7 +5,6 @@
# MAIN FOLDER # MAIN FOLDER
################################################################ ################################################################
!/.env
!/README.md !/README.md
################################################################ ################################################################
@ -20,16 +19,7 @@
!/protocol/README.md !/protocol/README.md
!/protocol/woche*.md !/protocol/woche*.md
!/scripts
!/scripts/*.sh
!/code !/code
!/code/python
!/code/golang
!/code/config.yml
!/dist
!/dist/VERSION
################################################################ ################################################################
# ARTEFACTS # ARTEFACTS

View File

@ -1,36 +1,12 @@
# Algorithmen und Datenstrukturen I, WiSe 2021-22 # # Algorithmen und Datenstrukturen I, WiSe 2021-22 #
Diese Repository ist für die Seminargruppe **j/l** am Freitag um 13:1514:45 Diese Repository ist für die Übungsgruppe am Freitag um 13:1514:45.
im Raum SG 3-14 bzw. SG 4-10 (alternierend).
**HINWEIS 1:** In diesem Repository werden keine Personen bezogenen Daten der Studierenden gespeichert. **HINWEIS:** In diesem Repository werden keine persönlichen Daten gespeichert.
**HINWEIS 2:** Es besteht absolut gar keine Pflicht, die Materialien in diesem Repo zu verwenden. Diese sind lediglich zusätzliche Hilfsmittel. **Im Zweifelsfalls** sollte man sich immer an den Definitionen und Auslegungen in der VL orientieren.
In diesem Repository findet man: In diesem Repository findet man:
- Protokolle der Seminargruppe [hier](./protocol). - Protokolle der Übungsgruppe [hier](./protocol).
- Notizen [hier](./notes). - Notizen [hier](./notes).
- Symbolverzeichnis unter [notes/glossar.md](./notes/glossar.md). - Symbolverzeichnis unter [notes/glossar.md](./notes/glossar.md).
- Referenzen unter [notes/quellen.md](./notes/quellen.md). - Referenzen unter [notes/quellen.md](./notes/quellen.md).
## Leistungen während des Semesters ##
- 12 x freiwillige Serien (unkorrigiert: Lösungen werden per Moodle veröffentlicht)
- 6 x Pflichtserien (jeweils 2 Wochen Bearbeitungsdauer)
- wöchentlich werden im den Lernstunden _andere_ Aufgabenblätter im Raum angezeigt und von Studierenden bearbeitet.
## Vorleistungen ##
- ≥ 50% der Punkte aus den 6 Pflichtserien sollen geschafft werden.
- _nur digitale Abgabe_!
## Code ##
In den Unterordnern
[`code/golang`](./code/golang)
und
[`code/python`](./code/python)
kann man Codeprojekte finden.
Dort kann man konkrete Implementierung der Algorithmen ansehen
und ggf. auch auf echte Daten austesten.

View File

@ -1,95 +0,0 @@
info:
title: AlgoDat I, WiSe 2021/22
description: Testfälle für Algorithmen.
parts:
## Hier kann man beliebig viele Testfälle einfügen mit beliebigen Eingaben (solange gültig!)
cases:
- command: 'algorithm-sum-maxsub'
inputs:
L: [5, -6, 4, 2, -5, 7, -2, -7, 3, 5]
- command: 'algorithm-sum-maxsub-dc'
inputs:
L: [5, -6, 4, 2, -5, 7, -2, -7, 3, 5]
- command: 'algorithm-search-sequential'
inputs:
L: [1, 3, 5, 7, 11, 13, 17, 19, 23]
x: 13
- command: 'algorithm-search-binary'
inputs:
L: [1, 3, 5, 7, 11, 13, 17, 19, 23]
x: 13
- command: 'algorithm-search-interpolation'
inputs:
L: [1, 3, 5, 7, 11, 13, 17, 19, 23]
x: 13
- command: 'algorithm-search-jump'
inputs:
L: [1, 3, 5, 7, 11, 13, 16, 17, 23, 33, 34, 35]
x: 17
m: 3
- command: 'algorithm-search-jump-exp'
inputs:
L: [1, 3, 5, 7, 11, 13, 16, 17, 23, 33, 34, 35]
x: 17
m: 3
## Freiwilliges ÜB 2, Aufgabe 4, Beispiel
- command: 'algorithm-search-poison'
description: 'Freiwilliges ÜB2, A4, Beispiel'
inputs: &ref_inputs_ueb2_4
L: [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
- command: 'algorithm-search-poison-fast'
description: 'Freiwilliges ÜB2, A4, Beispiel'
inputs: *ref_inputs_ueb2_4
## Freiwilliges ÜB 2, Aufgabe 5
- command: 'algorithm-search-binary'
description: 'Freiwilliges ÜB2, A5a'
inputs: &ref_inputs_ueb2_5
L: [4, 11, 22, 23, 25, 27, 29, 36, 41, 52, 64, 76, 82, 86, 94, 96, 102, 117, 123, 147, 188, 211, 216, 222, 224, 226, 233, 239, 255, 263, 277, 289]
x: 114
- command: 'algorithm-search-jump'
description: 'Freiwilliges ÜB2, A5b'
inputs:
<<: *ref_inputs_ueb2_5
m: 5
- command: 'algorithm-search-interpolation'
description: 'Freiwilliges ÜB2, A5c'
inputs: *ref_inputs_ueb2_5
## Freiwilliges ÜB 2, Aufgabe 6
- command: 'algorithm-search-ith-element'
description: 'Freiwilliges ÜB2, A6a'
inputs: &ref_inputs_ueb2_6a
L: [16, 15, 9, 5, 1, 10, 7, 14, 19, 8]
i: 2
- command: 'algorithm-search-ith-element-dc'
description: 'Freiwilliges ÜB2, A6a (D&C)'
inputs: *ref_inputs_ueb2_6a
- command: 'algorithm-search-ith-element'
description: 'Freiwilliges ÜB2, A6b'
inputs: &ref_inputs_ueb2_6b
<<: *ref_inputs_ueb2_6a
i: 5
- command: 'algorithm-search-ith-element-dc'
description: 'Freiwilliges ÜB2, A6b (D&C)'
inputs: *ref_inputs_ueb2_6b
# SEMINARBLATT 3
- command: 'algorithm-search-binary'
description: 'Seminarblatt Woche 3, Aufgabe 1'
inputs: &ref_inputs_sem3_1
L: [7, 12, 29, 33, 40, 44, 45, 55, 64, 68, 78, 81, 84, 89, 95, 117, 120, 124, 133, 148, 152, 157, 174, 209, 219, 226, 226, 237, 241, 273, 277, 282]
x: 101
- command: 'algorithm-search-jump'
description: 'Seminarblatt Woche 3, Aufgabe 1'
inputs:
<<: *ref_inputs_sem3_1
m: 5
- command: 'algorithm-search-interpolation'
description: 'Seminarblatt Woche 3, Aufgabe 1'
inputs: *ref_inputs_sem3_1
- command: 'algorithm-stacks-next-greater-element'
description: 'Seminarblatt Woche 4, Aufgabe 1'
inputs:
L: [4, 6, 3, 16]
- command: 'algorithm-stacks-next-greater-element'
description: 'Seminarblatt Woche 4, Aufgabe 1 mit anderen Daten'
inputs:
L: [20, 10, 10, 2, 1, 5, 30, 3, 16]

View File

@ -1,33 +0,0 @@
*
!/.gitignore
################################################################
# MAIN FOLDER
################################################################
!/Makefile
!/README.md
!/requirements
################################################################
# PROJECT FILES
################################################################
!/assets
!/assets/VERSION
!/assets/LOGO
!/assets/config.yml
!/pkg
!/internal
!/*/**/
!/*/**/*.go
!/go.mod
!/go.sum
################################################################
# ARTEFACTS
################################################################
/**/.DS_Store
/**/__archive__*

View File

@ -1,27 +0,0 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# LOCAL ARGUMENTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PATH_TO_CONFIG:=../config.yml#<- kann durch Pfad zur eigenen yml-Datei ersetzt werden
PATH_TO_ARTEFACT:=../../dist/ads#<- kann beliebiger Pfad sein
COLOUR:=true
## für Windows weichen Defaultsettings leicht ab:
ifeq ($(OS),Windows_NT)
PATH_TO_ARTEFACT:=${PATH_TO_ARTEFACT}.exe
COLOUR:=false# <- man kann als 'true' setzen, aber in Windows funktioniert es möglicherweise nicht
endif
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
setup:
go mod download
build:
go build -o ${PATH_TO_ARTEFACT} main.go
run: # non-interactive mode mit config-datei
${PATH_TO_ARTEFACT} run --debug --colour ${COLOUR} --config "${PATH_TO_CONFIG}"
run-it: # interactive mode
${PATH_TO_ARTEFACT} run --it --debug --colour ${COLOUR}
# Do everything:
all: setup build run
all-it: setup build run-it

View File

@ -1,88 +0,0 @@
# ADS - Golang-Projekt #
**Golang** ist eine relativ moderne Programmiersprache, die immer populärer wird und viele Vorteile anbietet.
Dieses Projekt ist erneut kein nötiger Bestandteil des Kurses,
sondern nur für Wissbegierige gedacht.
Zunächst bietet sich an, sich die Algorithmen im Unterordner [`pkg/algorithms`](./pkg/algorithms) anzuschauen,
z.&nbsp;B. [`pkg/algorithms/search/binary/binary.go`](./pkg/algorithms/search/binary/binary.go) für den Binärsuchalgorithmus,
ohne irgendetwas installieren zu müssen.
**HINWEIS 1:** _Bei meiner Implementierung kann es zu leichten Abweichungen kommen. Bitte **stets** an dem Material im VL-Skript sich orientieren. Der Hauptzweck der Code-Projekte besteht darin, dass Wissbegierige die Algorithmen konkret ausprobieren können. Alle theoretischen Aspekte werden jedoch im Skript und in den Übungen ausführlicher erklärt._
Den Code kann man auch durch die u.&nbsp;s. Anweisungen selber austesten.
**HINWEIS 2:** _Während hier die Anweisungen ausführlich sind und klappen sollten,
bitte nur auf eigener Gewähr diesen Code benutzen._
## Systemvoraussetzungen ##
- **Bash**. Dies kommt mit OSX (Terminal) und Linux. Für Windows-User braucht man [git-for-windows](https://gitforwindows.org) zu installieren, was auch bash mit installiert.
- [**go**](https://golang.org/dl/) Version **1.17.x**. (Man kann bestimmt bei späteren Releases höhere Versionen benutzen. Man muss lediglich dann in [`go.mod`](./go.mod) die Version hochstellen.)
Alle u.&nbsp;s. Befehle sollen in einer Bash-Konsole von diesem Ordner aus ausgeführt werden.
## Einrichten mittels **Makefile** ##
Führe jeweils
```bash
make setup
make build
make run
# oder für interaktiven Modus
make run-it
```
aus, um Packages zu installieren
bzw. den Code zu kompilieren
bzw. den Code auszuführen.
Siehe [`Makefile`](./Makefile) für Details zu den Vorgängen.
Wer Makefile benutzt kann die u.&nbsp;s. Anweisungen ignorieren.
## Setup/Kompilieren ##
1. Requirements (Packages) einmalig mittels
```bash
go get $( cat requirements )
```
installieren. Oder man führe den Befehl
für jede Zeile aus [`requirements`](./requirements) aus,
</br>
z.&nbsp;B. `go get github.com/akamensky/argparse@v1.3.1`
installiert eines der Packages.
2. Codetree mittels
```bash
go build -o ads main.go
```
kompilieren.
</br>
Statt `-o ads` kann man einen beliebigen Pfad verwenden.
</br>
In Unix kann man `-o path/to/folder/ads` verwenden.
</br>
In Windows kann man `-o path/to/folder/ads.exe` verwenden.
## Ausführung ##
Nach Kompilieren wird ein Artefakt namens `ads` gebaut,
den man per Doppelklick ausführen kann.
Alternativ kann man in der Konsole im Ordner mit dem Artefakt einfach
```bash
ads
```
ausführen.
## Entwicklung ##
Gerne kann man den Code benutzen, in einem eigenen Repository weiter entwickeln,
und mit den im Kurs präsentierten Algorithmen und Fällen herumexperimentieren.

View File

@ -1,3 +0,0 @@
+--------------------+
| \033[32;1mAlgoDat I\033[0m |
+--------------------+

View File

@ -1 +0,0 @@
0.0.0

View File

@ -1,7 +0,0 @@
info:
title: "App für ADS1"
description: "Interne Configurationsdatei"
options:
display: true
checks: false
metrics: true

View File

@ -1,13 +0,0 @@
module ads
go 1.17
require (
github.com/akamensky/argparse v1.3.1
github.com/davecgh/go-spew v1.1.1
github.com/lithammer/dedent v1.1.0
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.3.0
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

View File

@ -1,21 +0,0 @@
github.com/akamensky/argparse v1.3.1 h1:kP6+OyvR0fuBH6UhbE6yh/nskrDEIQgEA1SUXDPjx4g=
github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,42 +0,0 @@
package logging
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"os"
)
/* ---------------------------------------------------------------- *
* MAIN METHODS logging
* ---------------------------------------------------------------- */
func Plain(line interface{}, args ...interface{}) {
logGeneric(os.Stdout, "", line, args...)
}
func Info(line interface{}, args ...interface{}) {
logGeneric(os.Stdout, "[\033[94;1mINFO\033[0m]", line, args...)
}
func Debug(line interface{}, args ...interface{}) {
if !debugmode {
return
}
logGeneric(os.Stdout, "\033[2m[\033[96;1mDEBUG\033[0m\033[2m]\033[0m", fmt.Sprintf("\033[2m%v\033[0m", line), args...)
}
func Warn(line interface{}, args ...interface{}) {
logGeneric(os.Stdout, "[\033[93;1mWARNING\033[0m]", line, args...)
}
func Error(line interface{}, args ...interface{}) {
logGeneric(os.Stderr, "[\033[91;1mERROR\033[0m]", line, args...)
}
func Fatal(line interface{}, args ...interface{}) {
logGeneric(os.Stderr, "[\033[91;1mFATAL\033[0m]", line, args...)
os.Exit(1)
}

View File

@ -1,45 +0,0 @@
package logging
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"os"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* AUXILIARY METHODS
* ---------------------------------------------------------------- */
func logGeneric(pipe *os.File, tag string, line interface{}, args ...interface{}) {
if !force && quietmode {
return
}
if !(tag == "") {
tag = tag + " "
}
fmt.Fprintln(pipe, decorateLine(loggingPrefix, tag, expandLine(line, args)))
}
func expandLine(line interface{}, args []interface{}) string {
return fmt.Sprintf(fmt.Sprintf("%s", line), args...)
}
func decorateLine(loggingPrefix string, tag string, line string) string {
return stripAnsiIfNecessary(fmt.Sprintf("%[1]s%[2]s%[3]v", loggingPrefix, tag, line))
}
func stripAnsiIfNecessary(line string) string {
if !ansimode {
line = utils.StripAnsi(line)
}
return line
}
func ClearScreen() {
fmt.Print("\033[2J")
}

View File

@ -1,46 +0,0 @@
package logging
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"bufio"
"fmt"
"io"
"os"
"ads/pkg/re"
)
/* ---------------------------------------------------------------- *
* METHOD prompts
* ---------------------------------------------------------------- */
// Zeigt Prompt an und liest Usereingabe aus, erkennt auch ob Meta+D geklickt wurde
func Prompt(lines ...interface{}) (string, bool, error) {
pipe := os.Stdout
if len(lines) > 0 {
tag := ""
for _, line := range lines {
logGeneric(pipe, tag, line)
}
logGeneric(pipe, tag, "")
}
fmt.Fprintf(pipe, "%s ", promptSymb)
reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n')
line = re.Sub(`\s+$`, "", line)
if err != nil && err == io.EOF {
fmt.Fprintln(pipe, "")
return line, true, err
}
return line, false, err
}
func PromptAnyKeyToContinue() bool {
pipe := os.Stdout
fmt.Fprint(pipe, stripAnsiIfNecessary("\033[2;3mEingabetaste (Enter) zum Fortsetzen drücken:\033[0m "))
_, exit, _ := Prompt()
return exit
}

View File

@ -1,48 +0,0 @@
package logging
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var quietmode bool = false
var debugmode bool = true
var ansimode bool = false
var loggingPrefix string = ""
var force bool = false
var promptSymb string = ">"
func GetQuietMode() bool {
return quietmode
}
func SetQuietMode(mode bool) {
quietmode = mode
}
func GetDebugMode() bool {
return debugmode
}
func SetDebugMode(mode bool) {
debugmode = mode
}
func GetAnsiMode() bool {
return ansimode
}
func SetAnsiMode(mode bool) {
ansimode = mode
}
func GetForce() bool {
return force
}
func SetForce(mode bool) {
force = mode
}

View File

@ -1,90 +0,0 @@
package metrics
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"time"
"ads/internal/core/utils"
"ads/internal/types"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
var _ctr_time = types.NewCounter()
var _ctr_moves = types.NewCounter()
var _ctr_space = types.NewCounter()
var _tmr = types.NewTimer()
/* ---------------------------------------------------------------- *
* METHODS
* ---------------------------------------------------------------- */
func ResetMetrics() {
_ctr_time.Reset()
_ctr_moves.Reset()
_ctr_space.Reset()
_tmr.Reset()
}
func StartMetrics() {
_tmr.Start()
}
func StopMetrics() {
_tmr.Stop()
}
func AddTimeCost(options ...int) {
_ctr_time.Add(options...)
}
func AddMovesCost(options ...int) {
_ctr_moves.Add(options...)
}
func AddSpaceCost(options ...int) {
_ctr_space.Add(options...)
}
func SetSpaceCost(n int) {
_ctr_space.Set(n)
}
func GetTimeCost() int {
return _ctr_time.Size()
}
func GetMovesCost() int {
return _ctr_moves.Size()
}
func GetSpaceCost() int {
return _ctr_space.Size()
}
func GetTimeElapsed() time.Duration {
return _tmr.ElapsedTime()
}
func GetTimeElapsedLongFormat() string {
t := _tmr.ElapsedTime()
h := utils.Floor(t.Hours())
m := utils.Floor(t.Minutes()) - h*60
s := t.Seconds() - float64(m*60)
h_string := fmt.Sprintf("%v", h)
for len(h_string) < 2 {
h_string = "0" + h_string
}
m_string := fmt.Sprintf("%v", m)
for len(m_string) < 2 {
m_string = "0" + m_string
}
s_string := fmt.Sprintf("%f", s)
return fmt.Sprintf("%[1]s:%[2]s:%[3]s", h_string, m_string, s_string)
}

View File

@ -1,104 +0,0 @@
package utils
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"reflect"
)
/* ---------------------------------------------------------------- *
* METHOD array contains
* ---------------------------------------------------------------- */
func ArrayContains(x interface{}, elem interface{}) bool {
xAsArray := reflect.ValueOf(x)
if xAsArray.Kind() == reflect.Slice {
for i := 0; i < xAsArray.Len(); i++ {
if xAsArray.Index(i).Interface() == elem {
return true
}
}
}
return false
}
/* ---------------------------------------------------------------- *
* METHOD sort
* ---------------------------------------------------------------- */
func IsSortedListInt(X []int) bool {
n := len(X)
for i, x := range X {
for j := i + 1; j < n; j++ {
if X[j] < x {
return false
}
}
}
return true
}
/* ---------------------------------------------------------------- *
* METHOD insert, pop
* ---------------------------------------------------------------- */
func PopIndexListInt(X []int, index int) []int {
// NOTE: aus irgendeinem Grund reicht es nicht aus mit X zu arbeiten, denn sonst die u. s. Zeile überschreibt X
X_ := make([]int, len(X))
copy(X_, X)
return append(X_[:index], X_[(index+1):]...)
}
/* ---------------------------------------------------------------- *
* METHOD unique
* ---------------------------------------------------------------- */
func UniqueListInt(X []int) []int {
var ok bool
m := map[int]bool{}
X_unique := []int{}
for _, x := range X {
if _, ok = m[x]; !ok {
X_unique = append(X_unique, x)
}
}
return X_unique
}
func ContainsNoDuplicatesListInt(X []int) bool {
return len(X) <= len(UniqueListInt(X))
}
/* ---------------------------------------------------------------- *
* METHOD get value from array of unknown length
* ---------------------------------------------------------------- */
func GetArrayStringValue(arr *[]string, index int, Default string) string {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayBoolValue(arr *[]bool, index int, Default bool) bool {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayIntValue(arr *[]int, index int, Default int) int {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayInterfaceValue(arr *[](interface{}), index int, Default interface{}) interface{} {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}

View File

@ -1,147 +0,0 @@
package utils
/*
In Golang sind manche (basic!) mathematischen Vorgänge etwas umständlich zu implementieren.
Wir wollen diese Methoden komplett einhüllen, damit wir von ihrer Komplexität
in den Algorithmen nicht abgelenkt werden.
*/
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"math"
"strconv"
)
/* ---------------------------------------------------------------- *
* METHOD floor, ceil
* ---------------------------------------------------------------- */
func Floor(x float64) int {
return int(math.Floor(x))
}
func Ceil(x float64) int {
return int(math.Ceil(x))
}
/* ---------------------------------------------------------------- *
* METHOD max, min
* ---------------------------------------------------------------- */
func MinInt(x int, y ...int) int {
if len(y) == 0 {
return x
} else if x < y[0] {
return MinInt(x, y[1:]...)
} else {
return MinInt(y[0], y[1:]...)
}
}
func MaxInt(x int, y ...int) int {
if len(y) == 0 {
return x
} else if x > y[0] {
return MaxInt(x, y[1:]...)
} else {
return MaxInt(y[0], y[1:]...)
}
}
func ArgMinInt(X []int) int {
if len(X) == 0 {
return -1
}
minValue := X[0]
index := 0
for i, x := range X {
if x < minValue {
minValue = x
index = i
}
}
return index
}
func ArgMaxInt(X []int) int {
if len(X) == 0 {
return -1
}
maxValue := X[0]
index := 0
for i, x := range X {
if x > maxValue {
maxValue = x
index = i
}
}
return index
}
/* ---------------------------------------------------------------- *
* METHOD sum
* ---------------------------------------------------------------- */
func SumListInt(X []int) int {
result := 0
for _, x := range X {
result += x
}
return result
}
func SumListFloat(X []float64) float64 {
result := 0.
for _, x := range X {
result += x
}
return result
}
/* ---------------------------------------------------------------- *
* METHODS binary
* ---------------------------------------------------------------- */
/*
Für eine Zahl n != 0 liefert die Länge der binären Darstellung der Zahl,
und für n == 0 liefert 0
*/
func LengthOfBinary(number int) int {
if number == 0 {
return 0
}
if number < 0 {
number = -number
}
number_binary := fmt.Sprintf("%b", int64(number))
return len([]rune(number_binary))
}
/*
Für eine Zahl n != 0 liefert die Bits der binären Darstellung
*/
func IntToBinary(number int) []int {
if number == 0 || number == 1 {
return []int{number}
}
number_binary := fmt.Sprintf("%b", int64(number))
runes := []rune(number_binary)
bits := make([]int, len(runes))
for i, rune := range runes {
bit, _ := strconv.ParseInt(fmt.Sprintf("%c", rune), 2, 64)
bits[len(runes)-1-i] = int(bit)
}
return bits
}
func NthBit(number int, digit int) int {
bits := IntToBinary(number)
if digit < len(bits) {
return bits[digit]
}
return 0
}

View File

@ -1,76 +0,0 @@
package utils
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"log"
"strconv"
"strings"
"github.com/lithammer/dedent"
"ads/pkg/re"
)
/* ---------------------------------------------------------------- *
* METHOD dedent textblock and expand escaped symbols
* ---------------------------------------------------------------- */
func DedentIgnoreEmptyLines(text string) string {
return dedent.Dedent(text)
}
func DedentIgnoreFirstAndLast(text string) string {
text = re.Sub(`^\s*[\n\r]|[\n\r]\s*$`, ``, text)
return DedentIgnoreEmptyLines(text)
}
func DedentAndExpand(text string) string {
var err error
var result []string
result = []string{}
text = dedent.Dedent(text)
lines := strings.Split(text, "\n")
for _, line := range lines {
line = fmt.Sprintf(`"%s"`, line)
line, err = strconv.Unquote(line)
if err != nil {
log.Fatal(err)
}
result = append(result, line)
}
return strings.Join(result, "\n")
}
func FormatTextBlockAsList(text string, options ...bool) []string {
var unindent bool = GetArrayBoolValue(&options, 0, true)
if unindent {
text = DedentIgnoreFirstAndLast(text)
}
return re.Split(`\n`, text)
}
/* ---------------------------------------------------------------- *
* METHODS ansi
* ---------------------------------------------------------------- */
func StripAnsi(text string) string {
return re.Sub(`\x1b[^m]*m`, ``, text)
}
/* ---------------------------------------------------------------- *
* METHODS string -> bool
* ---------------------------------------------------------------- */
func IsTrue(text string) bool {
text = strings.TrimSpace(text)
return re.Matches(`(?i)(^(true|t|yes|y|1|\+|\+1)$)`, text)
}
func IsFalse(text string) bool {
text = strings.TrimSpace(text)
return re.Matches(`(?i)(^(false|f|no|n|0|-|-1)$)`, text)
}

View File

@ -1,34 +0,0 @@
package print
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
"ads/internal/setup/cli"
)
/* ---------------------------------------------------------------- *
* ENDPOINT version
* ---------------------------------------------------------------- */
func Version() {
logging.SetForce(true)
logging.Plain(setup.Version())
}
/* ---------------------------------------------------------------- *
* ENDPOINT help
* ---------------------------------------------------------------- */
func Help() {
logging.SetForce(true)
cli.ParseCli([]string{}) // <- generiere leere Instanz für Parser, um voll Hilfsanleitug zu zeigen
logging.Plain("")
logging.Plain(setup.Logo())
// logging.Plain(setup.Help())
logging.Plain(cli.Parser.Usage(nil))
logging.Plain("")
}

View File

@ -1,173 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/logging"
"ads/internal/setup"
"ads/internal/types"
algorithm_search_binary "ads/pkg/algorithms/search/binary"
algorithm_search_interpol "ads/pkg/algorithms/search/interpol"
algorithm_search_ith_element "ads/pkg/algorithms/search/ith_element"
algorithm_search_jump "ads/pkg/algorithms/search/jump"
algorithm_search_poison "ads/pkg/algorithms/search/poison"
algorithm_search_sequential "ads/pkg/algorithms/search/sequential"
algorithm_stacks_next_greater_element "ads/pkg/algorithms/stacks/next_greater_element"
algorithm_sum_maxsubsum "ads/pkg/algorithms/sum/maxsubsum"
)
/* ---------------------------------------------------------------- *
* ENDPOINT run interactive modus
* ---------------------------------------------------------------- */
// Startet App im interaktiven Modus
func RunInteractive() error {
logging.Plain(setup.Logo())
_, err := menuMain.ShowMenu()
logging.Plain("\033[2;3m...Programm terminiert.\033[0m")
return err
}
/* ---------------------------------------------------------------- *
* ENDPOINT run non-interactive modus
* ---------------------------------------------------------------- */
// Liest Config Datei ein und führt Algorithmen auf Fälle durch
func RunNonInteractive(path string) error {
var err error
var err_case error
// extrahiere user config
config := setup.NewUserConfig()
err = setup.GetUserConfig(path, &config)
if err != nil {
return err
}
logging.Plain(setup.Logo())
// Fälle extrahieren
cases := []types.UserConfigCase{}
if config.Parts != nil && config.Parts.Cases != nil {
cases = *config.Parts.Cases
}
for i := 0; i < len(cases); i++ {
err_case = nil
problem := cases[i]
setup.DisplayStartOfCase(i, problem.Description)
inputs := types.UserConfigInputs{}
if problem.Inputs != nil {
inputs = *problem.Inputs
}
if problem.Command == nil {
err_case = fmt.Errorf("Attribute 'command:' fehlt!")
} else {
switch *problem.Command {
case "algorithm-search-binary":
L := inputs.List
x := inputs.SearchValue
if L != nil && x != nil {
_, err_case = algorithm_search_binary.FancyBinarySearch(*L, *x)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-interpolation":
L := inputs.List
x := inputs.SearchValue
if L != nil && x != nil {
_, err_case = algorithm_search_interpol.FancyInterpolationSearch(*L, *x, 0, len(*L)-1)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-ith-element":
L := inputs.List
i := inputs.SearchRank
if L != nil && i != nil {
_, err_case = algorithm_search_ith_element.FancyFindIthSmallest(*L, *i)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-ith-element-dc":
L := inputs.List
i := inputs.SearchRank
if L != nil && i != nil {
_, err_case = algorithm_search_ith_element.FancyFindIthSmallestDC(*L, *i)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-jump":
L := inputs.List
x := inputs.SearchValue
m := inputs.JumpSize
if L != nil && x != nil {
_, err_case = algorithm_search_jump.FancyJumpSearchLinear(*L, *x, *m)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-jump-exp":
L := inputs.List
x := inputs.SearchValue
if L != nil && x != nil {
_, err_case = algorithm_search_jump.FancyJumpSearchExponentiell(*L, *x)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-poison":
L := inputs.List
if L != nil {
_, err_case = algorithm_search_poison.FancyFindPoison(*L)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-poison-fast":
L := inputs.List
if L != nil {
_, err_case = algorithm_search_poison.FancyFindPoisonFast(*L)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-search-sequential":
L := inputs.List
x := inputs.SearchValue
if L != nil && x != nil {
_, err_case = algorithm_search_sequential.FancySequentialSearch(*L, *x)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-stacks-next-greater-element":
L := inputs.List
if L != nil {
_, err_case = algorithm_stacks_next_greater_element.FancyNextGreaterElement(*L)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-sum-maxsub":
L := inputs.List
if L != nil {
_, _, _, err_case = algorithm_sum_maxsubsum.FancyMaxSubSum(*L)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
case "algorithm-sum-maxsub-dc":
L := inputs.List
if L != nil {
_, _, _, err_case = algorithm_sum_maxsubsum.FancyMaxSubSumDC(*L)
} else {
err_case = fmt.Errorf("Fehlende Inputs für Befehl '%[1]s'.", *problem.Command)
}
default:
err_case = fmt.Errorf("Unbekannter Befehl '%[1]s'.", *problem.Command)
}
}
if err_case != nil {
logging.Error(err_case)
}
}
setup.DisplayEndOfCase()
return nil
}

View File

@ -1,254 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
algorithm_search_binary "ads/pkg/algorithms/search/binary"
algorithm_search_interpol "ads/pkg/algorithms/search/interpol"
algorithm_search_ith_element "ads/pkg/algorithms/search/ith_element"
algorithm_search_jump "ads/pkg/algorithms/search/jump"
algorithm_search_poison "ads/pkg/algorithms/search/poison"
algorithm_search_sequential "ads/pkg/algorithms/search/sequential"
algorithm_stacks_next_greater_element "ads/pkg/algorithms/stacks/next_greater_element"
algorithm_sum_maxsubsum "ads/pkg/algorithms/sum/maxsubsum"
)
/* ---------------------------------------------------------------- *
* ACTIONS algorithmen - search
* ---------------------------------------------------------------- */
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()
_, err = algorithm_search_binary.FancyBinarySearch(input_L, input_x)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_interpol.FancyInterpolationSearch(input_L, input_x, 0, len(input_L)-1)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_ith_element.FancyFindIthSmallest(input_L, input_i)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_ith_element.FancyFindIthSmallestDC(input_L, input_i)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_jump.FancyJumpSearchLinear(input_L, input_x, input_m)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_jump.FancyJumpSearchExponentiell(input_L, input_x)
if err != nil {
logging.Error(err)
}
setup.DisplayEndOfCase()
return cancel, nil
}
func actionAlgorithmSearchPoison() (bool, error) {
input_L, cancel, err := promptInputListOfZeroOnes("L", "Liste von Werten", []string{
"muss genau eine 1 enthalten",
})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
_, err = algorithm_search_poison.FancyFindPoison(input_L)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_poison.FancyFindPoisonFast(input_L)
if err != nil {
logging.Error(err)
}
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()
_, err = algorithm_search_sequential.FancySequentialSearch(input_L, input_x)
if err != nil {
logging.Error(err)
}
setup.DisplayEndOfCase()
return cancel, nil
}
/* ---------------------------------------------------------------- *
* ACTIONS algorithmen - stacks
* ---------------------------------------------------------------- */
func actionAlgorithmStacksNextGreaterElement() (bool, error) {
input_L, cancel, err := promptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
_, err = algorithm_stacks_next_greater_element.FancyNextGreaterElement(input_L)
if err != nil {
logging.Error(err)
}
setup.DisplayEndOfCase()
return cancel, nil
}
/* ---------------------------------------------------------------- *
* ACTIONS algorithmen - sum
* ---------------------------------------------------------------- */
func actionAlgorithmSumMaxsub() (bool, error) {
input_L, cancel, err := promptInputListOfInt("L", "Liste von Werten", []string{})
if cancel || err != nil {
return cancel, err
}
setup.DisplayStartOfCaseBlank()
_, _, _, err = algorithm_sum_maxsubsum.FancyMaxSubSum(input_L)
if err != nil {
logging.Error(err)
}
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()
_, _, _, err = algorithm_sum_maxsubsum.FancyMaxSubSumDC(input_L)
if err != nil {
logging.Error(err)
}
setup.DisplayEndOfCase()
return cancel, nil
}

View File

@ -1,34 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* ACTIONS - basic
* ---------------------------------------------------------------- */
func actionShowVersion() (bool, error) {
logging.Plain("")
logging.Plain(setup.Logo())
logging.Plain("Version: \033[1m%s\033[0m", setup.Version())
logging.Plain("")
return false, nil
}
func actionRunOnConfig() (bool, error) {
path, cancel, err := logging.Prompt("Pfad zur Configdatei bitte eingeben:")
if cancel {
return true, nil
}
if err != nil {
return false, err
}
err = RunNonInteractive(path)
return false, err
}

View File

@ -1,64 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* ACTIONS - settting
* ---------------------------------------------------------------- */
func actionShowSettings() (bool, error) {
var state string
state = "aus"
if logging.GetAnsiMode() {
state = "ein"
}
logging.Info("Farbenmodus: %s", state)
state = "aus"
if logging.GetDebugMode() {
state = "ein"
}
logging.Info("Debugmodus: %s", state)
state = "aus"
if setup.AppConfigPerformChecks() {
state = "ein"
}
logging.Info("Pre/Postchecking: %s", state)
return false, nil
}
func actionColourModeOn() (bool, error) {
logging.SetAnsiMode(true)
return false, nil
}
func actionColourModeOff() (bool, error) {
logging.SetAnsiMode(false)
return false, nil
}
func actionDebugModeOn() (bool, error) {
logging.SetDebugMode(true)
return false, nil
}
func actionDebugModeOff() (bool, error) {
logging.SetDebugMode(false)
return false, nil
}
func actionPrePostCheckingOn() (bool, error) {
setup.SetAppConfigPerformChecks(true)
return false, nil
}
func actionPrePostCheckingOff() (bool, error) {
setup.SetAppConfigPerformChecks(false)
return false, nil
}

View File

@ -1,146 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/menus"
)
/* ---------------------------------------------------------------- *
* MENUS
* ---------------------------------------------------------------- */
var menuMain = menus.Menu{
IsRoot: true,
Path: []string{"Hauptmenü"},
PromptMessages: []string{
"Option wählen",
},
Options: [][]menus.MenuOption{
{
{Label: "Einstellungen", Submenu: &menuSettings},
{Label: "Version des Programms anzeigen", Action: actionShowVersion},
}, {
{Label: "Programm auf config Datei ausführen.", Action: actionRunOnConfig},
}, {
{Label: "Suchalgorithmen", Submenu: &menuSearchAlgorithms},
{Label: "Summenalgorithmen", Submenu: &menuSumAlgorithms},
{Label: "Algorithmen mit Stacks und Queues", Submenu: &menuStacksQueuesAlgorithms},
},
},
Default: -1,
}
var menuSettings = menus.Menu{
Path: []string{"Hauptmenü", "Einstellungen"},
PromptMessages: []string{
"Option wählen",
},
Options: [][]menus.MenuOption{
{
{Label: "Aktueller Zustand", Action: actionShowSettings},
{Label: "Farbenmodus", Submenu: &menuColourMode},
{Label: "Debugmodus", Submenu: &menuDebugMode},
{Label: "Pre / Postchecking", Submenu: &menuPrePostChecking},
},
},
Default: -1,
}
var menuColourMode = menus.Menu{
ForceReturn: true,
Path: []string{"Hauptmenü", "Einstellungen", "Farbenmodus"},
PromptMessages: []string{
"Soll Console-Output mit Formattierung dargestellt werden?",
"Option für den Farbenmodus wählen:",
},
Options: [][]menus.MenuOption{
{
{Label: "ein", Action: actionColourModeOn},
{Label: "aus", Action: actionColourModeOff},
},
},
Default: 1,
}
var menuDebugMode = menus.Menu{
ForceReturn: true,
Path: []string{"Hauptmenü", "Einstellungen", "Debugmodus"},
PromptMessages: []string{
"Sollen Infos zu jedem Schritt der Algorithmen angezeigt werden?",
"Option für den Debugmodus wählen:",
},
Options: [][]menus.MenuOption{
{
{Label: "ein", Action: actionDebugModeOn},
{Label: "aus", Action: actionDebugModeOff},
},
},
Default: 0,
}
var menuPrePostChecking = menus.Menu{
ForceReturn: true,
Path: []string{"Hauptmenü", "Einstellungen", "Pre/Postchecking"},
PromptMessages: []string{
"Sollen Inputs+Outputs bei Algorithmenausführungen geprüft werden?",
"Option für den Pre/Postchecking wählen:",
},
Options: [][]menus.MenuOption{
{
{Label: "ein", Action: actionPrePostCheckingOn},
{Label: "aus", Action: actionPrePostCheckingOff},
},
},
Default: 1,
}
var menuSearchAlgorithms = menus.Menu{
Path: []string{"Hauptmenü", "Suchalgorithmen"},
PromptMessages: []string{
"Algorithmus wählen",
},
Options: [][]menus.MenuOption{
{
{Label: "Binärsuchalgorithmus", Action: actionAlgorithmSearchBinary},
{Label: "Interpolationsalgorithmus", Action: actionAlgorithmSearchInterpolation},
{Label: "Suche i. kleinstes Element", Action: actionAlgorithmSearchIthElement},
{Label: "Suche i. kleinstes Element", SubLabel: "D & C", Action: actionAlgorithmSearchIthElementDc},
{Label: "Sprungsuche", SubLabel: "linear", Action: actionAlgorithmSearchJump},
{Label: "Sprungsuche", SubLabel: "exponentiell", Action: actionAlgorithmSearchJumpExp},
{Label: "Giftsuche", Action: actionAlgorithmSearchPoison},
{Label: "Giftsuche", SubLabel: "optimiert", Action: actionAlgorithmSearchPoisonFast},
{Label: "Sequentiellsuchalgorithmus", Action: actionAlgorithmSearchSequential},
},
},
Default: -1,
}
var menuStacksQueuesAlgorithms = menus.Menu{
Path: []string{"Hauptmenü", "Algorithmen mit Stacks und Queues"},
PromptMessages: []string{
"Algorithmus wählen",
},
Options: [][]menus.MenuOption{
{
{Label: "'Next Greater Element' mit Stacks", Action: actionAlgorithmStacksNextGreaterElement},
},
},
Default: -1,
}
var menuSumAlgorithms = menus.Menu{
Path: []string{"Hauptmenü", "Summenalgorithmen"},
PromptMessages: []string{
"Algorithmus wählen",
},
Options: [][]menus.MenuOption{
{
{Label: "Maximale Teilsumme", SubLabel: "brute force", Action: actionAlgorithmSumMaxsub},
{Label: "Maximale Teilsumme", SubLabel: "D & C", Action: actionAlgorithmSumMaxsubDc},
},
},
Default: -1,
}

View File

@ -1,76 +0,0 @@
package run
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/menus"
)
/* ---------------------------------------------------------------- *
* 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) {
var values = []int{}
type responseType struct {
Response []uint8 `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()
// uint8 -> int
if response.Response != nil {
for _, x := range response.Response {
values = append(values, int(x))
}
}
return values, cancel, err
}

View File

@ -1,206 +0,0 @@
package menus
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"reflect"
"strconv"
"strings"
"ads/internal/core/logging"
"gopkg.in/yaml.v3"
)
/* ---------------------------------------------------------------- *
* METHOD menu class methods
* ---------------------------------------------------------------- */
func (menu *Menu) SetDefault(index int) {
menu.Default = index
}
/* ---------------------------------------------------------------- *
* METHOD show menu
* ---------------------------------------------------------------- */
func (menu Menu) ShowMenu() (bool, error) {
var (
choice string
index int
meta bool
quit bool
cancel bool
err error
)
var promptMessages []string
var optionsFlattened []MenuOption
var optionsKeyValue [][2]string
var defaultOption string
var breaks []int
// Headline einfügen
promptMessages = make([]string, len(menu.PromptMessages))
copy(promptMessages, menu.PromptMessages)
head := fmt.Sprintf("\033[2m%s\033[0m", strings.Join(menu.Path, " > "))
promptMessages = append([]string{head}, promptMessages...)
// Zurück-Option einfügen
defaultOption = ""
if menu.Default >= 0 {
defaultOption = fmt.Sprintf("%v", menu.Default+1)
}
breaks = []int{}
optionsFlattened = []MenuOption{}
optionsKeyValue = []([2]string){}
index = 0
for _, suboptions := range menu.Options {
for _, opt := range suboptions {
optionsFlattened = append(optionsFlattened, opt)
key := fmt.Sprintf("%v", index+1)
subLabel := opt.SubLabel
label := opt.Label
if !(subLabel == "") {
label = fmt.Sprintf("%v (\033[2m%v\033[0m)", opt.Label, subLabel)
}
optionsKeyValue = append(optionsKeyValue, [2]string{key, label})
index++
}
breaks = append(breaks, index-1)
}
if !menu.IsRoot {
optionsKeyValue = append(optionsKeyValue, [2]string{"z", "Zurück zum vorherigen Menü"})
}
optionsKeyValue = append(optionsKeyValue, [2]string{"q", "Programm schließen"})
// User Response immer abfragen und abarbeiten, bis quit/return.
performClearScreen := !menu.IsRoot
for {
if performClearScreen {
logging.ClearScreen()
}
performClearScreen = true
choice, meta = promptListOfOptions(promptMessages, optionsKeyValue, breaks, defaultOption)
// Falls quit wählt, -> quit:
if (menu.IsRoot && meta) || choice == "q" {
return true, nil
}
// Falls User back wählt, -> return:
if (!menu.IsRoot && meta) || choice == "z" {
return false, nil
}
// sonst führe die assoziierte Methode aus
index64, _ := strconv.ParseInt(choice, 10, 64)
index = int(index64) - 1
if 0 <= index && index < len(optionsFlattened) {
opt := optionsFlattened[index]
// Entweder Untermenü öffnen oder Action ausführen
if opt.Submenu != nil {
quit, err = opt.Submenu.ShowMenu()
if quit {
return true, err
}
} else if opt.Action != nil {
cancel, err = opt.Action()
if err != nil {
logging.Error(err)
}
// Falls ForceReturn, dann nach Ausführung der Action, -> return
if menu.ForceReturn {
return false, nil
} else {
// Falls während der Action der User Meta+D klickt, -> return:
if cancel {
continue
}
quit := logging.PromptAnyKeyToContinue()
// Falls nach der Action der User Meta+D klickt, -> quit:
if quit {
return true, nil
}
}
} else {
logging.Warn("Option noch nicht implementiert.")
quit := logging.PromptAnyKeyToContinue()
if quit {
return true, nil
}
}
}
}
}
/* ---------------------------------------------------------------- *
* 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;4mAnforderung(en) auf Input:\033[0m \033[2m%s\033[0m", requirement))
} else {
lines = append(lines, fmt.Sprintf(" \033[3;4mAnforderung(en) auf Input:\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.Error(err)
logging.Plain("")
continue
}
line = fmt.Sprintf("\"response\": %s", line)
err = yaml.Unmarshal([]byte(line), query.Response)
if err != nil {
logging.Error(err)
logging.Plain("")
continue
}
break
}
return cancel, err
}

View File

@ -1,81 +0,0 @@
package menus
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"strings"
"ads/internal/core/logging"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* METHOD prompt options
* ---------------------------------------------------------------- */
// Zeigt Prompt mit Liste von Optionen an
func promptListOfOptions(messages []string, options [][2]string, breaks []int, defaultChoice string) (string, bool) {
var n = len(options)
var (
choice string
cancel bool
err error
)
var lines []interface{}
var optionsMap = map[string]string{}
// Erzeuge Messages
lines = []interface{}{}
for _, message := range messages {
lines = append(lines, message)
}
lines = append(lines, "")
textbar := fmt.Sprintf(" \033[93m+%s+\033[0m", strings.Repeat("-", 40))
lines = append(lines, textbar)
for i, obj := range options {
key := obj[0]
label := obj[1]
optionsMap[key] = label
if key == defaultChoice {
lines = append(lines, fmt.Sprintf("\033[91m*\033[0m\033[93;1m%v)\033[0m %v", key, label))
} else {
lines = append(lines, fmt.Sprintf(" \033[93;1m%v)\033[0m %v", key, label))
}
if i < n-1 && utils.ArrayContains(breaks, i) {
lines = append(lines, " \033[93m+----\033[0m")
}
i++
}
lines = append(lines, textbar)
if !(defaultChoice == "") {
lines = append(lines, "")
lines = append(lines, " \033[91;2m*\033[0m\033[2m = Default\033[0m")
}
// Wiederhole Prompt, bis gültige Eingabe erreicht
for {
choice, cancel, err = logging.Prompt(lines...)
if cancel {
return "", true
}
if err != nil {
logging.ClearScreen()
logging.Error(err)
continue
}
if choice == "" {
choice = defaultChoice
break
}
if _, ok := optionsMap[choice]; !ok {
logging.ClearScreen()
logging.Error("Ungültige eingabe")
continue
}
break
}
return choice, false
}

View File

@ -1,58 +0,0 @@
package menus
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* TYPES
* ---------------------------------------------------------------- */
type MenuOption struct {
Label string
SubLabel string
Submenu *Menu
Action func() (bool, error) // NOTE: in go, this is automatically a pointer type
}
type Menu struct {
IsRoot bool
ForceReturn bool
Path []string
PromptMessages []string
Options [][]MenuOption
Default 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

@ -1,94 +0,0 @@
package cli
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"github.com/akamensky/argparse"
"ads/internal/types"
"ads/pkg/re"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var Parser *argparse.Parser
/* ---------------------------------------------------------------- *
* LOCAL VARIABLES / CONSTANTS
* ---------------------------------------------------------------- */
var optionsQuiet = argparse.Options{
Help: "Blendet alle Konsole-Messages aus.",
Required: false,
Default: false,
}
var optionsChecks = argparse.Options{
Help: "Ob vor und nach Ausführung von Algorithmen Checks auf Inputs/Outputs ausgeführt werden sollen.",
Required: false,
// NOTE: no `Boolean` option available!
Default: "false",
}
var optionsDebug = argparse.Options{
Help: "Blendet Debugging-Befehle ein.",
Required: false,
Default: false,
}
var optionsInteractive = argparse.Options{
Help: "Startet das Programm im interaktiven Modus.",
Required: false,
Default: false,
}
var optionsColour = argparse.Options{
Help: "Ob Logging färblich angezeigt wird.",
Required: false,
// NOTE: no `Boolean` option available!
Default: "false",
}
var optionsConfigFile = argparse.Options{
Help: "Pfad zur Configdatei (nur für run Endpunkt).",
Required: false,
Default: "code/config.yml",
}
/* ---------------------------------------------------------------- *
* METHODS parse cli
* ---------------------------------------------------------------- */
// Parst cli flags.
func ParseCli(args []string) (*types.CliArguments, error) {
var err error
Parser = argparse.NewParser(
"cli parser",
"\033[93;2mEin Programm zur Ausführung verschiedener Algorithmen aus dem Kurs AlgoDat I.\033[0m",
)
arguments := types.CliArguments{
ModeHelp: Parser.NewCommand("help", "Hilfsanleitung anzeigen"),
ModeVersion: Parser.NewCommand("version", "Version anzeigen."),
ModeRun: Parser.NewCommand("run", "Algorithmen ausführen."),
Quiet: Parser.Flag("q", "quiet", &optionsQuiet),
Debug: Parser.Flag("", "debug", &optionsDebug),
Interactive: Parser.Flag("", "it", &optionsInteractive),
Checks: Parser.String("", "checks", &optionsChecks),
Colour: Parser.String("", "colour", &optionsColour),
ConfigFile: Parser.String("", "config", &optionsConfigFile),
}
err = Parser.Parse(args)
return &arguments, err
}
// Prüft, ob der Parser nur deshalb fehlschlägt, weil ein Command fehlt.
func ParseCliCommandMissing(err error) bool {
// FIXME: unschöne Lösung. Leider ist Error-Typ im Package versteckt
return re.Matches(`(?i)(command required)`, fmt.Sprintf("%v", err))
}

View File

@ -1,56 +0,0 @@
package setup
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"gopkg.in/yaml.v3"
"ads/internal/types"
)
/* ---------------------------------------------------------------- *
* GLOBAL CONSTANTS
* ---------------------------------------------------------------- */
var AppConfig = types.AppConfig{}
/* ---------------------------------------------------------------- *
* METHODS getters
* ---------------------------------------------------------------- */
// Extrahiert Inhalte einer YAML Config und parset dies als Struktur
func AppConfigInitialise() error {
contents := AppConfigYaml()
err := yaml.Unmarshal([]byte(contents), &AppConfig)
return err
}
func AppConfigFancyMode() bool {
return AppConfig.Options.Display
}
func AppConfigShowMetrics() bool {
return AppConfig.Options.Metrics
}
func AppConfigPerformChecks() bool {
return AppConfig.Options.Checks
}
/* ---------------------------------------------------------------- *
* METHODS setters
* ---------------------------------------------------------------- */
func SetAppConfigFancyMode(value bool) {
AppConfig.Options.Display = value
}
func SetAppConfigShowMetrics(value bool) {
AppConfig.Options.Metrics = value
}
func SetAppConfigPerformChecks(value bool) {
AppConfig.Options.Checks = value
}

View File

@ -1,60 +0,0 @@
package setup
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"embed"
"fmt"
"log"
"strings"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var Res embed.FS
var Assets map[string]string
/* ---------------------------------------------------------------- *
* METHOD read assets
* ---------------------------------------------------------------- */
func ReadAsset(key string) string {
var found bool
if _, found = Assets[key]; !found {
log.Fatal(fmt.Sprintf("Key \033[1m%s\033[0m not found in dictionary!", key))
}
data, err := Res.ReadFile(Assets[key])
if err != nil {
log.Fatal(err)
}
text := string(data)
return text
}
/* ---------------------------------------------------------------- *
* METHODS assets
* ---------------------------------------------------------------- */
func Help() string {
contents := ReadAsset("help")
return utils.DedentAndExpand(contents)
}
func Logo() string {
contents := ReadAsset("logo")
return utils.DedentAndExpand(contents)
}
func Version() string {
return strings.Trim(ReadAsset("version"), "\n")
}
func AppConfigYaml() string {
return strings.Trim(ReadAsset("appconfig"), "\n")
}

View File

@ -1,130 +0,0 @@
package setup
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"reflect"
"strings"
"ads/internal/core/logging"
"ads/internal/core/metrics"
)
/* ---------------------------------------------------------------- *
* METHOD display case start/end
* ---------------------------------------------------------------- */
func DisplayStartOfCase(index int, descr *string) {
DisplayBar(80)
if descr == nil || *descr == "" {
logging.Plain("\033[92;1mCASE %[1]v\033[0m.", index)
} else {
logging.Plain("\033[92;1mCASE %[1]v\033[0m (\033[1;2m%[2]s\033[0m).", index, *descr)
}
}
func DisplayStartOfCaseBlank() {
DisplayBar(80)
return
}
func DisplayEndOfCase() {
DisplayBar(80)
return
}
/* ---------------------------------------------------------------- *
* METHOD display value
* ---------------------------------------------------------------- */
func RepresentValue(value interface{}) interface{} {
switch reflect.TypeOf(value).Kind() {
case reflect.Ptr:
obj := reflect.ValueOf(value)
if obj.IsNil() {
return fmt.Sprintf("%v", nil)
} else {
return fmt.Sprintf("&%v", RepresentValue(obj.Elem().Interface()))
}
case reflect.Slice:
obj := reflect.ValueOf(value)
n := obj.Len()
values := []interface{}{}
for i := 0; i < n; i++ {
x := RepresentValue(obj.Index(i).Interface())
values = append(values, x)
}
if n > 10 {
values = append(append(values[:3], "..."), values[n-2:]...)
}
return fmt.Sprintf("%v", values)
case reflect.Map:
obj := reflect.ValueOf(value)
n := obj.Len()
iter := obj.MapRange()
m := map[interface{}]interface{}{}
parts := []string{}
for iter.Next() {
key := iter.Key().Interface()
x := RepresentValue(iter.Value().Interface())
m[key] = x
parts = append(parts, fmt.Sprintf("%[1]v: %[2]v", key, x))
}
if n > 4 {
parts = append(append(parts[:3], "..."), parts[n-2:]...)
}
return fmt.Sprintf("{%s}", strings.Join(parts, ", "))
}
return value
}
/* ---------------------------------------------------------------- *
* METHOD display algorithm start/end
* ---------------------------------------------------------------- */
func DisplayStartOfAlgorithm(name string, inputs map[string]interface{}) {
logging.Plain("Ausführung vom Algorithmus: \033[92;1m%[1]s\033[0m", name)
logging.Plain("INPUTS")
for varname, value := range inputs {
logging.Plain(" - %[1]s = %[2]v", varname, RepresentValue(value))
}
}
func DisplayEndOfAlgorithm(outputs map[string]interface{}) {
logging.Plain("OUTPUTS:")
for varname, value := range outputs {
logging.Plain(" - %[1]s = %[2]v", varname, RepresentValue(value))
}
}
func DisplayMetrics() {
// logging.Plain("Dauer der Ausführung: t = \033[1m%[1]v\033[0m", metrics.GetTimeElapsed())
logging.Plain("Dauer der Ausführung: t = \033[1m%[1]v\033[0m", metrics.GetTimeElapsedLongFormat())
logging.Plain("Kosten (Zeit): T(n) = \033[1m%[1]v\033[0m", displayCost(metrics.GetTimeCost()))
logging.Plain("Kosten (#Züge): M(n) = \033[1m%[1]v\033[0m", displayCost(metrics.GetMovesCost()))
logging.Plain("Kosten (Platz): S(n) = \033[1m%[1]v\033[0m", displayCost(metrics.GetSpaceCost()))
return
}
/* ---------------------------------------------------------------- *
* METHODS Verschiedenes
* ---------------------------------------------------------------- */
func DisplayBar(options ...int) {
n := 80
if len(options) > 0 {
n = options[0]
}
logging.Plain("+%[1]s+", strings.Repeat("-", n))
return
}
func displayCost(cost int) string {
if cost > 0 {
return fmt.Sprintf("%v", cost)
}
return "-"
}

View File

@ -1,31 +0,0 @@
package setup
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"io/ioutil"
"gopkg.in/yaml.v3"
"ads/internal/types"
)
/* ---------------------------------------------------------------- *
* METHODS
* ---------------------------------------------------------------- */
// Erstellt eine Struktur, die die Infos aus der Config-Datei erfasst
func NewUserConfig() types.UserConfig {
return types.UserConfig{}
}
// Extrahiert Inhalte einer YAML Config und parset dies als Struktur
func GetUserConfig(path string, config *types.UserConfig) error {
contents, err := ioutil.ReadFile(path)
if err == nil {
err = yaml.Unmarshal(contents, config)
}
return err
}

View File

@ -1,27 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* YAML SCHEMES
* ---------------------------------------------------------------- */
type AppConfig struct {
Info *AppConfigInfo `yaml:"info"`
Options *AppConfigOptions `yaml:"options"`
}
type AppConfigInfo struct {
Title *string `yaml:"title"`
Description *string `yaml:"description"`
}
type AppConfigOptions struct {
Display bool `yaml:"display"`
Checks bool `yaml:"checks"`
Metrics bool `yaml:"metrics"`
}

View File

@ -1,109 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"reflect"
)
/* ---------------------------------------------------------------- *
* METHOD convert basic types to pointers
* ---------------------------------------------------------------- */
/****
* NOTE: these cannot be replaced by inline variants, e.g.
* var x string
* var xx *string = &x
* as then the values are tied.
* These methods create addresses to clones of the original variables,
* and do not coincide with the addresses of the original variables.
****/
func StructToPtr(x struct{}) *struct{} {
var value = x
return &value
}
func InterfaceToPtr(x interface{}) *interface{} {
var value = x
return &value
}
func BoolToPtr(x bool) *bool {
var value = x
return &value
}
func StringToPtr(x string) *string {
var value = x
return &value
}
func IntToPtr(x int) *int {
var value = x
return &value
}
/* ---------------------------------------------------------------- *
* METHOD get value from ptr with default
* ---------------------------------------------------------------- */
func ExpandPtrToBool(p *bool) interface{} {
if p != nil {
return *p
}
return p
}
func PtrToBool(p *bool, Default bool) bool {
if p != nil {
return *p
}
return Default
}
func ExpandPtrToString(p *string) interface{} {
if p != nil {
return *p
}
return p
}
func PtrToString(p *string, Default string) string {
if p != nil {
return *p
}
return Default
}
func ExpandPtrToInt(p *int) interface{} {
if p != nil {
return *p
}
return p
}
func PtrToInt(p *int, Default int) int {
if p != nil {
return *p
}
return Default
}
/* ---------------------------------------------------------------- *
* METHOD interface to (ptr to) array
* ---------------------------------------------------------------- */
func InterfaceToArray(x interface{}) *[]interface{} {
if reflect.TypeOf(x).Kind() == reflect.Slice {
var xSlice []interface{} = []interface{}{}
var xConverted = reflect.ValueOf(x)
for i := 0; i < xConverted.Len(); i++ {
xSlice = append(xSlice, xConverted.Index(i).Interface())
}
return &xSlice
}
return nil
}

View File

@ -1,55 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"github.com/akamensky/argparse"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* TYPES
* ---------------------------------------------------------------- */
type CliArguments struct {
ModeHelp *argparse.Command
ModeVersion *argparse.Command
ModeRun *argparse.Command
Quiet *bool
Debug *bool
Interactive *bool
Checks *string
Colour *string
ConfigFile *string
}
/* ---------------------------------------------------------------- *
* METHODS convert string option to boolean
* ---------------------------------------------------------------- */
func (arguments CliArguments) QuietModeOn() bool {
return *arguments.Quiet
}
func (arguments CliArguments) DebugModeOn() bool {
return *arguments.Debug
}
func (arguments CliArguments) InteractiveMode() bool {
return *arguments.Interactive
}
func (arguments CliArguments) ShowChecks() bool {
return !utils.IsFalse(*arguments.Checks)
}
func (arguments CliArguments) ShowColour() bool {
return !utils.IsFalse(*arguments.Colour)
}
func (arguments CliArguments) GetConfigFile() string {
return *arguments.ConfigFile
}

View File

@ -1,56 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* TYPE Counter
* ---------------------------------------------------------------- */
type Counter struct {
nr int
}
/* ---------------------------------------------------------------- *
* CLASS METHODS
* ---------------------------------------------------------------- */
func NewCounter() Counter {
c := Counter{}
return c
}
func (self Counter) String() string {
return fmt.Sprintf("%[1]v", self.nr)
}
func (self Counter) Size() int {
return self.nr
}
func (self *Counter) Reset() {
self.nr = 0
}
func (self *Counter) Set(n int) {
self.nr = n
}
func (self *Counter) Add(options ...int) {
n := 1
if len(options) > 0 {
n = options[0]
}
self.nr += n
}

View File

@ -1,72 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"time"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* TYPE Timer
* ---------------------------------------------------------------- */
type Timer struct {
time_elapsed time.Duration
time_current time.Time
running bool
}
/* ---------------------------------------------------------------- *
* CLASS METHODS
* ---------------------------------------------------------------- */
func NewTimer() Timer {
c := Timer{}
c.Reset()
return c
}
func (self Timer) String() string {
return fmt.Sprintf("%[1]v", self.time_elapsed)
}
func (self Timer) CurrentTime() time.Time {
return self.time_current
}
func (self Timer) ElapsedTime() time.Duration {
return self.time_elapsed
}
func (self *Timer) Start() {
self.time_current = time.Now()
self.running = true
}
func (self *Timer) Stop() {
if self.running {
t0 := self.time_current
t1 := time.Now()
delta := t1.Sub(t0)
self.time_current = t1
self.time_elapsed += delta
}
self.running = false
}
func (self *Timer) Reset() {
t := time.Now()
delta := t.Sub(t) // d. h. 0
self.time_current = t
self.time_elapsed = delta
self.running = false
}

View File

@ -1,38 +0,0 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* YAML SCHEMES
* ---------------------------------------------------------------- */
type UserConfig struct {
Info *UserConfigInfo `yaml:"info"`
Parts *UserConfigParts `yaml:"parts"`
}
type UserConfigInfo struct {
Title *string `yaml:"title"`
Description *string `yaml:"description"`
}
type UserConfigParts struct {
Cases *([]UserConfigCase) `yaml:"cases"`
}
type UserConfigCase struct {
Command *string `yaml:"command"`
Description *string `yaml:"description"`
Inputs *UserConfigInputs `yaml:"inputs"`
}
type UserConfigInputs struct {
List *[]int `yaml:"L"`
SearchRank *int `yaml:"i"`
SearchValue *int `yaml:"x"`
JumpSize *int `yaml:"m"`
}

View File

@ -1,103 +0,0 @@
package main
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"embed"
"os"
"ads/internal/core/logging"
"ads/internal/setup"
"ads/internal/setup/cli"
"ads/internal/types"
endpoints_print "ads/internal/endpoints/print"
endpoints_run "ads/internal/endpoints/run"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var (
// !!! NOTE: do not remove the following "comment", as it is a preprocessing instruction !!!
//go:embed assets/*
res embed.FS
assets = map[string]string{
"appconfig": "assets/config.yml",
"version": "assets/VERSION",
"logo": "assets/LOGO",
"help": "assets/HELP",
}
)
/* ---------------------------------------------------------------- *
* METHOD main
* ---------------------------------------------------------------- */
func main() {
var arguments *types.CliArguments
var (
err1 error
err2 error
err3 error
cmdMissing bool
showChecks bool
)
// assets festlegen
setup.Res = res
setup.Assets = assets
// cli arguments parsen
arguments, err1 = cli.ParseCli(os.Args)
cmdMissing = cli.ParseCliCommandMissing(err1)
// Programmeinstellungen initialisieren
showChecks = false
if err1 == nil {
if !(arguments.ModeRun.Happened() && arguments.InteractiveMode()) {
logging.SetQuietMode(arguments.QuietModeOn())
logging.SetDebugMode(arguments.DebugModeOn())
}
logging.SetAnsiMode(arguments.ShowColour())
showChecks = arguments.ShowChecks()
}
err2 = setup.AppConfigInitialise()
setup.SetAppConfigPerformChecks(showChecks)
// Fehler melden (fatal)
if err1 != nil && !cmdMissing {
logging.Fatal(err1)
}
if err2 != nil {
logging.Fatal(err2)
}
// Wenn der Artefakt ohne Argument aufgerufen wird, keinen Fehler melden, sondern im it-Modus ausführen
if cmdMissing {
endpoints_run.RunInteractive()
return
}
// Sonst Commands behandeln
if arguments.ModeHelp.Happened() {
endpoints_print.Help()
return
} else if arguments.ModeVersion.Happened() {
endpoints_print.Version()
return
} else if arguments.ModeRun.Happened() {
if arguments.InteractiveMode() {
endpoints_run.RunInteractive()
} else {
err3 = endpoints_run.RunNonInteractive(arguments.GetConfigFile())
if err3 != nil {
logging.Fatal(err3)
}
}
return
} else {
endpoints_run.RunInteractive()
}
}

View File

@ -1,54 +0,0 @@
package binary
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM binary search
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl.
Annahme: L sei aufsteigend sortiert.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
*/
func BinarySearch(L []int, x int) int {
if len(L) == 0 {
logging.Debug("x nicht in L.")
return -1
}
metrics.AddTimeCost()
m := int(len(L) / 2)
if L[m] == x {
logging.Debug("Suche in %v .. %v; m = %v; L[m] = x ==> Element gefunden.", 0, len(L)-1, m)
return m
} else if len(L) == 1 {
logging.Debug("L enthält 1 Element; L[m] =/= x; ==> x nicht in L.")
return -1
} else if x < L[m] {
logging.Debug("Suche in %v .. %v; m = %v; L[m] = %v > x ==> Suche in linker Hälfte fortsetzen.", 0, len(L)-1, m, L[m])
index := BinarySearch(L[:m], x)
return index
} else { // } else if x > L[m] {
logging.Debug("Suche in %v .. %v; m = %v; L[m] = %v < x ==> Suche in rechter Hälfte fortsetzen.", 0, len(L)-1, m, L[m])
index := BinarySearch(L[m+1:], x)
if index == -1 {
return -1 // wenn nicht gefunden
}
return index + (m + 1) // NOTE: muss Indexwert kompensieren
}
}

View File

@ -1,106 +0,0 @@
package binary
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
if !utils.IsSortedListInt(L) {
return fmt.Errorf("Ungültiger Input: L muss aufsteigend sortiert sein!")
}
return nil
}
func postChecks(L []int, x int, index int, _ ...interface{}) error {
if utils.ArrayContains(L, x) {
if !(index >= 0) {
return fmt.Errorf("Der Algorithmus sollte nicht -1 zurückgeben.")
}
if L[index] != x {
return fmt.Errorf("Der Algorithmus hat den falschen Index bestimmt.")
}
} else {
if index != -1 {
return fmt.Errorf("Der Algorithmus sollte -1 zurückgeben.")
}
}
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM binary search + Display
* ---------------------------------------------------------------- */
func FancyBinarySearch(input_L []int, input_x int) (int, error) {
var name = "Binärsuchalgorithmus"
var inputs = map[string]interface{}{
"L": input_L,
"x": input_x,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_x)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = BinarySearch(input_L, input_x)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_x, output_index)
if err != nil {
break
}
}
}
return output_index, err
}

View File

@ -1,67 +0,0 @@
package interpol
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"math"
"ads/internal/core/logging"
"ads/internal/core/metrics"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM interpolation
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl.
Annahme: L sei aufsteigend sortiert.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
*/
func InterpolationSearch(L []int, x int, u int, v int) int {
if len(L) == 0 {
logging.Debug("Liste L leer, also x nicht in L")
return -1
} else if !(L[u] <= x && x <= L[v]) {
logging.Debug("x liegt außerhalb der Grenzen von L")
return -1
}
metrics.AddTimeCost()
p := getSuchposition(L, x, u, v)
if L[p] == x {
logging.Debug("Interpolante in (%[1]v, %[2]v) ist p = %[3]v; L[p] == x; ===> Element gefunden", u, v, p)
return p
} else if x < L[p] {
logging.Debug("Interpolante in (%[1]v, %[2]v) ist p = %[3]v; L[p] > x; ===> suche in linker Hälfte", u, v, p)
return InterpolationSearch(L, x, u, p-1)
} else { // } else if x > L[p] {
logging.Debug("Interpolante in (%[1]v, %[2]v) ist p = %[3]v; L[p] < x; ===> suche in rechter Hälfte", u, v, p)
return InterpolationSearch(L, x, p+1, v)
}
}
/* ---------------------------------------------------------------- *
* ALGORITHM interpolation
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl, [u, v] = Suchinterval.
Outputs: Interpolierte Position, um Suchinterval ausgeglichen aufzuteilen.
*/
func getSuchposition(L []int, x int, u int, v int) int {
metrics.AddTimeCost()
r := float64(x-L[u]) / float64(L[v]-L[u])
p := int(math.Floor(float64(u) + r*float64(v-u)))
return p
}

View File

@ -1,108 +0,0 @@
package interpol
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
if !utils.IsSortedListInt(L) {
return fmt.Errorf("Ungültiger Input: L muss aufsteigend sortiert sein!")
}
return nil
}
func postChecks(L []int, x int, index int, _ ...interface{}) error {
if utils.ArrayContains(L, x) {
if !(index >= 0) {
return fmt.Errorf("Der Algorithmus sollte nicht -1 zurückgeben.")
}
if L[index] != x {
return fmt.Errorf("Der Algorithmus hat den falschen Index bestimmt.")
}
} else {
if index != -1 {
return fmt.Errorf("Der Algorithmus sollte -1 zurückgeben.")
}
}
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM interpolation + Display
* ---------------------------------------------------------------- */
func FancyInterpolationSearch(input_L []int, input_x int, input_u int, input_v int) (int, error) {
var name = "Interpolationssuchalgorithmus"
var inputs = map[string]interface{}{
"L": input_L,
"x": input_x,
"u": input_u,
"v": input_v,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_x, input_u, input_v)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = InterpolationSearch(input_L, input_x, input_u, input_v)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_x, output_index)
if err != nil {
break
}
}
}
return output_index, err
}

View File

@ -1,94 +0,0 @@
package ith_element
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM find ith smallest
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, i = Ordinalzahl
Annahmen:
- L enthält keine Duplikate.
- L enthält mindestens i Elemente.
Outputs: Wert des i. kleinste Element in L.
Beachte 1.kleinstes <==> Minimum.
*/
func FindIthSmallest(L []int, i int) int {
n := len(L)
// extrahiere Wert + Index des Minimums - bedarf n Schritte
metrics.AddTimeCost(n)
index := utils.ArgMinInt(L)
minValue := L[index]
// Falls i = 1, dann wird das Minimum gesucht, sonst Minimum entfernen und nach i-1. Element suchen
if i == 1 {
logging.Debug("Das i. kleinste Element wurde gefunden.")
return minValue
} else {
logging.Debug("Entferne Minimum: %[1]v.", minValue)
i = i - 1
L_ := utils.PopIndexListInt(L, index) // entferne Element mit Index = index
return FindIthSmallest(L_, i)
}
}
/* ---------------------------------------------------------------- *
* ALGORITHM find ith smallest (D & C)
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, i = Ordinalzahl
Annahmen:
- L enthält keine Duplikate.
- L enthält mindestens i Elemente.
Outputs: Wert des i. kleinste Element in L.
Beachte 1.kleinstes <==> Minimum.
*/
func FindIthSmallestDC(L []int, i int) int {
metrics.AddTimeCost()
p := L[len(L)-1] // NOTE: Pivotelement kann beliebig gewählt werden
// Werte in L in linke und rechte Teillisten um das Pivotelement aufteilen:
Ll := []int{} // wird alle Elemente in L < p enthalten
Lr := []int{} // wird alle Elemente in L > p enthalten
for i := 0; i < len(L); i++ {
x := L[i]
if x < p {
Ll = append(Ll, x)
} else if x > p {
Lr = append(Lr, x)
}
}
// Fallunterscheidung:
if len(Ll) == i-1 {
logging.Debug("Es gibt i-1 Elemente vor p=%[1]v. ==> i. kleinste Element = p", p)
return p
} else if len(Ll) >= i {
logging.Debug("Es gibt >= i Elemente vor p=%[1]v. ==> Suche in linker Hälfte!", p)
return FindIthSmallestDC(Ll, i)
} else {
logging.Debug("Es gibt < i-1 Elemente vor p=%[1]v. ==> Suche in rechter Hälfte!", p)
i = i - (len(Ll) + 1)
return FindIthSmallestDC(Lr, i)
}
}

View File

@ -1,163 +0,0 @@
package ith_element
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"sort"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, i int, _ ...interface{}) error {
if !(1 <= i && i <= len(L)) {
return fmt.Errorf("Der Wert von i muss zw. %[1]v und %[2]v liegen.", 1, len(L))
} else if !utils.ContainsNoDuplicatesListInt(L) {
return fmt.Errorf("Ungültiger Input: L darf keine Duplikate enthalten!")
}
return nil
}
func postChecks(L []int, i int, value int, _ ...interface{}) error {
L_ := make([]int, len(L))
copy(L_, L)
sort.Ints(L_)
if !(L_[i-1] == value) {
return fmt.Errorf("Das i=%[1]v. kleinste Element ist %[2]v und nicht %[3]v.", i, L_[i-1], value)
}
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM find ith smallest + Display
* ---------------------------------------------------------------- */
func FancyFindIthSmallest(input_L []int, input_i int) (int, error) {
var name = "Auswahlproblem (i. kleinstes Element)"
var inputs = map[string]interface{}{
"L": input_L,
"i": input_i,
}
var outputs map[string]interface{}
var (
output_value int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_i)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_value = FindIthSmallest(input_L, input_i)
metrics.StopMetrics()
outputs = map[string]interface{}{
"value": output_value,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_i, output_value)
if err != nil {
break
}
}
}
return output_value, err
}
/* ---------------------------------------------------------------- *
* ALGORITHM find ith smallest (D & C) + Display
* ---------------------------------------------------------------- */
func FancyFindIthSmallestDC(input_L []int, input_i int) (int, error) {
var name = "Auswahlproblem (i. kleinstes Element, D & C)"
var inputs = map[string]interface{}{
"L": input_L,
"i": input_i,
}
var outputs map[string]interface{}
var (
output_value int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_i)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_value = FindIthSmallestDC(input_L, input_i)
metrics.StopMetrics()
outputs = map[string]interface{}{
"value": output_value,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_i, output_value)
if err != nil {
break
}
}
}
return output_value, err
}

View File

@ -1,96 +0,0 @@
package jump
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/pkg/algorithms/search/sequential"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM jump search
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl, m = lineare Sprunggröße.
Annahmen:
- L sei aufsteigend sortiert.
- Idealerweise: L enthält keine Duplikate.
- Idealerweise: Abstände zw. Elementen nicht uniform.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
*/
func JumpSearchLinear(L []int, x int, m int) int {
i0 := 0
i1 := m
// ACHTUNG: dies ist eine while-Schleife ist golang:
for i0 < len(L) {
metrics.AddTimeCost()
if i1 > len(L) {
i1 = len(L)
}
block := L[i0:i1]
elementAfterBlock := block[len(block)-1] + 1
if x < elementAfterBlock {
logging.Debug("Element muss sich im Block [%[1]v, %[2]v) befinden.", i0, i1)
index := sequential.SequentialSearch(block, x)
if index == -1 {
return -1 // wenn nicht gefunden
}
return index + i0 // NOTE: muss wegen Offset kompensieren
}
logging.Debug("Element befindet sich nicht im Block [%[1]v, %[2]v).", i0, i1)
i0 = i1
i1 += m
}
return -1
}
/* ---------------------------------------------------------------- *
* ALGORITHM jump search - exponentiell
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl.
Annahmen:
- L sei aufsteigend sortiert.
- L enthält keine Duplikate.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
*/
func JumpSearchExponentiell(L []int, x int) int {
i0 := 0
i1 := 1
// ACHTUNG: dies ist eine while-Schleife ist golang:
for i0 < len(L) {
metrics.AddTimeCost()
if i1 > len(L) {
i1 = len(L)
}
block := L[i0:i1]
elementAfterBlock := block[len(block)-1] + 1
if x < elementAfterBlock {
logging.Debug("Element muss sich im Block [%[1]v, %[2]v) befinden.", i0, i1)
index := sequential.SequentialSearch(block, x)
if index == -1 {
return -1 // wenn nicht gefunden
}
return index + i0 // NOTE: muss wegen Offset kompensieren
}
logging.Debug("Element befindet sich nicht im Block [%[1]v, %[2]v).", i0, i1)
i0 = i1
i1 *= 2
}
return -1
}

View File

@ -1,168 +0,0 @@
package jump
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
if !utils.IsSortedListInt(L) {
return fmt.Errorf("Ungültiger Input: L muss aufsteigend sortiert sein!")
}
// NOTE: nicht prüfen, ob Duplikate existieren. Das ist nur eine erwünschte aber keine notwendige Annahme.
return nil
}
func postChecks(L []int, x int, index int, _ ...interface{}) error {
if utils.ArrayContains(L, x) {
if !(index >= 0) {
return fmt.Errorf("Der Algorithmus sollte nicht -1 zurückgeben.")
}
if L[index] != x {
return fmt.Errorf("Der Algorithmus hat den falschen Index bestimmt.")
}
} else {
if index != -1 {
return fmt.Errorf("Der Algorithmus sollte -1 zurückgeben.")
}
}
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM jump search + Display
* ---------------------------------------------------------------- */
func FancyJumpSearchLinear(input_L []int, input_x int, input_m int) (int, error) {
var name = "Sprungsuche"
var inputs = map[string]interface{}{
"L": input_L,
"x": input_x,
"m": input_m,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_x, input_m)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = JumpSearchLinear(input_L, input_x, input_m)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_x, output_index)
if err != nil {
break
}
}
}
return output_index, err
}
/* ---------------------------------------------------------------- *
* ALGORITHM jump search - exponentiell + Display
* ---------------------------------------------------------------- */
func FancyJumpSearchExponentiell(input_L []int, input_x int) (int, error) {
var name = "Sprungsuche (exponentiell)"
var inputs = map[string]interface{}{
"L": input_L,
"x": input_x,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_x)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = JumpSearchExponentiell(input_L, input_x)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_x, output_index)
if err != nil {
break
}
}
}
return output_index, err
}

View File

@ -1,171 +0,0 @@
package poison
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
//
/* ---------------------------------------------------------------- *
* ALGORITHM find poison
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
Inputs: L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
Annahme: Genau ein Getränk sei vergiftet.
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
*/
func FindPoison(L []int) int {
logging.Debug("Bereite Vorkoster vor")
n := len(L)
testers := [][]int{}
for i := 0; i < n; i++ {
metrics.AddSpaceCost()
logging.Debug("Füge Vorkoster hinzu, der nur Getränk %[1]v testet.", i)
testers = append(testers, []int{i})
}
logging.Debug("Warte auf Effekte")
effects := waitForEffects(L, testers)
logging.Debug("Effekte auswerten, um vergiftete Getränke zu lokalisieren.")
poisened := evaluateEffects(testers, effects)
if len(poisened) > 0 {
return poisened[0]
}
return -1
}
/* ---------------------------------------------------------------- *
* ALGORITHM find poison fast
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
Inputs: L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
Annahme: Genau ein Getränk sei vergiftet.
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
*/
func FindPoisonFast(L []int) int {
logging.Debug("Bereite Vorkoster vor")
n := len(L)
p := utils.LengthOfBinary(n)
testers := [][]int{}
// Für jedes Bit i=0 bis p-1 ...
for i := 0; i < p; i++ {
tester0 := []int{}
tester1 := []int{}
for k := 0; k < n; k++ {
if utils.NthBit(k, i) == 0 {
tester0 = append(tester0, k)
} else {
tester1 = append(tester1, k)
}
}
/*
* NOTE: tester1 ist virtuell: aus den Effekten auf tester0 und den Annahmen
* lassen sich die Effekte auf tester0 erschließen.
* Darum zählen wir nicht 2 sondern 1 Vorkoster.
*/
metrics.AddSpaceCost(1)
logging.Debug("Füge Vorkoster hinzu, der alle Getränke k testet mit %[1]v. Bit von k = 0.", i)
testers = append(testers, tester0)
testers = append(testers, tester1)
}
logging.Debug("Warte auf Effekte")
effects := waitForEffects(L, testers)
logging.Debug("Effekte auswerten, um vergiftete Getränke zu lokalisieren.")
poisened := evaluateEffects(testers, effects)
if len(poisened) > 0 {
return poisened[0]
}
return -1
}
/* ---------------------------------------------------------------- *
* AUXILIARY METHOD wait for effects, evaluate effects
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
Inputs:
- L = Liste von Getränken: durch boolesche Werte wird dargestellt, ob ein Getränk vergiftet ist.
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
Outputs: effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
*/
func waitForEffects(L []int, testers [][]int) []int {
m := len(testers)
effects := make([]int, m)
for i, tester := range testers {
effect := 0
for _, k := range tester {
effect += L[k]
}
effects[i] = effect
}
return effects
}
/*
Inputs:
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
- effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
Annahmen: Vorkoster wurden so angewiesen, dass es garantiert ist, vergiftete Getränke zu finden, wenn es die gibt.
Outputs: Liste der Indexes aller vergifteten Getränke.
*/
func evaluateEffects(testers [][]int, effects []int) []int {
var states = map[int]bool{}
var poisened = []int{}
// Werte Effekte aus, um Gift zu lokalisieren:
// Zuerst die Indexes der Getränke bei allen vergifteten Tester zusammenführen:
for i, tester := range testers {
// wenn Tester positiv testet, dann ist eines der von ihm probierten Getränks vergiftet
if effects[i] > 0 {
// markiere alle vom Tester probierten Getränke
for _, k := range tester {
states[k] = true
}
}
}
// jetzt eliminieren wir alle Getränke, die von nicht vergifteten Testern konsumiert wurden:
for i, tester := range testers {
// wenn Tester negativ testet, dann ist KEINES der von ihm probierten Getränks vergiftet
if effects[i] == 0 {
// schließe alle vom Tester probierten Getränke aus
for _, k := range tester {
states[k] = false
}
}
}
// was übrig bleibt sind die vergifteten Getränke, vorausgesetzt genug Vorkoster wurden ausgewählt
for k, state := range states {
if state {
poisened = append(poisened, k)
}
}
return poisened
}

View File

@ -1,160 +0,0 @@
package poison
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
func preChecks(L []int, _ ...interface{}) error {
s := utils.SumListInt(L)
if !(s > 0) {
return fmt.Errorf("Mindestens ein Getränk muss vergiftet sein!")
} else if !(s <= 1) {
return fmt.Errorf("Höchstens ein Getränk darf vergiftet sein!")
}
return nil
}
func postChecks(L []int, index int, _ ...interface{}) error {
if !(index >= 0) {
return fmt.Errorf("Der Algorithmus hat kein vergiftetes Getränk gefunden, obwohl per Annahme eines existiert.")
} else if !(L[index] > 0) {
return fmt.Errorf("Der Algorithmus hat das vergiftete Getränk nicht erfolgreich bestimmt.")
}
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM find poison + Display
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
func FancyFindPoison(input_L []int) (int, error) {
var name = "Giftsuche (O(n) Vorkoster)"
var inputs = map[string]interface{}{
"L": input_L,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = FindPoison(input_L)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, output_index)
if err != nil {
break
}
}
}
return output_index, err
}
/* ---------------------------------------------------------------- *
* ALGORITHM find poison fast + Display
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
func FancyFindPoisonFast(input_L []int) (int, error) {
var name = "Giftsuche (O(log(n)) Vorkoster)"
var inputs = map[string]interface{}{
"L": input_L,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = FindPoisonFast(input_L)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, output_index)
if err != nil {
break
}
}
}
return output_index, err
}

View File

@ -1,37 +0,0 @@
package sequential
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM sequential search
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen, x = Zahl.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
*/
func SequentialSearch(L []int, x int) int {
n := len(L)
for i := 0; i < n; i++ {
metrics.AddTimeCost()
if L[i] == x {
logging.Debug("Element in Position %[1]v gefunden.", i)
return i
}
logging.Debug("Element nicht in Position %[1]v.", i)
}
return -1
}

View File

@ -1,104 +0,0 @@
package sequential
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/core/utils"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
// Keine Checks!
return nil
}
func postChecks(L []int, x int, index int, _ ...interface{}) error {
if utils.ArrayContains(L, x) {
if !(index >= 0) {
return fmt.Errorf("Der Algorithmus sollte nicht -1 zurückgeben.")
}
if L[index] != x {
return fmt.Errorf("Der Algorithmus hat den falschen Index bestimmt.")
}
} else {
if index != -1 {
return fmt.Errorf("Der Algorithmus sollte -1 zurückgeben.")
}
}
return nil
}
/* ---------------------------------------------------------------- *
* METHOD sequential search + Display
* ---------------------------------------------------------------- */
func FancySequentialSearch(input_L []int, input_x int) (int, error) {
var name = "Sequenziellsuchalgorithmus"
var inputs = map[string]interface{}{
"L": input_L,
"x": input_x,
}
var outputs map[string]interface{}
var (
output_index int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L, input_x)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_index = SequentialSearch(input_L, input_x)
metrics.StopMetrics()
outputs = map[string]interface{}{
"index": output_index,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, input_x, output_index)
if err != nil {
break
}
}
}
return output_index, err
}

View File

@ -1,81 +0,0 @@
package next_greater_element
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/pkg/data_structures/stacks"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM next greater element
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen.
Outputs: Liste von Paaren von Elementen und ihrem nächsten größeren Element
*/
func NextGreaterElement(L []int) [][2]int {
output := [][2]int{}
S := stacks.CREATE()
S.INIT()
for i := 0; i < len(L); i++ {
logging.Debug("Stack S | %v", S)
logging.Debug("Nächstes List-Element L[%v] = %v betrachten", i, L[i])
nextElement := L[i]
logging.Debug("Alle top Elemente vom Stack, die < nextElement sind, mit L[i] paaren")
// Führe aus, bis top Element >= nextElement oder Stack leer ist.
for !S.EMPTY() { // ACHTUNG: schreibe 'while' im Pseudocode, denn dies ist eine while-Schleife in golang
element := S.TOP()
if element < nextElement {
// falls top Element < next Element, zum Output hinzufügen und vom Stack entfernen
logging.Debug("Stack S | %v; top Element < nextElement; ==> pop und Paar zum Output hinzufügen", S)
output = append(output, [2]int{element, nextElement})
S.POP()
metrics.AddMovesCost()
logging.Debug("Stack S | %v", S)
} else if element > nextElement {
// falls top Element > next Element, auf Stack lassen und Schleife abbrechen.
break
} else {
// falls top Element == next Element, vom Stack entfernen und Schleife abbrechen.
S.POP()
metrics.AddMovesCost()
break
}
}
logging.Debug("L[%v] auf Stack legen", i)
S.PUSH(nextElement)
metrics.AddMovesCost()
}
logging.Debug("Stack S | %v", S)
// was übrig bleibt hat kein größeres Element
logging.Debug("Alles übrige auf Stack hat kein nächstes größeres Element")
for !S.EMPTY() { // ACHTUNG: schreibe 'while' im Pseudocode, denn dies ist eine while-Schleife in golang
logging.Debug("Stack S | %v", S)
element := S.TOP()
output = append(output, [2]int{element, -1})
S.POP()
metrics.AddMovesCost()
}
logging.Debug("Stack S | %v", S)
return output
}

View File

@ -1,89 +0,0 @@
package next_greater_element
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/metrics"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
// TODO
return nil
}
func postChecks(L []int, pairs [][2]int, _ ...interface{}) error {
// TODO
return nil
}
/* ---------------------------------------------------------------- *
* ALGORITHM binary search + Display
* ---------------------------------------------------------------- */
func FancyNextGreaterElement(input_L []int) ([][2]int, error) {
var name = "Next Greater Element"
var inputs = map[string]interface{}{
"L": input_L,
}
var outputs map[string]interface{}
var (
pairs [][2]int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
pairs = NextGreaterElement(input_L)
metrics.StopMetrics()
outputs = map[string]interface{}{
"pairs": pairs,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, pairs)
if err != nil {
break
}
}
}
return pairs, err
}

View File

@ -1,167 +0,0 @@
package maxsubsum
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM max sub sum
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
*/
func MaxSubSum(L []int) (int, int, int) {
maxSum := 0
u := 0
v := -1
for i := 0; i < len(L); i++ {
// Bestimme maximale Teilsumme der linken Rände der Liste ab Index i {
maxSum_, _, k := lRandSum(L[i:])
if maxSum_ > maxSum {
k += i // NOTE: muss wegen Offset kompensieren
maxSum, u, v = maxSum_, i, k
logging.Debug("max Teilsumme aktualisiert: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
}
}
return maxSum, u, v
}
/* ---------------------------------------------------------------- *
* ALGORITHM max sub sum (D & C)
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
*/
func MaxSubSumDC(L []int) (int, int, int) {
maxSum := 0
u := 0
v := -1
if len(L) == 1 {
// wenn Liste aus 1 Element besteht, nicht teilen:
if L[0] > maxSum {
v = 0
maxSum = L[0]
}
} else {
u = utils.Ceil(float64(len(L)) / 2)
Ll := L[:u]
Lr := L[u:]
// berechnet maximale Teilsumme der linken Hälfte:
maxSum1, u1, v1 := MaxSubSumDC(Ll)
// berechnet maximale Teilsumme der rechten Hälfte:
maxSum2, u2, v2 := MaxSubSumDC(Lr)
u2, v2 = u2+len(Ll), v2+len(Ll) // offsets kompensieren
// berechnet maximale Teilsumme mit Überschneidung zw. den Hälften:
maxSum3, u3, v3 := lrRandSum(Ll, Lr)
// bestimme Maximum der 3 Möglichkeiten:
maxSum = utils.MaxInt(maxSum1, maxSum2, maxSum3)
if maxSum == maxSum1 {
maxSum, u, v = maxSum1, u1, v1
logging.Debug("max Teilsumme kommt in linker Partition vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
} else if maxSum == maxSum3 {
maxSum, u, v = maxSum3, u3, v3
logging.Debug("max Teilsumme kommt in Überschneidung vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
} else { // } else if maxSum == maxSum2 {
maxSum, u, v = maxSum2, u2, v2
logging.Debug("max Teilsumme kommt in rechter Partition vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
}
}
return maxSum, u, v
}
/* ---------------------------------------------------------------- *
* AUXILIARY METHODS
* ---------------------------------------------------------------- */
/*
Bestimmt maximale Teilsumme einer Teiliste einer Liste,
wobei die Liste in zwei Intervalle partitioniert ist
und die Teilliste beide überschneidet.
Inputs: Ll, Lr = eine Partition einer Liste von Zahlen in zwei Intervalle
Outputs: maxSum, u=0, v
*/
func lrRandSum(Ll []int, Lr []int) (int, int, int) {
maxSumL, u, _ := rRandSum(Ll)
maxSumR, _, v := lRandSum(Lr)
maxSum := maxSumL + maxSumR
v += len(Ll) // offsets kompensieren
return maxSum, u, v
}
/*
Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u(=0), v
*/
func lRandSum(L []int) (int, int, int) {
n := len(L)
// berechne kumulative Summen (vorwärts)
metrics.AddTimeCost(n)
total := L[0]
maxSum := total
u := 0
v := 0
for i := 0; i < n; i++ {
total += L[i]
if total > maxSum {
v = i
maxSum = total
}
}
return maxSum, u, v
}
/*
Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u, v(=len(L)-1)
*/
func rRandSum(L []int) (int, int, int) {
n := len(L)
// berechne kumulative Summen (rückwärts)
metrics.AddTimeCost(n)
total := L[n-1]
maxSum := total
u := n - 1
v := n - 1
for i := n - 2; i >= 0; i-- {
total += L[i]
if total > maxSum {
u = i
maxSum = total
}
}
return maxSum, u, v
}

View File

@ -1,160 +0,0 @@
package maxsubsum
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"ads/internal/core/metrics"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* CHECKS
* ---------------------------------------------------------------- */
func preChecks(L []int, _ ...interface{}) error {
if !(len(L) > 0) {
return fmt.Errorf("Liste darf nicht leer sein.")
}
return nil
}
func postChecks(L []int, _ ...interface{}) error {
// TODO
return nil
}
/* ---------------------------------------------------------------- *
* METHOD Algorithm + Display
* ---------------------------------------------------------------- */
func FancyMaxSubSum(input_L []int) (int, int, int, error) {
var name = "MaxSubSum (Maximale Teilsumme)"
var inputs = map[string]interface{}{
"L": input_L,
}
var outputs map[string]interface{}
var (
output_maxSum int
output_indexFrom int
output_indexTo int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_maxSum, output_indexFrom, output_indexTo = MaxSubSum(input_L)
metrics.StopMetrics()
outputs = map[string]interface{}{
"maxSum": output_maxSum,
"index_from": output_indexFrom,
"index_to": output_indexTo,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, output_maxSum, output_indexFrom, output_indexTo)
if err != nil {
break
}
}
}
return output_maxSum, output_indexFrom, output_indexTo, err
}
/* ---------------------------------------------------------------- *
* ALGORITHM max sub sum (D & C)
* ---------------------------------------------------------------- */
func FancyMaxSubSumDC(input_L []int) (int, int, int, error) {
var name = "MaxSubSum (Maximale Teilsumme mit D & C)"
var inputs = map[string]interface{}{
"L": input_L,
}
var outputs map[string]interface{}
var (
output_maxSum int
output_indexFrom int
output_indexTo int
)
var err error
do_once := true
for do_once {
do_once = false
// Start Message
setup.DisplayStartOfAlgorithm(name, inputs)
// Prechecks:
if setup.AppConfigPerformChecks() {
err = preChecks(input_L)
if err != nil {
break
}
}
// Ausführung des Algorithmus:
metrics.ResetMetrics()
metrics.StartMetrics()
output_maxSum, output_indexFrom, output_indexTo = MaxSubSumDC(input_L)
metrics.StopMetrics()
outputs = map[string]interface{}{
"maxSum": output_maxSum,
"index_from": output_indexFrom,
"index_to": output_indexTo,
}
// Metriken anzeigen
if setup.AppConfigShowMetrics() {
setup.DisplayMetrics()
}
// End Message
setup.DisplayEndOfAlgorithm(outputs)
// Postchecks:
if setup.AppConfigPerformChecks() {
err = postChecks(input_L, output_maxSum, output_indexFrom, output_indexTo)
if err != nil {
break
}
}
}
return output_maxSum, output_indexFrom, output_indexTo, err
}

View File

@ -1,81 +0,0 @@
package queues
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"strings"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* TYPE
* ---------------------------------------------------------------- */
type QueueInt struct {
values *[]int
}
/* ---------------------------------------------------------------- *
* METHODS queues
* ---------------------------------------------------------------- */
func CREATE() QueueInt {
return QueueInt{}
}
func (S *QueueInt) INIT() {
S.values = &[]int{}
}
func (S QueueInt) Length() int {
if S.values == nil {
return 0
}
return len(*S.values)
}
func (S QueueInt) String() string {
if S.EMPTY() {
return "-"
}
values := []string{}
n := S.Length()
for i := n - 1; i >= 0; i-- {
value := (*S.values)[i]
values = append(values, fmt.Sprintf("%v", value))
}
return fmt.Sprintf(strings.Join(values, " -> "))
}
func (S QueueInt) EMPTY() bool {
return S.Length() == 0
}
func (S *QueueInt) ENQUEUE(x int) {
if S.values == nil {
panic("Queue not initialised!")
}
*S.values = append(*S.values, x)
}
func (S *QueueInt) FRONT() int {
if S.EMPTY() {
panic("Cannot read from empty queue!")
}
return (*S.values)[0]
}
func (S *QueueInt) DEQUEUE() {
if S.EMPTY() {
panic("Cannot remove from empty queue!")
}
*S.values = (*S.values)[1:]
}

View File

@ -1,81 +0,0 @@
package stacks
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"strings"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* TYPE
* ---------------------------------------------------------------- */
type StackInt struct {
values *[]int
}
/* ---------------------------------------------------------------- *
* METHODS stacks
* ---------------------------------------------------------------- */
func CREATE() StackInt {
return StackInt{}
}
func (S *StackInt) INIT() {
S.values = &[]int{}
}
func (S StackInt) Length() int {
if S.values == nil {
return 0
}
return len(*S.values)
}
func (S StackInt) String() string {
if S.EMPTY() {
return "-"
}
values := []string{}
for _, value := range *S.values {
values = append(values, fmt.Sprintf("%v", value))
}
return fmt.Sprintf(strings.Join(values, ", "))
}
func (S StackInt) EMPTY() bool {
return S.Length() == 0
}
func (S *StackInt) PUSH(x int) {
if S.values == nil {
panic("Stack not initialised!")
}
*S.values = append(*S.values, x)
}
func (S *StackInt) TOP() int {
if S.EMPTY() {
panic("Cannot read from empty stack!")
}
n := S.Length()
return (*S.values)[n-1]
}
func (S *StackInt) POP() {
if S.EMPTY() {
panic("Cannot remove from empty stack!")
}
n := S.Length()
*S.values = (*S.values)[:(n - 1)]
}

View File

@ -1,62 +0,0 @@
package re
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"regexp"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
type Reader struct {
regex *regexp.Regexp
lastpattern *string
}
var defaultReader Reader = Reader{}
/* ---------------------------------------------------------------- *
* METHODS
* ---------------------------------------------------------------- */
func Matches(pattern string, text string) bool {
return defaultReader.Matches(pattern, text)
}
func Sub(pattern string, substitute string, text string) string {
return defaultReader.Sub(pattern, substitute, text)
}
func Split(pattern string, text string) []string {
return defaultReader.Split(pattern, text)
}
func (r *Reader) Matches(pattern string, text string) bool {
r.setReader(pattern)
return r.regex.MatchString(text)
}
func (r *Reader) Sub(pattern string, substitute string, text string) string {
r.setReader(pattern)
return r.regex.ReplaceAllString(text, substitute)
}
func (r *Reader) Split(pattern string, text string) []string {
r.setReader(pattern)
return r.regex.Split(text, -1)
}
/* ---------------------------------------------------------------- *
* PRIVATE MEHODS
* ---------------------------------------------------------------- */
func (r *Reader) setReader(pattern string) {
if r.regex == nil || r.lastpattern == nil || *r.lastpattern != pattern {
r.lastpattern = &pattern
r.regex = regexp.MustCompile(pattern)
}
}

View File

@ -1,4 +0,0 @@
github.com/akamensky/argparse@v1.3.1
github.com/lithammer/dedent@v1.1.0
github.com/stretchr/testify@v1.7.0
gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b

View File

@ -1,38 +0,0 @@
*
!/.gitignore
################################################################
# MAIN FOLDER
################################################################
!/Makefile
!/README.md
!/requirements
################################################################
# PROJECT FILES
################################################################
!/assets
!/assets/VERSION
!/assets/LOGO
!/assets/config.yml
!/src
!/src/**/
!/src/**/*.py
!/test
!/test/**/
!/test/**/*.py
## nicht synchronisieren:
!/build
################################################################
# ARTEFACTS
################################################################
/**/__pycache__
/**/.DS_Store
/**/__archive__*

View File

@ -1,27 +0,0 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# LOCAL ARGUMENTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PATH_TO_CONFIG:=../config.yml#<- kann durch Pfad zur eigenen yml-Datei ersetzt werden
COLOUR:=true
PYTHON:=python3
PIP:=python3 -m pip
## für Windows weichen Defaultsettings leicht ab:
ifeq ($(OS),Windows_NT)
COLOUR:=false# <- man kann als 'true' setzen, aber in Windows funktioniert es möglicherweise nicht
PYTHON:=py -3
PIP:=py -3 -m pip
endif
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
setup: # TODO: Variant mit venv
${PIP} install -r requirements;
run: # non-interactive mode mit config-datei
${PYTHON} src/main.py run --debug --colour ${COLOUR} --config "${PATH_TO_CONFIG}"
run-it: # interactive mode
${PYTHON} src/main.py run --it --debug --colour ${COLOUR}
# Do everything:
all: setup run
all-it: setup run-it

View File

@ -1,78 +0,0 @@
# ADS - Python-Projekt #
**Python** ist eine sehr verbreitete Sprache, die eine Riesencommunity hat.
Sie ist sehr populär unter Wissenschaftlern und Ingenieuren.
Ein Vorteil mit Python ist, dass man sehr leicht und schnell Prototypen entwickeln kann.
Dieses Projekt ist erneut kein nötiger Bestandteil des Kurses,
sondern nur für Wissbegierige gedacht.
Zunächst bietet sich an, sich die Algorithmen im Unterordner [`src/algorithms`](./src/algorithms) anzuschauen,
z.&nbsp;B. [`src/algorithms/search/binary.py`](./src/algorithms/search/binary.py) für den Binärsuchalgorithmus,
ohne irgendetwas installieren zu müssen.
**HINWEIS 1:** _Bei meiner Implementierung kann es zu leichten Abweichungen kommen. Bitte **stets** an dem Material im VL-Skript sich orientieren. Der Hauptzweck der Code-Projekte besteht darin, dass Wissbegierige die Algorithmen konkret ausprobieren können. Alle theoretischen Aspekte werden jedoch im Skript und in den Übungen ausführlicher erklärt._
Den Code kann man auch durch die u.&nbsp;s. Anweisungen selber austesten.
**HINWEIS 2:** _Während hier die Anweisungen ausführlich sind und klappen sollten,
bitte nur auf eigener Gewähr diesen Code benutzen._
### Systemvoraussetzungen ###
- Python version 3.x.x (idealerweise zumindest 3.9.5)
## Einrichten mittels **Makefile** ##
Führe jeweils
```bash
make setup
make run
# oder für interaktiven Modus
make run-it
```
aus, um Packages zu installieren
bzw. den Code auszuführen.
Siehe [`Makefile`](./Makefile) für Details zu den Vorgängen.
Wer Makefile benutzt kann die u.&nbsp;s. Anweisungen ignorieren.
## Setup ##
Requirements (Packages) einmalig mittels
```bash
python3 -m pip install -r requirements; # linux, osx
py -3 -m pip install -r requirements; # Windows
```
installieren lassen.
## Ausführung ##
Zum Anzeigen der Hilfsanleitung in einer Konsole folgenden Befehl ausführen
```bash
python3 src/main.py help; # linux, OSX
py -3 src/main.py help; # Windows
```
Zur Ausführung der Algorithmen auf Fälle in der [Config-Datei](./../config.yml)
in einer Konsole folgenden Befehl ausführen
```bash
python3 src/main.py run; # linux, OSX
py -3 src/main.py run; # Windows
```
Mit dem `--debug` Flag werden Infos über Schritte mit angezeigt.
</br>
Mit dem `--colour true/false` Argument wird der Farbenmodus ein-/ausgeschaltet.
</br>
Mit dem `--config path/to/config` Argument kann man andere Config-Dateien verwenden.
## Entwicklung ##
Gerne kann man den Code benutzen, in einem eigenen Repository weiter entwickeln,
und mit den im Kurs präsentierten Algorithmen und Fällen herumexperimentieren.

View File

@ -1,3 +0,0 @@
+--------------------+
| \033[32;1mAlgoDat I\033[0m |
+--------------------+

View File

@ -1 +0,0 @@
0.0.0

View File

@ -1,7 +0,0 @@
info:
title: "App für ADS1"
description: "Interne Configurationsdatei"
options:
display: true
checks: false
metrics: true

View File

@ -1,4 +0,0 @@
pip>=21.3.1
argparse>=1.4.0
pyyaml>=5.4.1
typing>=3.7.4.3

View File

@ -1,42 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# NOTE: This file is needed in addition to main.py
# for the creation of an artefact.
# It is stored one level higher than src.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import os;
import sys;
sys.path.insert(0, os.path.abspath(os.path.join(os.path.abspath(__file__), '..')));
from src.setup.cli import *;
from src.endpoints.exports import *;
from src.main import enter;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXECUTION
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == '__main__':
sys.tracebacklimit = 0;
try:
args = GetArgumentsFromCli(*sys.argv[1:]);
except:
endpoint_help();
exit(1);
enter(
mode=args.mode,
it=args.it,
quiet=args.quiet,
debug=args.debug,
checks=args.checks,
colour=args.colour,
config=args.config,
);

View File

@ -1,10 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.algorithms.search.exports import *;
from src.algorithms.stacks.exports import *;
from src.algorithms.sum.exports import *;

View File

@ -1,99 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import functools
from src.core.log import *;
from src.setup import appconfig;
from src.core.metrics import *;
from src.setup.display import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASSES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class OneShot(object):
state: bool;
def __init__(self):
self.state = True;
def setState(self, state: bool):
self.state = state;
def reload(self):
self.state = True;
def trigger(self):
self.state = False;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DECORATORS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Trigger, der das fancy Zeug bei verschachtelten Algorithmen verhindert
nonnestedAlgorithms = OneShot();
def algorithmInfos(
name: str,
outputnames: List[str] = ['result'],
preChecks: Any = None,
postChecks: Any = None
):
'''
Decorator für Algorithmen, der Folgendes macht:
- Zeigt vorm Start Console-Messages mit Namen des Algorithmus + Inputs.
- Zeit am Ende optional Metriken (bspw. Zeitkosten).
- Zeigt am Ende Console-Messages von Output/s.
- Prüft optional vor und nach Ausführung des Algorithmus, dass die Inputs/Outputs stimmen.
Bei rekursiven Definitionen werden die o. s. Punkte nur bei dem äußersten Aufruf gemacht.
'''
def func_decorator(func):
## Trigger, der das fancy Zeug bei verschachtelten Aufrufen verhindert
nonnestedRecursion = OneShot();
@functools.wraps(func)
def func_wrapper(**inputs):
try:
state1 = nonnestedAlgorithms.state;
state2 = nonnestedRecursion.state;
state = state1 and state2;
if state:
# Initialisierung
DisplayStartOfAlgorithm(name, **inputs);
# Prechecks
if appconfig.AppConfigPerformChecks() and callable(preChecks):
preChecks(**inputs);
# Metriken initialisieren + starten
ResetMetrics();
StartMetrics();
# Ausführung des Algorithmus:
nonnestedRecursion.trigger();
nonnestedAlgorithms.trigger();
outputs = func(*[], **inputs);
nonnestedAlgorithms.state = state1;
nonnestedRecursion.state = state2;
if state:
# Metriken anhalten
StopMetrics();
# benenne Outputs:
outputs_ = outputs if isinstance(outputs, tuple) else tuple([outputs]);
outputsNamed = { outputnames[k]: value for k, value in enumerate(outputs_) };
# Letzte Messages
if appconfig.AppConfigShowMetrics():
DisplayMetrics();
DisplayEndOfAlgorithm(**outputsNamed);
# Postchecks
if appconfig.AppConfigPerformChecks() and callable(postChecks):
postChecks(**inputs, **outputsNamed);
except Exception as e:
nonnestedAlgorithms.state = state1;
nonnestedRecursion.state = state2;
raise e;
return outputs;
return func_wrapper;
return func_decorator;

View File

@ -1,66 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
assert L == sorted(L), 'Ungültiger Input: L muss aufsteigend sortiert sein!';
return;
def postChecks(L: List[int], x: int, index: int, **_):
if x in L:
assert index >= 0, 'Der Algorithmus sollte nicht -1 zurückgeben.';
assert L[index] == x, 'Der Algorithmus hat den falschen Index bestimmt.';
else:
assert index == -1, 'Der Algorithmus sollte -1 zurückgeben.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM binary search
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Binärsuchalgorithmus', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def BinarySearch(L: List[int], x: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl.
Annahme: L sei aufsteigend sortiert.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
'''
if len(L) == 0:
logDebug('x nicht in L');
return -1;
AddTimeCost();
m = math.floor(len(L)/2);
if L[m] == x:
logDebug('x in Position m gefunden');
return m;
elif x < L[m]:
logDebug('Suche in linker Hälfte fortsetzen.');
index = BinarySearch(L=L[:m], x=x);
return index;
else: # x > L[m]
logDebug('Suche in rechter Hälfte fortsetzen.');
index = BinarySearch(L=L[m+1:], x=x);
if index >= 0:
index += (m + 1); # NOTE: muss Indexwert kompensieren
return index;

View File

@ -1,16 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.search.binary import BinarySearch;
from src.algorithms.search.interpol import InterpolationSearch;
from src.algorithms.search.jump import JumpSearchLinear;
from src.algorithms.search.jump import JumpSearchExponentiell;
from src.algorithms.search.ith_smallest import FindIthSmallest;
from src.algorithms.search.ith_smallest import FindIthSmallestDC;
from src.algorithms.search.poison import FindPoison;
from src.algorithms.search.poison import FindPoisonFast;

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
assert L == sorted(L), 'Ungültiger Input: L muss aufsteigend sortiert sein!';
return;
def postChecks(L: List[int], x: int, index: int, **_):
if x in L:
assert index >= 0, 'Der Algorithmus sollte nicht -1 zurückgeben.';
assert L[index] == x, 'Der Algorithmus hat den falschen Index bestimmt.';
else:
assert index == -1, 'Der Algorithmus sollte -1 zurückgeben.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM interpolation
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Interpolationssuchalgorithmus', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def InterpolationSearch(L: List[int], x: int, u: int, v: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl, [u, v] = Suchinterval.
Annahme: L sei aufsteigend sortiert.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
'''
if not(L[u] <= x and x <= L[v]):
logDebug('Element kann sich nicht in der Liste befinden!')
return -1;
p = getSuchposition(L=L, x=x, u=u, v=v);
logDebug('Interpolante von x in (u, v)={uv} ist p = {p}.'.format(uv=(u, v), p=p));
if L[p] == x:
logDebug('x in Position p gefunden');
return p;
elif x > L[p]:
logDebug('Suche in rechter Hälfte fortsetzen.');
return InterpolationSearch(L=L, x=x, u=p+1, v=v);
else: # x < L[p]
logDebug('Suche in linker Hälfte fortsetzen.');
return InterpolationSearch(L=L, x=x, u=u, v=p-1);
def getSuchposition(L: List[int], x: int, u: int, v: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl, [u, v] = Suchinterval.
Outputs: Interpolierte Position, um Suchinterval ausgeglichen aufzuteilen.
'''
AddTimeCost();
r = (x - L[u])/(L[v]-L[u]);
p = math.floor(u + r*(v-u))
return p;

View File

@ -1,97 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], i: int, **_):
assert 1 <= i and i <= len(L), 'Der Wert von i muss zw. {lb} und {ub} liegen.'.format(lb = 1, ub = len(L));
assert sorted(L) == sorted(list(set(L))), 'Ungültiger Input: L darf keine Duplikate enthalten!';
return;
def postChecks(L: List[int], i: int, value: int, **_):
L = sorted(L);
assert L[i-1] == value, 'Der Algorithmus hat versagt.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM find ith smallest element
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Auswahlproblem (i. kleinstes Element)', outputnames=['value'], preChecks=preChecks, postChecks=postChecks)
def FindIthSmallest(L: List[int], i: int) -> int:
'''
Inputs: L = Liste von Zahlen, i = Ordinalzahl
Annahmen:
- L enthält keine Duplikate.
- L enthält mindestens i Elemente.
Outputs: Wert des i. kleinste Element in L.
Beachte 1.kleinstes <==> Minimum.
'''
index = 0;
minValue = L[0];
AddTimeCost(len(L));
for i_ in range(1, len(L)):
if L[i_] < minValue:
index = i_;
minValue = L[i_];
if i == 1:
logDebug('Das i. kleinste Element wurde gefunden.');
return minValue;
else:
logDebug('Entfernte Minimum: {value}.'.format(value = minValue));
i = i - 1;
return FindIthSmallest(L=L[:index] + L[(index+1):], i=i);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM find ith smallest element (D & C)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Auswahlproblem (i. kleinstes Element, D & C)', outputnames=['value'], preChecks=preChecks, postChecks=postChecks)
def FindIthSmallestDC(L: List[int], i: int) -> int:
'''
Inputs: L = Liste von Zahlen, i = Ordinalzahl
Annahmen:
- L enthält keine Duplikate.
- L enthält mindestens i Elemente.
Outputs: Wert des i. kleinste Element in L.
Beachte 1.kleinstes <==> Minimum.
'''
AddTimeCost();
p = L[len(L)-1]; # NOTE: Pivotelement kann beliebig gewählt werden
Ll = [ x for x in L if x < p ];
Lr = [ x for x in L if x > p ];
if len(Ll) == i - 1:
logDebug('Es gibt i-1 Elemente vor p={p}. ==> i. kleinste Element = p'.format(p=p));
return p;
elif len(Ll) >= i:
logDebug('Es gibt >= i Elemente vor p={p}. ==> Suche in linker Hälfte!'.format(p=p));
return FindIthSmallestDC(L=Ll, i=i);
else:
i = i - (len(Ll) + 1)
logDebug('Es gibt < i-1 Elemente vor p={p}. ==> Suche in rechter Hälfte!'.format(p=p));
return FindIthSmallestDC(L=Lr, i=i);

View File

@ -1,101 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
assert L == sorted(L), 'Ungültiger Input: L muss aufsteigend sortiert sein!';
## NOTE: nicht prüfen, ob Duplikate existieren. Das ist nur eine erwünschte aber keine notwendige Annahme.
return;
def postChecks(L: List[int], x: int, index: int, **_):
if x in L:
assert index >= 0, 'Der Algorithmus sollte nicht -1 zurückgeben.';
assert L[index] == x, 'Der Algorithmus hat den falschen Index bestimmt.';
else:
assert index == -1, 'Der Algorithmus sollte -1 zurückgeben.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM jump search
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Sprungsuche', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def JumpSearchLinear(L: List[int], x: int, m: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl, m = lineare Sprunggröße.
Annahmen:
- L sei aufsteigend sortiert.
- Idealerweise: L enthält keine Duplikate.
- Idealerweise: Abstände zw. Elementen nicht uniform.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
'''
i = 0;
while i*m < len(L):
AddTimeCost();
offset = i*m;
block = L[offset:][:m];
elementAfterBlock = block[-1] + 1;
if x < elementAfterBlock:
logDebug('Element muss sich im Block [{i0}, {i1}) befinden.'.format(i0 = i*m, i1 = (i+1)*m));
index = SequentialSearch(L=block, x=x);
if index >= 0:
index += offset; # NOTE: muss wegen Offset kompensieren
return index;
logDebug('Element befindet sich nicht im im Block [{i0}, {i1}) befinden.'.format(i0 = i*m, i1 = (i+1)*m));
i += 1;
return -1;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM jump search - exponentiell
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Sprungsuche (exponentiell)', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def JumpSearchExponentiell(L: List[int], x: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl.
Annahmen:
- L sei aufsteigend sortiert.
- Idealerweise: L enthält keine Duplikate.
- Idealerweise: Abstände zw. Elementen nicht uniform.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
'''
i0 = 0;
i1 = 1;
while i0 < len(L):
AddTimeCost();
block = L[i0:i1];
elementAfterBlock = block[-1] + 1;
if x < elementAfterBlock:
logDebug('Element muss sich im Block [{i0}, {i1}) befinden.'.format(i0 = i0, i1 = i1));
index = SequentialSearch(L=block, x=x);
if index >= 0:
index += i0; # NOTE: muss wegen Offset kompensieren
return index;
logDebug('Element befindet sich nicht im Block [{i0}, {i1}) befinden.'.format(i0 = i0, i1 = i1));
i0 = i1;
i1 *= 2;
return -1;

View File

@ -1,147 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
s = sum(L);
assert s > 0, 'Mindestens ein Getränk muss vergiftet sein!';
assert s <= 1, 'Höchstens ein Getränk darf vergiftet sein!';
return;
def postChecks(L: List[int], index: int, **_):
assert index >= 0, 'Der Algorithmus hat kein vergiftetes Getränk gefunden, obwohl per Annahme eines existiert.';
assert L[index] > 0, 'Der Algorithmus hat das vergiftete Getränk nicht erfolgreich bestimmt.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM find poison
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Giftsuche (O(n) Vorkoster)', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def FindPoison(L: List[int]) -> int:
'''
Inputs: L = Liste von Getränken: durch 0-1 Werte wird dargestellt, ob ein Getränk vergiftet ist.
Annahme: Genau ein Getränk sei vergiftet.
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
'''
logDebug('Bereite Vorkoster vor');
n = len(L);
testers = [];
for i in range(n):
AddSpaceCost();
logDebug('Füge Vorkoster hinzu, der nur Getränk {i} testet.'.format(i=i))
testers.append([i]);
logDebug('Warte auf Effekte');
effects = waitForEffects(L, testers);
logDebug('Effekte auswerten, um vergiftete Getränke zu lokalisieren.');
poisened = evaluateEffects(testers, effects);
if len(poisened) > 0:
return poisened[0];
return -1;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM find poison fast
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Giftsuche (O(log(n)) Vorkoster)', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def FindPoisonFast(L: List[int]) -> int:
'''
Inputs: L = Liste von Getränken: durch 0-1 Werte wird dargestellt, ob ein Getränk vergiftet ist.
Annahme: Genau ein Getränk sei vergiftet.
Outputs: Der Index des vergifteten Getränks, falls es eines gibt, ansonsten -1.
NOTE: Zeitkosten hier messen nur die Anzahl der Vorkoster.
'''
logDebug('Bereite Vorkoster vor');
n = len(L);
p = math.floor(math.log2(n));
testers = [];
## Für jedes Bit i=0 bis p ...
for i in range(p+1):
tester0 = [ k for k in range(n) if nthBit(number=k, digit=i) == 0 ];
tester1 = [ k for k in range(n) if not (k in tester0) ];
# NOTE: tester1 ist virtuell: aus den Effekten auf tester0 und den Annahmen lassen sich die Effekte auf tester0 erschließen.
# Darum zählen wir nicht 2 sondern 1 Vorkoster.
AddSpaceCost(1);
logDebug('Füge Vorkoster hinzu, der alle Getränke k testet mit {i}. Bit = 0.'.format(i=i))
testers.append(tester0);
testers.append(tester1);
logDebug('Warte auf Effekte');
effects = waitForEffects(L, testers);
logDebug('Effekte auswerten, um vergiftete Getränke zu lokalisieren.');
poisened = evaluateEffects(testers, effects);
if len(poisened) > 0:
return poisened[0];
return -1;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHOD wait for effects, evaluate effects
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def waitForEffects(L: List[int], testers: List[List[int]]) -> List[int]:
'''
Inputs:
- L = Liste von Getränken: durch 0-1 Werte wird dargestellt, ob ein Getränk vergiftet ist.
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
Outputs: effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
'''
m = len(testers);
effects = [];
for i in range(m):
effect = sum([L[k] for k in testers[i]]);
effects.append(effect);
return effects;
def evaluateEffects(testers: List[List[int]], effects: List[int]) -> List[int]:
'''
Inputs:
- testers = Liste von Vorkostern. Jeder Vorkoster kostet eine 'Teilliste' der Getränke.
- effects = eine Liste, die jedem Vorkoster zuordnet, wie viele vergiftete Getränke er konsumiert hat.
Annahmen: Vorkoster wurden so angewiesen, dass es garantiert ist, vergiftete Getränke zu finden, wenn es die gibt.
Outputs: Liste der Indexes aller vergifteten Getränke.
'''
## Werte Effekte aus, um Gift zu lokalisieren:
search = set([]);
## Zuerst die Indexes der Getränke bei allen vergifteten Tester zusammenführen:
for i in range(len(testers)):
if effects[i] > 0:
search = search.union(testers[i]);
## jetzt eliminieren wir alle Getränke, die von nicht vergifteten Testern konsumiert wurden:
for i in range(len(testers)):
if effects[i] == 0:
search = search.difference(testers[i]);
return list(search);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHOD n. Bit der binären Darstellung einer Zahl
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def nthBit(number: int, digit: int) -> int:
number_binary = bin(number)[2:][::-1];
if digit < len(number_binary):
return int(number_binary[digit]);
return 0;

View File

@ -1,53 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
# Keine Checks!
return;
def postChecks(L: List[int], x: int, index: int, **_):
if x in L:
assert index >= 0, 'Der Algorithmus sollte nicht -1 zurückgeben.';
assert L[index] == x, 'Der Algorithmus hat den falschen Index bestimmt.';
else:
assert index == -1, 'Der Algorithmus sollte -1 zurückgeben.';
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM sequential search
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='Sequenziellsuchalgorithmus', outputnames=['index'], preChecks=preChecks, postChecks=postChecks)
def SequentialSearch(L: List[int], x: int) -> int:
'''
Inputs: L = Liste von Zahlen, x = Zahl.
Outputs: Position von x in L, sonst 1 wenn x nicht in L.
'''
n = len(L);
for i in range(n):
AddTimeCost();
if L[i] == x:
logDebug('Element in Position {} gefunden.'.format(i));
return i;
logDebug('Element nicht in Position {}.'.format(i));
return -1;

View File

@ -1,8 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.algorithms.stacks.next_greater_element import NextGreaterElement;

View File

@ -1,91 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.typing import *;
from src.core.log import *;
from src.core.metrics import *;
from src.data_structures.stacks import Stack;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
# TODO
return;
def postChecks(L: List[int], **_):
# TODO
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM next greater element
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='NextGreaterElement (with stacks)', outputnames=['pairs'], preChecks=preChecks, postChecks=postChecks)
def NextGreaterElement(L: List[int]) -> List[Tuple[int,int]]:
'''
Inputs: L = Liste von Zahlen.
Outputs: Liste von Paaren von Elementen und ihrem nächsten größeren Element
'''
output = [];
S = Stack();
S.INIT();
for i in range(len(L)):
logDebug('Stack S | {S}'.format(S=S));
logDebug('Nächstes List-Element L[{i}] = {el} betrachten'.format(i=i, el=L[i]));
nextElement = L[i];
logDebug('Alle top Elemente vom Stack, die < nextElement sind, mit L[i] paaren');
# Führe aus, bis top Element >= nextElement oder Stack leer ist.
logDebug('Stack S | {S}'.format(S=S));
while not S.EMPTY():
element = S.TOP();
# falls element < next Element, zum Output hinzufügen und vom Stack entfernen
if element < nextElement:
logDebug('Stack S | {S}; top Element < nextElement; ==> pop und Paar zum Output hinzufügen'.format(S=S))
output.append((element, nextElement));
S.POP();
AddMovesCost();
logDebug('Stack S | {S}'.format(S=S));
# falls top Element > next Element, auf Stack lassen und Schleife abbrechen.
elif element > nextElement:
break
# falls top Element == next Element, vom Stack entfernen und Schleife abbrechen.
else:
S.POP()
AddMovesCost()
break
logDebug('Stack S | {S}'.format(S=S));
logDebug('L[{i}] auf Stack legen'.format(i=i));
S.PUSH(nextElement);
AddMovesCost();
logDebug('Stack S | {S}'.format(S=S));
# was übrig bleibt hat kein größeres Element
logDebug('Alles übrige auf Stack hat kein nächstes größeres Element')
while not S.EMPTY():
logDebug('Stack S | {S}'.format(S=S));
element = S.TOP();
S.POP();
AddMovesCost();
output.append((element, -1));
logDebug('Stack S | {S}'.format(S=S))
return output;

View File

@ -1,9 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.algorithms.sum.maxsubsum import MaxSubSum;
from src.algorithms.sum.maxsubsum import MaxSubSumDC;

View File

@ -1,179 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.maths import *;
from src.local.typing import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks(L: List[int], **_):
assert len(L) > 0, 'Liste darf nicht leer sein.';
return;
def postChecks(L: List[int], **_):
# TODO
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM max sub sum
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='MaxSubSum (Maximale Teilsumme)', outputnames=['maxSum', 'index_from', 'index_to'], preChecks=preChecks, postChecks=postChecks)
def MaxSubSum(L: List[float]) -> Tuple[float, int, int]:
'''
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
'''
maxSum: float = 0;
u: int = 0;
v: int = -1;
for i in range(len(L)):
## Bestimme maximale Teilsumme der linken Rände der Liste ab Index i:
maxSum_, _, k = lRandSum(L[i:]);
if maxSum_ > maxSum:
k += i; # NOTE: muss wegen Offset kompensieren
maxSum, u, v = maxSum_, i, k;
logDebug('max Teilsumme aktualisiert: Summe L[i] von i={u} .. {v} = {value}'.format(u = u, v = v, value = maxSum));
return maxSum, u, v;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM max sub sum (D & C)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos(name='MaxSubSum (Maximale Teilsumme mit D & C)', outputnames=['maxSum', 'index_from', 'index_to'], preChecks=preChecks, postChecks=postChecks)
def MaxSubSumDC(L: List[float]) -> Tuple[float, int, int]:
'''
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
'''
maxSum = 0;
u = 0;
v = -1;
if len(L) == 1:
## wenn Liste aus 1 Element besteht, nicht teilen:
if L[0] > maxSum:
v = 0;
maxSum = L[0];
else:
u = math.ceil(len(L)/2);
Ll = L[:u];
Lr = L[u:];
## berechnet maximale Teilsumme der linken Hälfte:
maxSum1, u1, v1 = MaxSubSumDC(L=Ll);
## berechnet maximale Teilsumme der rechten Hälfte:
maxSum2, u2, v2 = MaxSubSumDC(L=Lr);
u2, v2 = u2 + len(Ll), v2 + len(Ll); # offsets kompensieren
## berechnet maximale Teilsumme mit Überschneidung zw. den Hälften:
maxSum3, u3, v3 = lrRandSum(Ll=Ll, Lr=Lr);
## bestimme Maximum der 3 Möglichkeiten:
maxSum = max(maxSum1, maxSum2, maxSum3);
if maxSum == maxSum1:
maxSum, u, v = maxSum1, u1, v1;
logDebug('max Teilsumme kommt in linker Partition vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum));
elif maxSum == maxSum3:
maxSum, u, v = maxSum3, u3, v3;
logDebug('max Teilsumme kommt in Überschneidung vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum));
else: # elif maxSum == maxSum2:
maxSum, u, v = maxSum2, u2, v2;
logDebug('max Teilsumme kommt in rechter Partition vor: Summe L[i] von i={i} .. {j} = {value}'.format(L = L, i = u, j = v, value = maxSum));
return maxSum, u, v;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def lrRandSum(Ll: List[float], Lr: List[float]) -> Tuple[float, int, int]:
'''
Bestimmt maximale Teilsumme einer Teiliste einer Liste,
wobei die Liste in zwei Intervalle partitioniert ist
und die Teilliste beide überschneidet.
Inputs: Ll, Lr = eine Partition einer Liste von Zahlen in zwei Intervalle
Outputs: maxSum, u=0, v
'''
maxSumL, u, _ = rRandSum(L=Ll);
maxSumR, _, v = lRandSum(L=Lr);
maxSum = maxSumL + maxSumR;
v += len(Ll) # offsets kompensieren
return maxSum, u, v;
def lRandSum(L: List[float]) -> Tuple[float, int, int]:
'''
Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u(=0), v
'''
n = len(L);
## berechne kumulative Summen (vorwärts)
AddTimeCost(n);
total = L[0];
maxSum = total;
u = 0;
v = 0;
for i in range(1, n):
total += L[i];
if total > maxSum:
v = i;
maxSum = total;
return maxSum, 0, v;
def rRandSum(L: List[float]) -> Tuple[float, int, int]:
'''
Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u, v(=len(L)-1)
'''
n = len(L);
## berechne kumulative Summen (rückwärts)
AddTimeCost(n);
total = L[n-1];
maxSum = total;
u = n-1;
v = n-1;
for i in range(0, n-1)[::-1]:
total += L[i];
if total > maxSum:
u = i;
maxSum = total;
return maxSum, u, v;
# Sei N ∈ ℕ⁺
# Sei p so, dass 2^p ≤ N < 2^{p+1},
# Also p = floor(log₂(N)).
# Setze
# B(i,d) := {k < N | bit(k, i) = d}
# für i ∈ {0, 1, ..., p-1}
# und setze
# 𝒜 = {B(i,d) : i ∈ {0, 1, ..., p-1}, d ∈ {0,1}}.
# Seien k1, k2 ∈ N mit k1 ≠ k2.
# Dann existiert i ∈ {0, 1, ..., p-1},
# so dass
# d := bit(k1, i) ≠ bit(k2, i).
# Also
# k1 ∈ B(i, d) ∌ k2.
# Darum erfüllt 𝒜 die erwünschte Eigenschaft.
# Es gilt
# |𝒜| = 2p = 2·floor(log₂(N)) ∈ O(log(N)).

View File

@ -1,60 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.typing import *;
from src.local.config import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHOD read config file
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def ReadConfigFile(path: str) -> dict:
with open(path, 'r') as fp:
spec = load(fp, Loader=FullLoader);
assert isinstance(spec, dict), 'Die Configdatei muss eines Dictionary-Typs sein';
return spec;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHOD extract attribut from dictionary/list
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def GetAttribute(
obj: Any,
*keys: Union[str, int, List[Union[str, int]]],
expectedtype: Union[Type, Tuple[Type]] = Any,
default: Any = None
) -> Any:
if len(keys) == 0:
return obj;
nextkey = keys[0];
nextkey = nextkey if isinstance(nextkey, list) else [ nextkey ];
try:
for key in nextkey:
if isinstance(key, str) and isinstance(obj, dict) and key in obj:
value = obj[key];
if len(keys) <= 1:
return value if isinstance(value, expectedtype) else default;
else:
return GetAttribute(obj[key], *keys[1:], expectedtype=expectedtype, default=default);
elif isinstance(key, int) and isinstance(obj, (list,tuple)) and key < len(obj):
value = obj[key];
if len(keys) <= 1:
return value if isinstance(value, expectedtype) else default;
else:
return GetAttribute(obj[key], *keys[1:], expectedtype=expectedtype, default=default);
except:
pass;
if len(keys) <= 1:
return default;
path = ' -> '.join([ str(key) for key in keys ]);
raise Exception('Konnte \033[1m{}\033[0m im Objekt nicht finden!'.format(path));

View File

@ -1,121 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.local.io import *;
from src.local.misc import *;
from src.local.system import *;
from src.local.typing import *;
from src.core.utils import StripAnsi;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_logging_prefix: str = '';
_quietmode: bool = False;
_debugmode: bool = True;
_ansimode: bool = False;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHOD get/set quiet mode, logging depth, timer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def GetQuietMode() -> bool:
return _quietmode;
def SetQuietMode(mode: bool):
global _quietmode;
_quietmode = mode;
return;
def GetDebugMode() -> bool:
return _debugmode;
def SetDebugMode(mode: bool):
global _debugmode;
_debugmode = mode;
return;
def GetAnsiMode() -> bool:
return _ansimode;
def SetAnsiMode(mode: bool):
global _ansimode;
_ansimode = mode;
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Logging
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def logGeneric(tag: str, *lines: Any, file: io.TextIOWrapper, force: bool = False, tag_all: bool = True):
if not force and _quietmode:
return;
tag = '' if tag == '' else tag + ' ';
file = file or sys.stdout;
for line in lines:
line = '{}{}{}'.format('', tag, line);
if not _ansimode:
line = StripAnsi(line);
print(line, file=file);
if not tag_all:
tag = '';
return;
def logPlain(*lines: Any, force: bool = False, file: Any = None):
logGeneric('', *lines, force=force, file=file or sys.stdout);
def logInfo(*lines: Any, force: bool = False, tag_all: bool = True, file: Any = None):
logGeneric('[\033[94;1mINFO\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stdout);
def logDebug(*lines: Any, force: bool = False, tag_all: bool = True, file: Any = None):
if not _debugmode:
return;
logGeneric('\033[2m[\033[96;1mDEBUG\033[0m\033[2m]\033[0m',
*[ '\033[2m{}\033[0m'.format(line) for line in lines ],
force=force, tag_all=tag_all, file=file or sys.stdout
);
def logWarn(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None):
logGeneric('[\033[93;1mWARNING\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stdout);
def logError(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None):
logGeneric('[\033[91;1mERROR\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stderr);
def logFatal(*lines: Any, force: bool = False, tag_all: bool = False, file: Any = None):
logGeneric('[\033[91;1mFATAL\033[0m]', *lines, force=force, tag_all=tag_all, file=file or sys.stderr);
exit(1);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# User Input
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def askUserInput(message: str, expectedformat: Callable) -> Union[str, None]:
answer = None;
while True:
try:
answer = input('{}{}'.format(_logging_prefix, message));
## Meta+C erkennen:
except KeyboardInterrupt:
logPlain('');
return None;
## Meta+D erkennen:
except EOFError:
logPlain('');
return None;
except:
continue;
if expectedformat(answer):
break;
return answer;
def askConfirmation(message: str, default: bool = False) -> bool:
answer = askUserInput(message, lambda x: not not re.match(r'^(y|yes|j|ja|n|no|nein)$', x));
if isinstance(answer, str):
return True if re.match(r'^(y|yes|j|ja)$', answer) else False;
return default;

View File

@ -1,145 +0,0 @@
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
from datetime import datetime;
from datetime import timedelta;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_ctr_time = None;
_ctr_space = None;
_tmr = None;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASS counter
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Counter(object):
value: int;
def __init__(self):
self.reset();
def __str__(self) -> str:
return str(self.value);
def add(self, n: int = 1):
self.value += n;
return self;
def reset(self):
self.value = 0;
return self;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASS timer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Timer(object):
_time_elapsed: timedelta;
_time_current: datetime;
_running: bool
def __init__(self):
self.reset();
def __str__(self) -> str:
return str(self._time_elapsed);
@property
def elapsedTime(self) -> timedelta:
return self._time_elapsed;
def start(self):
self._time_current = datetime.now();
self._running = True
return self;
def stop(self):
if self._running:
t0 = self._time_current;
t1 = datetime.now();
delta = t1 - t0;
self._time_current = t1;
self._time_elapsed += delta;
self._running = False
return self;
def reset(self):
t = datetime.now();
delta = t - t;
self._time_current = t;
self._time_elapsed = delta;
self._running = False
return self;
## Initialisierung:
_ctr_time = Counter();
_ctr_moves = Counter();
_ctr_space = Counter();
_tmr = Timer();
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def ResetMetrics():
global _ctr_time;
global _ctr_moves;
global _ctr_space;
global _tmr;
_ctr_time.reset();
_ctr_moves.reset();
_ctr_space.reset();
_tmr.reset();
return;
def StartMetrics():
_tmr.start()
return;
def StopMetrics():
_tmr.stop()
return;
def AddTimeCost(n: int = 1):
global _ctr_time;
_ctr_time.add(n);
return;
def AddMovesCost(n: int = 1):
global _ctr_moves;
_ctr_moves.add(n);
return;
def AddSpaceCost(n: int = 1):
global _ctr_space;
_ctr_space.add(n);
return;
def SetSpaceCost(n: int):
global _ctr_space;
_ctr_space.value = n;
return;
def GetTimeCost() -> int:
return _ctr_time.value;
def GetMovesCost() -> int:
return _ctr_moves.value;
def GetSpaceCost() -> int:
return _ctr_space.value;
def GetTimeElapsed() -> timedelta:
global _tmr;
_tmr.stop();
return _tmr.elapsedTime;

View File

@ -1,40 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import re;
from textwrap import dedent;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS ansi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def StripAnsi(text: str) -> str:
return re.sub(r'\x1b[^m]*m', '', text);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS strings
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def DedentIgnoreFirstLast(text: str) -> str:
text = '\n'.join(re.split(r'\n', text)[1:][:-1])
return dedent(text);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS strings -> bool
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def IsTrue(text: str) -> bool:
text = text.strip();
if re.match(r'^(true|t|yes|y|1|\+|\+1)$', text, re.IGNORECASE):
return True;
return False;
def IsFalse(text: str) -> bool:
text = text.strip();
if re.match(r'^(false|f|no|n|0|-|-1)$', text, re.IGNORECASE):
return True;
return False;

View File

@ -1,52 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.typing import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASS Queue
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Queue(object):
_initialised: bool;
values: List[int];
def __init__(self):
self._initialised = False;
def INIT(self):
self.values = [];
self._initialised = True;
def EMPTY(self) -> bool:
return not self._initialised or len(self.values) == 0;
def ENQUEUE(self, x: int):
if not self._initialised:
raise Exception('Queue not initialised!')
self.values.append(x);
def FRONT(self) -> int:
if self.EMPTY():
raise Exception('Cannot read from empty queue!')
return self.values[0];
def DEQUEUE(self) -> int:
if self.EMPTY():
raise Exception('Cannot remove from empty queue!')
self.values = self.values[1:];
def __str__(self) -> str:
if len(self.values) == 0:
return '-';
return ', '.join([str(x) for x in self.values]);

View File

@ -1,52 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.typing import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASS Stack
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Stack(object):
_initialised: bool;
values: List[int];
def __init__(self):
self._initialised = False;
def INIT(self):
self.values = [];
self._initialised = True;
def EMPTY(self) -> bool:
return not self._initialised or len(self.values) == 0;
def PUSH(self, x: int):
if not self._initialised:
raise Exception('Stack not initialised!');
self.values.append(x);
def TOP(self) -> int:
if self.EMPTY():
raise Exception('Cannot read from empty stack!');
return self.values[-1];
def POP(self) -> int:
if self.EMPTY():
raise Exception('Cannot remove from empty stack!');
self.values = self.values[:-1];
def __str__(self) -> str:
if len(self.values) == 0:
return '-';
return ', '.join([str(x) for x in self.values]);

View File

@ -1,11 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.endpoints.print import version as endpoint_version;
from src.endpoints.print import help as endpoint_help;
from src.endpoints.run import runInteractive as endpoint_runInteractive;
from src.endpoints.run import runNonInteractive as endpoint_runNonInteractive;

View File

@ -1,25 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.core.log import *;
from src.setup import assets;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ENDPOINT version
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def version():
logPlain(assets.Version());
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ENDPOINT help
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def help():
logPlain(assets.Help());
return;

View File

@ -1,74 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.core.log import *;
from src.core.config import *;
from src.setup.display import *;
from src.setup import assets;
from src.algorithms.exports import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ENDPOINT run interactive modus
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def runInteractive():
'''
Startet Programm im interaktiven Modus (Konsole).
'''
logPlain(assets.Logo());
logWarn('Interaktiver Modus noch nicht implementiert.');
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ENDPOINT run non-interactive
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def runNonInteractive(path: str):
'''
Liest Fälle aus Configdatei aus und führt Algorithmen darauf aus.
'''
config = ReadConfigFile(path);
cases = GetAttribute(config, 'parts', 'cases', expectedtype=list, default=[]);
logPlain(assets.Logo());
for caseindex, case in enumerate(cases):
command = GetAttribute(case, 'command', expectedtype=str, default='');
descr = GetAttribute(case, 'description', expectedtype=str, default='');
inputs = GetAttribute(case, 'inputs', expectedtype=dict, default={});
DisplayStartOfCase(caseindex, descr);
try:
if command == 'algorithm-search-sequential':
SequentialSearch(L=inputs['L'], x=inputs['x']);
elif command == 'algorithm-search-binary':
BinarySearch(L=inputs['L'], x=inputs['x']);
elif command == 'algorithm-search-interpolation':
InterpolationSearch(L=inputs['L'], x=inputs['x'], u=0, v=len(inputs['L'])-1);
elif command == 'algorithm-search-jump':
JumpSearchLinear(L=inputs['L'], x=inputs['x'], m=inputs['m']);
elif command == 'algorithm-search-jump-exp':
JumpSearchExponentiell(L=inputs['L'], x=inputs['x']);
elif command == 'algorithm-search-ith-element':
FindIthSmallest(L=inputs['L'], i=inputs['i']);
elif command == 'algorithm-search-ith-element-dc':
FindIthSmallestDC(L=inputs['L'], i=inputs['i']);
elif command == 'algorithm-search-poison':
FindPoison(L=inputs['L']);
elif command == 'algorithm-search-poison-fast':
FindPoisonFast(L=inputs['L']);
elif command == 'algorithm-stacks-next-greater-element':
NextGreaterElement(L=inputs['L']);
elif command == 'algorithm-sum-maxsub':
MaxSubSum(L=inputs['L']);
elif command == 'algorithm-sum-maxsub-dc':
MaxSubSumDC(L=inputs['L']);
else:
raise ValueError('Command \033[1m{}\033[0m nicht erkannt'.format(command));
except Exception as e:
logError(e);
DisplayEndOfCase();
return;

Some files were not shown because too many files have changed in this diff Show More