diff --git a/README.md b/README.md index e69de29..9c4b7f5 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,20 @@ +# PR3 Code Repository + +This repository contains all code of the PR3 lecture. This includes assignments. Solutions and code produced during the lecture is added incrementally during the semester. + +## Usage + +The code for each programming language is located in a dedicated subfolder. The individual development environment is defined by a [Development Container](https://containers.dev/) which ensures a uniform easy to set up coding experience on all platforms (Windows/MacOS/Linux). The following tools shall be available on the developer's machine: + +- A [container runtime](https://en.wikipedia.org/wiki/OS-level_virtualization) such as [docker](https://www.docker.com/) or [podman](https://podman.io/). Windows users should install [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/) beforehand. + +- [Visual Studio Code](https://code.visualstudio.com/) along with the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. + +Follow these steps to get started: + +1. Clone this repository into a local folder of your choice. Use a WSL folder on Windows. +2. Navigate to the subfolder of the desired programming language (e.g. `cd pr3-xyz/go`). +3. Open Visual Studio Code in that folder by executing `code .` +4. Click on *Reopen in Container* in the popup that appears on the bottom right corner: ![](vscode-devcontainer-popup.png) + +This will open the folder in the dedicated *Development Container* that contains all required tools. Furthermore, programming language specific Visual Studio Code extensions are automatically installed inside the *Development Container* without affecting the host system. diff --git a/go/.devcontainer/Dockerfile b/go/.devcontainer/Dockerfile new file mode 100644 index 0000000..72b1aa7 --- /dev/null +++ b/go/.devcontainer/Dockerfile @@ -0,0 +1,10 @@ +FROM golang:1.26-bookworm + +RUN apt-get update \ + && apt-get install -y build-essential \ + && rm -rf /var/lib/apt/lists/* + +ARG USERNAME=developer +ARG USER_UID=1000 +ARG USER_GID=$USER_UID +RUN groupadd --gid $USER_GID $USERNAME && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME diff --git a/go/.devcontainer/devcontainer.json b/go/.devcontainer/devcontainer.json new file mode 100644 index 0000000..933cbe5 --- /dev/null +++ b/go/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +{ + "name": "Go Dev Container", + "build": { + "dockerfile": "Dockerfile" + }, + "postCreateCommand": "go install github.com/go-delve/delve/cmd/dlv@latest && go install github.com/cweill/gotests/gotests@v1.9.0 && go install golang.org/x/tools/gopls@latest && go install golang.org/x/tools/cmd/goimports@latest && go install honnef.co/go/tools/cmd/staticcheck@latest", + "customizations": { + "vscode": { "extensions": [ + "golang.go", + "gruntfuggly.todo-tree", + "-github.copilot" + ]} + }, + "remoteUser": "developer", + "updateRemoteUserUID": true +} diff --git a/go/.vscode/settings.json b/go/.vscode/settings.json new file mode 100644 index 0000000..bfba8e3 --- /dev/null +++ b/go/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "chat.disableAIFeatures": true, + "terminal.integrated.env.linux": { + "EDITOR": "code --wait" + }, + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "icon": "terminal-bash" + } + } +} diff --git a/go/00-hello-world/README.md b/go/00-hello-world/README.md new file mode 100644 index 0000000..92b9cf6 --- /dev/null +++ b/go/00-hello-world/README.md @@ -0,0 +1,17 @@ +# Hello World + +## Run +`go run hello-world.go` + +## Build +`go build hello-world.go` + +## Formatting +`go fmt hello-world.go` + +## Linting +`go vet hello-world.go` + +### Examples +1. `fmt.Printf("hello world, %s\n")` +2. `a := 7` (already caught by the compiler) diff --git a/go/00-hello-world/go.mod b/go/00-hello-world/go.mod new file mode 100644 index 0000000..d565f37 --- /dev/null +++ b/go/00-hello-world/go.mod @@ -0,0 +1,3 @@ +module gitty.informatik.th-mannheim.de/steger/pr3-sose2026/go/00-hello-world/hello-world + +go 1.26.0 diff --git a/go/00-hello-world/hello-world.go b/go/00-hello-world/hello-world.go new file mode 100644 index 0000000..c048119 --- /dev/null +++ b/go/00-hello-world/hello-world.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("hello world") +} diff --git a/go/01-basics/README.md b/go/01-basics/README.md new file mode 100644 index 0000000..8ef91a5 --- /dev/null +++ b/go/01-basics/README.md @@ -0,0 +1,84 @@ +# Go By Example + + + +# Assignment 1 - Simple Calculator + +## Objective +Write a Go program that performs basic mathematical operations (addition, subtraction, multiplication, and division) based on user input. + +## Steps + +1. Define constants for valid operations (*add*,*subtract*,*multiply*,*divide*). +2. Use variables to store user inputs and computed results. +3. Use a loop to allow the user to perform multiple calculations until they choose to exit. +4. Validate inputs using statements (e.g., handle division by zero). +5. Use a statement to perform the selected mathematical operation. + +## Example Output +``` +Enter operation (add, subtract, multiply, divide, exit): add +Enter the first number: 5 +Enter the second number: 3 +Result: 8 + +Enter operation (add, subtract, multiply, divide, exit): divide +Enter the first number: 10 +Enter the second number: 0 +Error: Division by zero is not allowed! + +Enter operation (add, subtract, multiply, divide, exit): exit +Goodbye! +``` + +## Hint +The program can use the `fmt.Scan` function to accept user input. + +# Assignment 2 - Inventory Management System + +## Objective +Create a program that simulates an inventory management system for a store. + +## Steps +1. Define product categories (e.g., Electronics, Groceries, Clothes) using `const` and `iota`. +2. Store a fixed list of initial product names in an **array**. +3. Convert the array into a **slice** so the inventory can grow or shrink dynamically. +4. Use a **map** to associate product names with details like quantity, price, and category. +5. Implement the following **functions**: + - *AddProduct*: Add a new product to the inventory. + - *RemoveProduct*: Remove a product from the inventory. + - *DisplayInventory*: Display all products with their details. + - *UpdateQuantity*: Update the quantity of a product. + +## Example Output +``` +Welcome to the Inventory Manager! + +Initial Inventory: +1. Laptop - Electronics (Price: $1000, Quantity: 5) +2. Apples - Groceries (Price: $2, Quantity: 50) +3. T-shirt - Clothes (Price: $10, Quantity: 20) + +Adding a new product: Phone (Electronics, Price: $800, Quantity: 10) + +Updated Inventory: +1. Laptop - Electronics (Price: $1000, Quantity: 5) +2. Apples - Groceries (Price: $2, Quantity: 50) +3. T-shirt - Clothes (Price: $10, Quantity: 20) +4. Phone - Electronics (Price: $800, Quantity: 10) + +Updating quantity for Apples: New Quantity = 30 + +Removing product: T-shirt + +Final Inventory: +1. Laptop - Electronics (Price: $1000, Quantity: 5) +2. Apples - Groceries (Price: $2, Quantity: 30) +3. Phone - Electronics (Price: $800, Quantity: 10) +``` + +- Use **arrays** to store initial product information. +- Use **slices** to dynamically manage items in the inventory. +- Use **maps** to track product details (e.g., quantity or price). +- Define **functions** for adding, removing, and displaying products. +- Use **enums** (via constants) to represent product categories. diff --git a/go/01-basics/calculator.go b/go/01-basics/calculator.go new file mode 100644 index 0000000..7686df8 --- /dev/null +++ b/go/01-basics/calculator.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" +) + +func main() { + + //TODO: implement according to README.md + + //the following code just demonstrates how to use fmt.Scan + + var str string + fmt.Print("Please enter a string: ") + fmt.Scan(&str) + + var x float64 + fmt.Print("Please enter a float: ") + fmt.Scan(&x) + + fmt.Printf("You entered '%s' and %f\n", str, x) +} diff --git a/go/01-basics/inventory.go b/go/01-basics/inventory.go new file mode 100644 index 0000000..209c374 --- /dev/null +++ b/go/01-basics/inventory.go @@ -0,0 +1,50 @@ +package main + +type Product struct { + Name string + Price float64 + Quantity int + Category string //TODO: use enum instead +} + +func addProduct(inventory *[]Product, name string, price float64, quantity int, category string) { + //TODO: implement +} + +func removeProduct(inventory *[]Product, name string) { + //TODO: implement +} + +func updateQuantity(inventory *[]Product, name string, newQuantity int) { + //TODO: implement +} + +func displayInventory(inventory []Product) { + //TODO: implement +} + +func main() { + inventory := []Product{ + {Name: "Laptop", Price: 1000, Quantity: 5, Category: "Electronics"}, + {Name: "Apples", Price: 2, Quantity: 50, Category: "Groceries"}, + {Name: "T-shirt", Price: 10, Quantity: 20, Category: "Clothes"}, + } + + // Display initial inventory + displayInventory(inventory) + + // Add a new product + addProduct(&inventory, "Phone", 800, 10, "Electronics") + + // Display updated inventory + displayInventory(inventory) + + // Update the quantity of an existing product + updateQuantity(&inventory, "Apples", 30) + + // Remove a product + removeProduct(&inventory, "T-shirt") + + // Display final inventory + displayInventory(inventory) +} diff --git a/go/02-next-level/05-generics.go b/go/02-next-level/05-generics.go new file mode 100644 index 0000000..5481cb1 --- /dev/null +++ b/go/02-next-level/05-generics.go @@ -0,0 +1,51 @@ +package main + +import "fmt" + +func SlicesIndex[S []E, E int](s []string, v string) int { + for i := range s { + if v == s[i] { + return i + } + } + return -1 +} + +type List struct { + head, tail *element +} + +type element struct { + next *element + val int +} + +func (lst *List) Push(v int) { + if lst.tail == nil { + lst.head = &element{val: v} + lst.tail = lst.head + } else { + lst.tail.next = &element{val: v} + lst.tail = lst.tail.next + } +} + +func (lst *List) AllElements() []int { + var elems []int + for e := lst.head; e != nil; e = e.next { + elems = append(elems, e.val) + } + return elems +} + +func main() { + var s = []string{"foo", "bar", "zoo"} + + fmt.Println("index of zoo:", SlicesIndex(s, "zoo")) + + lst := List{} + lst.Push(10) + lst.Push(13) + lst.Push(23) + fmt.Println("list:", lst.AllElements()) +} diff --git a/go/02-next-level/06-defer.go b/go/02-next-level/06-defer.go new file mode 100644 index 0000000..998103c --- /dev/null +++ b/go/02-next-level/06-defer.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + f := createFile("/tmp/defer.txt") + writeFile(f) + closeFile(f) +} + +func createFile(p string) *os.File { + fmt.Println("creating") + f, err := os.Create(p) + if err != nil { + panic(err) + } + return f +} + +func writeFile(f *os.File) { + fmt.Println("writing") + fmt.Fprintln(f, "data") +} + +func closeFile(f *os.File) { + fmt.Println("closing") + err := f.Close() + + if err != nil { + panic(err) + } +} diff --git a/go/03-modules/main.go b/go/03-modules/main.go new file mode 100644 index 0000000..7905807 --- /dev/null +++ b/go/03-modules/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} diff --git a/go/03-modules/myMath/math.go b/go/03-modules/myMath/math.go new file mode 100644 index 0000000..e69de29 diff --git a/go/04-design-pattern/README.md b/go/04-design-pattern/README.md new file mode 100644 index 0000000..850d97c --- /dev/null +++ b/go/04-design-pattern/README.md @@ -0,0 +1,9 @@ +# Assignment + +Implement an arbitrary [design pattern](https://refactoring.guru/design-patterns/catalog) in Go. + +1. Create a package named `patterns` in the `04-design-patterns` folder +2. Implement the design pattern in that package +3. Implement a corresponding unit test +4. Create an example application that uses the design pattern in the file `04-design-patterns/main.go` +5. Zip the source code and upload diff --git a/go/05-concurrency/deadlock.go b/go/05-concurrency/deadlock.go new file mode 100644 index 0000000..931c201 --- /dev/null +++ b/go/05-concurrency/deadlock.go @@ -0,0 +1,17 @@ +package main + +func print(ci <-chan int) { + //TODO: implement +} + +func main() { + + c := make(chan int) + + c <- 1 + c <- 2 + c <- 3 + close(c) + + print(c) +} diff --git a/go/05-concurrency/mergeSort.go b/go/05-concurrency/mergeSort.go new file mode 100644 index 0000000..4160246 --- /dev/null +++ b/go/05-concurrency/mergeSort.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" + "math/rand" + "sort" + "time" +) + +func mergeSortSequential(data []float64) { + if len(data) <= 1 { + return + } + + mid := len(data) / 2 + left := data[:mid] + right := data[mid:] + + mergeSortSequential(left) + mergeSortSequential(right) + + copy(data, merge(left, right)) +} + +func merge(left, right []float64) []float64 { + result := make([]float64, 0, len(left)+len(right)) + i, j := 0, 0 + + for i < len(left) && j < len(right) { + if left[i] < right[j] { + result = append(result, left[i]) + i++ + } else { + result = append(result, right[j]) + j++ + } + } + + result = append(result, left[i:]...) + result = append(result, right[j:]...) + + return result +} + +func main() { + + //1. DATA CREATION + data := make([]float64, 1000*1000*20) + + for i := range data { + data[i] = rand.Float64() * 100 // Random floats between 0 and 100 + } + + expected := make([]float64, len(data)) + copy(expected, data) + sort.Float64s(expected) + + //2. SORTING + start := time.Now() + + mergeSortSequential(data) + + elapsed := time.Since(start) + fmt.Printf("MergeSort took %s\n", elapsed) + + //3. VERIFICATION + if sort.Float64sAreSorted(data) { + fmt.Println("Data is sorted correctly") + } else { + fmt.Println("Data is NOT sorted correctly") + } + + if len(data) != len(expected) { + fmt.Println("Data and expected slices have different lengths") + return + } + + for i := range data { + if data[i] != expected[i] { + fmt.Println("Data and expected slices do not match") + return + } + } + + fmt.Println("Data and expected slices match") +} diff --git a/go/05-concurrency/select.go b/go/05-concurrency/select.go new file mode 100644 index 0000000..8af6e52 --- /dev/null +++ b/go/05-concurrency/select.go @@ -0,0 +1,19 @@ +package main + +import ( + "math/rand" + "time" +) + +func main() { + + ch1 := make(chan string) + + go func() { + time.Sleep(time.Duration(rand.Intn(5)+1) * time.Second) + ch1 <- "Message from channel 1" + }() + + msg1 := <-ch1 + println("Received:", msg1) +} diff --git a/go/go-cheat-sheet.pdf b/go/go-cheat-sheet.pdf new file mode 100644 index 0000000..709b20f Binary files /dev/null and b/go/go-cheat-sheet.pdf differ diff --git a/vscode-devcontainer-popup.png b/vscode-devcontainer-popup.png new file mode 100644 index 0000000..d230c73 Binary files /dev/null and b/vscode-devcontainer-popup.png differ