From 0882db5cd1c600c4fb91a7a51a05e0d6891c309f Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 12 Sep 2025 22:58:41 +0330 Subject: [PATCH 01/23] Add solution for Challenge 1 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 challenge-1/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-1/submissions/Ali-Fartoot/solution-template.go b/challenge-1/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..b72bd540 --- /dev/null +++ b/challenge-1/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" +) + +func main() { + var a, b int + // Read two integers from standard input + _, err := fmt.Scanf("%d, %d", &a, &b) + if err != nil { + fmt.Println("Error reading input:", err) + return + } + + // Call the Sum function and print the result + result := Sum(a, b) + fmt.Println(result) +} + +// Sum returns the sum of a and b. +func Sum(a int, b int) int { + + return a + b +} From 0caaf6cd4ed6b4c470279a1941ff2e86ec47b44f Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 12 Sep 2025 23:16:48 +0330 Subject: [PATCH 02/23] Add solution for Challenge 2 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 challenge-2/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-2/submissions/Ali-Fartoot/solution-template.go b/challenge-2/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..8327d2a4 --- /dev/null +++ b/challenge-2/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,32 @@ +package main + +import ( + "bufio" + "fmt" + "os" +) + +func main() { + // Read input from standard input + scanner := bufio.NewScanner(os.Stdin) + if scanner.Scan() { + input := scanner.Text() + + // Call the ReverseString function + output := ReverseString(input) + + // Print the result + fmt.Println(output) + } +} + +// ReverseString returns the reversed string of s. +func ReverseString(s string) string { + runes := []rune(s) + for startChar, endChar := 0, len(runes)-1; startChar < endChar; startChar, endChar = startChar+1, endChar-1 { + runes[startChar], runes[endChar] = runes[endChar], runes[startChar] + } + + result := string(runes) + return result +} From fd16b48fed4557f5481cdb27aa1deeb81b7d5d38 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Sat, 13 Sep 2025 20:04:19 +0330 Subject: [PATCH 03/23] Add solution for Challenge 3 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 challenge-3/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-3/submissions/Ali-Fartoot/solution-template.go b/challenge-3/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..8714dc88 --- /dev/null +++ b/challenge-3/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,65 @@ +package main + +import "fmt" + +type Employee struct { + ID int + Name string + Age int + Salary float64 +} + +type Manager struct { + Employees []Employee +} + +// AddEmployee adds a new employee to the manager's list. +func (m *Manager) AddEmployee(e Employee) { + m.Employees = append(m.Employees, e) +} + +// RemoveEmployee removes an employee by ID from the manager's list. +func (m *Manager) RemoveEmployee(id int) { + for i, emp:=range m.Employees{ + if emp.ID == id { + m.Employees = append(m.Employees[:i], m.Employees[i+1:]...) + } + } +} + +// GetAverageSalary calculates the average salary of all employees. +func (m *Manager) GetAverageSalary() float64 { + if len(m.Employees) == 0 { + return 0 + } + var total float64 = 0.0 + for _, emp:= range m.Employees{ + total += emp.Salary + } + return float64(total) / float64(len(m.Employees)) + +} + +// FindEmployeeByID finds and returns an employee by their ID. +func (m *Manager) FindEmployeeByID(id int) *Employee { + for i:= range m.Employees{ + if m.Employees[i].ID == id{ + return &m.Employees[i] + } + } + return nil +} + +func main() { + manager := Manager{} + manager.AddEmployee(Employee{ID: 1, Name: "Alice", Age: 30, Salary: 70000}) + manager.AddEmployee(Employee{ID: 2, Name: "Bob", Age: 25, Salary: 65000}) + manager.RemoveEmployee(1) + averageSalary := manager.GetAverageSalary() + employee := manager.FindEmployeeByID(2) + + fmt.Printf("Average Salary: %f\n", averageSalary) + if employee != nil { + fmt.Printf("Employee found: %+v\n", *employee) + } +} From a6418bcca237f63a6a38976c01f536f0f8f02f28 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Wed, 17 Sep 2025 01:06:44 +0330 Subject: [PATCH 04/23] Add solution for Challenge 4 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 challenge-4/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-4/submissions/Ali-Fartoot/solution-template.go b/challenge-4/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..cb684bd2 --- /dev/null +++ b/challenge-4/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,175 @@ +package main + +import ( + "fmt" + "sync" +) + +// BFSResult represents the result of a single BFS query +type BFSResult struct { + StartNode int + Traversal []int +} + +// BFS performs breadth-first search starting from the given node +func BFS(graph map[int][]int, start int) []int { + visited := make(map[int]bool) + queue := []int{start} + result := []int{} + + // Mark the starting node as visited + visited[start] = true + + for len(queue) > 0 { + current := queue[0] + queue = queue[1:] + result = append(result, current) + + // Explore all neighbors of current node (if it has any) + if neighbors, exists := graph[current]; exists { + for _, neighbor := range neighbors { + if !visited[neighbor] { + visited[neighbor] = true + queue = append(queue, neighbor) + } + } + } + } + + return result +} + +// ConcurrentBFSQueries processes BFS queries concurrently using worker goroutines +// Each worker processes queries from a shared job queue +func ConcurrentBFSQueries(graph map[int][]int, queries []int, numWorkers int) map[int][]int { + // Channel to distribute work to workers + jobQueue := make(chan int, len(queries)) + + // Channel to collect results from workers + resultQueue := make(chan BFSResult, len(queries)) + + // WaitGroup to ensure all workers complete before closing result channel + var wg sync.WaitGroup + + // Start worker goroutines + for i := 0; i < numWorkers; i++ { + wg.Add(1) + go func(workerID int) { + defer wg.Done() + // Each worker processes jobs until channel is closed + for startNode := range jobQueue { + bfsTraversal := BFS(graph, startNode) + resultQueue <- BFSResult{ + StartNode: startNode, + Traversal: bfsTraversal, + } + } + }(i) + } + + // Send all queries to the job queue + for _, query := range queries { + jobQueue <- query + } + close(jobQueue) // Signal no more jobs coming + + // Close result channel when all workers finish + go func() { + wg.Wait() + close(resultQueue) + }() + + // Collect all results + finalResults := make(map[int][]int) + for result := range resultQueue { + finalResults[result.StartNode] = result.Traversal + } + + return finalResults +} + +// Alternative implementation using buffered channels for better performance +func ConcurrentBFSQueriesBuffered(graph map[int][]int, queries []int, numWorkers int) map[int][]int { + // Buffered channels for better throughput + jobQueue := make(chan int, numWorkers*2) + resultQueue := make(chan BFSResult, numWorkers*2) + + // Start workers + for i := 0; i < numWorkers; i++ { + go func() { + for startNode := range jobQueue { + bfsTraversal := BFS(graph, startNode) + resultQueue <- BFSResult{ + StartNode: startNode, + Traversal: bfsTraversal, + } + } + }() + } + + // Send jobs concurrently + go func() { + defer close(jobQueue) + for _, query := range queries { + jobQueue <- query + } + }() + + // Collect results + finalResults := make(map[int][]int) + for i := 0; i < len(queries); i++ { + result := <-resultQueue + finalResults[result.StartNode] = result.Traversal + } + + return finalResults +} + +func main() { + // Example graph + graph := map[int][]int{ + 0: {1, 2}, + 1: {2, 3}, + 2: {3}, + 3: {4}, + 4: {}, + } + + queries := []int{0, 1, 2} + numWorkers := 2 + + fmt.Println("=== Standard Concurrent Implementation ===") + results1 := ConcurrentBFSQueries(graph, queries, numWorkers) + for _, query := range queries { + fmt.Printf("BFS from %d: %v\n", query, results1[query]) + } + + fmt.Println("\n=== Buffered Channel Implementation ===") + results2 := ConcurrentBFSQueriesBuffered(graph, queries, numWorkers) + for _, query := range queries { + fmt.Printf("BFS from %d: %v\n", query, results2[query]) + } + + // Larger example to demonstrate concurrency benefits + fmt.Println("\n=== Large Graph Example ===") + largeGraph := make(map[int][]int) + for i := 0; i < 100; i++ { + neighbors := []int{} + if i < 99 { + neighbors = append(neighbors, i+1) + } + if i > 0 { + neighbors = append(neighbors, i-1) + } + largeGraph[i] = neighbors + } + + largeQueries := []int{0, 25, 50, 75, 99} + largeResults := ConcurrentBFSQueries(largeGraph, largeQueries, 4) + + for _, query := range largeQueries { + result := largeResults[query] + fmt.Printf("BFS from %d: [%d, %d, %d, ..., %d] (length: %d)\n", + query, result[0], result[1], result[2], result[len(result)-1], len(result)) + } +} \ No newline at end of file From b1f7c0ba553dacce4b78ffe92f68f10d286048e0 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Wed, 17 Sep 2025 01:37:30 +0330 Subject: [PATCH 05/23] Add solution for Challenge 5 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 challenge-5/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-5/submissions/Ali-Fartoot/solution-template.go b/challenge-5/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..0d7a5fb9 --- /dev/null +++ b/challenge-5/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "net/http" +) + +const validToken = "secret" + +// AuthMiddleware checks the "X-Auth-Token" header. +// If it's "secret", call the next handler. +// Otherwise, respond with 401 Unauthorized. +func AuthMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authToken := r.Header.Get("X-Auth-Token") + + if authToken != validToken { + w.WriteHeader(http.StatusUnauthorized) + return + } + next.ServeHTTP(w, r) + // TODO: Implement the logic: + // 1) Grab the "X-Auth-Token" header + // 2) Compare against validToken + // 3) If mismatch or missing, respond with 401 + // 4) Otherwise pass to next handler + }) +} + +// helloHandler returns "Hello!" on GET /hello +func helloHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, "Hello!") +} + +// secureHandler returns "You are authorized!" on GET /secure +func secureHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, "You are authorized!") +} + +// SetupServer configures the HTTP routes with the authentication middleware. +func SetupServer() http.Handler { + mux := http.NewServeMux() + + // Public route: /hello (no auth required) + mux.HandleFunc("/hello", helloHandler) + + // Secure route: /secure + // Wrap with AuthMiddleware + secureRoute := http.HandlerFunc(secureHandler) + mux.Handle("/secure", AuthMiddleware(secureRoute)) + + return mux +} + +func main() { + // Optional: you can run a real server for local testing + http.ListenAndServe(":8080", SetupServer()) +} From 970237b705768473377ee377663e9dbd60e1d225 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Wed, 17 Sep 2025 02:03:08 +0330 Subject: [PATCH 06/23] Add solution for Challenge 6 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 challenge-6/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-6/submissions/Ali-Fartoot/solution-template.go b/challenge-6/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..08de56dd --- /dev/null +++ b/challenge-6/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,29 @@ +// Package challenge6 contains the solution for Challenge 6. +package challenge6 + +import ( + "strings" + "unicode" +) + +func CountWordFrequency(text string) map[string]int { + var cleaned strings.Builder + for _, r := range text { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + cleaned.WriteRune(unicode.ToLower(r)) + } else if r == '\'' { + continue + } else { + cleaned.WriteRune(' ') + } + } + + words := strings.Fields(cleaned.String()) + counter := make(map[string]int) + + for _, word := range words { + counter[word]++ + } + + return counter +} From e0d5cd132c26bccf7f2eb8f13e396ea766ec43a0 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Wed, 17 Sep 2025 22:16:24 +0330 Subject: [PATCH 07/23] Add solution for Challenge 7 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 challenge-7/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-7/submissions/Ali-Fartoot/solution-template.go b/challenge-7/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..e336c420 --- /dev/null +++ b/challenge-7/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,240 @@ +// Package challenge7 contains the solution for Challenge 7: Bank Account with Error Handling. +package challenge7 + +import ( + "fmt" + "strings" + "sync" +) + +// BankAccount represents a bank account with balance management and minimum balance requirements. +type BankAccount struct { + ID string + Owner string + Balance float64 + MinBalance float64 + mu sync.Mutex // For thread safety +} + +// Constants for account operations +const ( + MaxTransactionAmount = 10000.0 // Example limit for deposits/withdrawals +) + +// Custom error types + +// AccountError is a general error type for bank account operations. +type AccountError struct { + Message string + Code string +} + +func (e *AccountError) Error() string { + return fmt.Sprintf("account error [%s]: %s", e.Code, e.Message) +} + +// InsufficientFundsError occurs when a withdrawal or transfer would bring the balance below minimum. +type InsufficientFundsError struct { + RequestedAmount float64 + CurrentBalance float64 + MinBalance float64 +} + +func (e *InsufficientFundsError) Error() string { + return fmt.Sprintf("insufficient funds: requested %.2f, current balance %.2f, minimum balance %.2f", + e.RequestedAmount, e.CurrentBalance, e.MinBalance) +} + +// NegativeAmountError occurs when an amount for deposit, withdrawal, or transfer is negative. +type NegativeAmountError struct { + Amount float64 +} + +func (e *NegativeAmountError) Error() string { + return fmt.Sprintf("negative amount not allowed: %.2f", e.Amount) +} + +// ExceedsLimitError occurs when a deposit or withdrawal amount exceeds the defined limit. +type ExceedsLimitError struct { + Amount float64 + Limit float64 +} + +func (e *ExceedsLimitError) Error() string { + return fmt.Sprintf("amount %.2f exceeds transaction limit of %.2f", e.Amount, e.Limit) +} + +// NewBankAccount creates a new bank account with the given parameters. +// It returns an error if any of the parameters are invalid. +func NewBankAccount(id, owner string, initialBalance, minBalance float64) (*BankAccount, error) { + // Validate input parameters + if strings.TrimSpace(id) == "" { + return nil, &AccountError{ + Message: "account ID cannot be empty", + Code: "INVALID_ID", + } + } + + if strings.TrimSpace(owner) == "" { + return nil, &AccountError{ + Message: "account owner cannot be empty", + Code: "INVALID_OWNER", + } + } + + if minBalance < 0 { + return nil, &NegativeAmountError{Amount: minBalance} + } + + if initialBalance < 0 { + return nil, &NegativeAmountError{Amount: initialBalance} + } + + if initialBalance < minBalance { + return nil, &InsufficientFundsError{ + RequestedAmount: 0, + CurrentBalance: initialBalance, + MinBalance: minBalance, + } + } + + return &BankAccount{ + ID: strings.TrimSpace(id), + Owner: strings.TrimSpace(owner), + Balance: initialBalance, + MinBalance: minBalance, + }, nil +} + +// Deposit adds the specified amount to the account balance. +// It returns an error if the amount is invalid or exceeds the transaction limit. +func (a *BankAccount) Deposit(amount float64) error { + // Validate amount + if amount < 0 { + return &NegativeAmountError{Amount: amount} + } + + if amount > MaxTransactionAmount { + return &ExceedsLimitError{ + Amount: amount, + Limit: MaxTransactionAmount, + } + } + + // Thread-safe operation + a.mu.Lock() + defer a.mu.Unlock() + + a.Balance += amount + return nil +} + +// Withdraw removes the specified amount from the account balance. +// It returns an error if the amount is invalid, exceeds the transaction limit, +// or would bring the balance below the minimum required balance. +func (a *BankAccount) Withdraw(amount float64) error { + // Validate amount + if amount < 0 { + return &NegativeAmountError{Amount: amount} + } + + if amount > MaxTransactionAmount { + return &ExceedsLimitError{ + Amount: amount, + Limit: MaxTransactionAmount, + } + } + + // Thread-safe operation + a.mu.Lock() + defer a.mu.Unlock() + + // Check if withdrawal would bring balance below minimum + if amount > 0 && a.Balance-amount < a.MinBalance { + return &InsufficientFundsError{ + RequestedAmount: amount, + CurrentBalance: a.Balance, + MinBalance: a.MinBalance, + } + } + + a.Balance -= amount + return nil +} + +// Transfer moves the specified amount from this account to the target account. +// It returns an error if the amount is invalid, exceeds the transaction limit, +// or would bring the balance below the minimum required balance. +func (a *BankAccount) Transfer(amount float64, target *BankAccount) error { + // Validate target account + if target == nil { + return &AccountError{ + Message: "target account cannot be nil", + Code: "INVALID_TARGET", + } + } + + // Validate amount + if amount < 0 { + return &NegativeAmountError{Amount: amount} + } + + if amount > MaxTransactionAmount { + return &ExceedsLimitError{ + Amount: amount, + Limit: MaxTransactionAmount, + } + } + + // Prevent self-transfer + if a == target { + return &AccountError{ + Message: "cannot transfer to the same account", + Code: "SELF_TRANSFER", + } + } + + // Lock both accounts in a consistent order to prevent deadlocks + // Always lock the account with the smaller ID first + var first, second *BankAccount + if strings.Compare(a.ID, target.ID) < 0 { + first, second = a, target + } else { + first, second = target, a + } + + first.mu.Lock() + defer first.mu.Unlock() + second.mu.Lock() + defer second.mu.Unlock() + + // Check if withdrawal would bring source balance below minimum + if amount > 0 && a.Balance-amount < a.MinBalance { + return &InsufficientFundsError{ + RequestedAmount: amount, + CurrentBalance: a.Balance, + MinBalance: a.MinBalance, + } + } + + // Perform the transfer + a.Balance -= amount + target.Balance += amount + + return nil +} + +// GetBalance returns the current balance (thread-safe read) +func (a *BankAccount) GetBalance() float64 { + a.mu.Lock() + defer a.mu.Unlock() + return a.Balance +} + +// String returns a string representation of the account +func (a *BankAccount) String() string { + a.mu.Lock() + defer a.mu.Unlock() + return fmt.Sprintf("Account[ID: %s, Owner: %s, Balance: %.2f, MinBalance: %.2f]", + a.ID, a.Owner, a.Balance, a.MinBalance) +} \ No newline at end of file From 83866558de9ee5f45f68cdbf4b9fc1b3a3647742 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Thu, 18 Sep 2025 23:01:10 +0330 Subject: [PATCH 08/23] Add solution for Challenge 4 by Ali-Fartoot --- challenge-4/submissions/Ali-Fartoot/solution-template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/challenge-4/submissions/Ali-Fartoot/solution-template.go b/challenge-4/submissions/Ali-Fartoot/solution-template.go index cb684bd2..f536fd32 100644 --- a/challenge-4/submissions/Ali-Fartoot/solution-template.go +++ b/challenge-4/submissions/Ali-Fartoot/solution-template.go @@ -39,6 +39,7 @@ func BFS(graph map[int][]int, start int) []int { return result } + // ConcurrentBFSQueries processes BFS queries concurrently using worker goroutines // Each worker processes queries from a shared job queue func ConcurrentBFSQueries(graph map[int][]int, queries []int, numWorkers int) map[int][]int { From e86aaac7b0b593d8657a9e894e1c2deee9df6181 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Thu, 18 Sep 2025 23:48:55 +0330 Subject: [PATCH 09/23] Add solution for Challenge 5 by Ali-Fartoot --- challenge-5/submissions/Ali-Fartoot/solution-template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/challenge-5/submissions/Ali-Fartoot/solution-template.go b/challenge-5/submissions/Ali-Fartoot/solution-template.go index 0d7a5fb9..eb58ec7e 100644 --- a/challenge-5/submissions/Ali-Fartoot/solution-template.go +++ b/challenge-5/submissions/Ali-Fartoot/solution-template.go @@ -32,6 +32,7 @@ func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello!") } + // secureHandler returns "You are authorized!" on GET /secure func secureHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "You are authorized!") From 074acc7be4a07b37c9764f689bb909e95d66bca4 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 19 Sep 2025 00:08:35 +0330 Subject: [PATCH 10/23] Add solution for Challenge 6 by Ali-Fartoot --- challenge-6/submissions/Ali-Fartoot/solution-template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/challenge-6/submissions/Ali-Fartoot/solution-template.go b/challenge-6/submissions/Ali-Fartoot/solution-template.go index 08de56dd..a7204bd7 100644 --- a/challenge-6/submissions/Ali-Fartoot/solution-template.go +++ b/challenge-6/submissions/Ali-Fartoot/solution-template.go @@ -27,3 +27,4 @@ func CountWordFrequency(text string) map[string]int { return counter } + From c121972235c8a5df8f8eee0ca786cd65c5c8e631 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 19 Sep 2025 00:11:45 +0330 Subject: [PATCH 11/23] Add solution for Challenge 7 by Ali-Fartoot --- challenge-7/submissions/Ali-Fartoot/solution-template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/challenge-7/submissions/Ali-Fartoot/solution-template.go b/challenge-7/submissions/Ali-Fartoot/solution-template.go index e336c420..cc0d9a25 100644 --- a/challenge-7/submissions/Ali-Fartoot/solution-template.go +++ b/challenge-7/submissions/Ali-Fartoot/solution-template.go @@ -231,6 +231,7 @@ func (a *BankAccount) GetBalance() float64 { return a.Balance } + // String returns a string representation of the account func (a *BankAccount) String() string { a.mu.Lock() From 8433705d7648cd6efc2eab9847ab45d2b8ee4dcb Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 19 Sep 2025 01:22:04 +0330 Subject: [PATCH 12/23] Add solution for Challenge 8 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 challenge-8/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-8/submissions/Ali-Fartoot/solution-template.go b/challenge-8/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..1aa8b884 --- /dev/null +++ b/challenge-8/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,154 @@ +package challenge8 + +import ( + "errors" + "fmt" + "sync" + "time" +) + +type Client struct { + Username string + Messages chan string + server *ChatServer +} + +type ChatServer struct { + clients map[string]*Client + broadcast chan BroadcastMessage + connect chan *Client + disconnect chan *Client + mutex sync.RWMutex +} + +type BroadcastMessage struct { + Sender *Client + Content string +} + +var ( + ErrUsernameAlreadyTaken = errors.New("username already taken") + ErrRecipientNotFound = errors.New("recipient not found") + ErrClientDisconnected = errors.New("client disconnected") +) + +func NewChatServer() *ChatServer { + s := &ChatServer{ + clients: make(map[string]*Client), + broadcast: make(chan BroadcastMessage, 1000), + connect: make(chan *Client, 1000), + disconnect: make(chan *Client, 1000), + } + go s.run() + return s +} + +func (s *ChatServer) run() { + for { + select { + case client := <-s.connect: + s.mutex.Lock() + s.clients[client.Username] = client + s.mutex.Unlock() + case client := <-s.disconnect: + s.mutex.Lock() + s.disconnectClient(client) + s.mutex.Unlock() + case msg := <-s.broadcast: + s.mutex.RLock() + for _, client := range s.clients { + if client.Username != msg.Sender.Username { + client.Send(fmt.Sprintf("%s: %s", msg.Sender.Username, msg.Content)) + } + } + s.mutex.RUnlock() + } + } +} + +func (s *ChatServer) Connect(username string) (*Client, error) { + s.mutex.RLock() + _, exists := s.clients[username] + s.mutex.RUnlock() + + if exists { + return nil, ErrUsernameAlreadyTaken + } + + client := &Client{ + Username: username, + Messages: make(chan string, 1000), + server: s, + } + + // Send connect request and wait a bit for it to be processed + s.connect <- client + time.Sleep(10 * time.Millisecond) + + return client, nil +} + +func (s *ChatServer) disconnectClient(client *Client) { + if _, exists := s.clients[client.Username]; exists { + close(client.Messages) + delete(s.clients, client.Username) + } +} + +func (s *ChatServer) Disconnect(client *Client) { + s.disconnect <- client + time.Sleep(10 * time.Millisecond) // Give time for disconnect to process +} + +func (s *ChatServer) Broadcast(sender *Client, message string) { + // Check if sender is still connected + s.mutex.RLock() + _, exists := s.clients[sender.Username] + s.mutex.RUnlock() + + if exists { + s.broadcast <- BroadcastMessage{Sender: sender, Content: message} + } +} + +func (s *ChatServer) PrivateMessage(sender *Client, recipient string, message string) error { + // Check if sender is still connected + s.mutex.RLock() + _, senderExists := s.clients[sender.Username] + recipientClient, recipientExists := s.clients[recipient] + s.mutex.RUnlock() + + if !senderExists { + return ErrClientDisconnected + } + + if !recipientExists { + return ErrRecipientNotFound + } + + formattedMessage := fmt.Sprintf("[Private from %s]: %s", sender.Username, message) + + select { + case recipientClient.Messages <- formattedMessage: + return nil + default: + return errors.New("recipient's message queue is full") + } +} + +func (c *Client) Send(message string) { + select { + case c.Messages <- message: + default: + // Message dropped - queue full + } +} + +func (c *Client) Receive() string { + msg, ok := <-c.Messages + if !ok { + // Channel closed + return "" + } + return msg +} \ No newline at end of file From 51749616b0b7104c7766ae2d9f3b84ff12f4ebe5 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 26 Sep 2025 12:18:19 +0330 Subject: [PATCH 13/23] Add solution for Challenge 18 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 challenge-18/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-18/submissions/Ali-Fartoot/solution-template.go b/challenge-18/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..4ad9e755 --- /dev/null +++ b/challenge-18/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "math" +) + +// CelsiusToFahrenheit converts a temperature from Celsius to Fahrenheit +// Formula: F = C × 9/5 + 32 +func CelsiusToFahrenheit(celsius float64) float64 { + F := celsius * (9.0 / 5.0) + 32 // Use floating-point division + return Round(F, 2) +} + +// FahrenheitToCelsius converts a temperature from Fahrenheit to Celsius +// Formula: C = (F - 32) × 5/9 +func FahrenheitToCelsius(fahrenheit float64) float64 { + C := (fahrenheit - 32) * (5.0 / 9.0) // Use floating-point division + return Round(C, 2) +} + +// Round rounds a float64 value to the specified number of decimal places +func Round(value float64, decimals int) float64 { + precision := math.Pow10(decimals) + return math.Round(value*precision) / precision +} + +func main() { + // Example usage + celsius := 25.0 + fahrenheit := CelsiusToFahrenheit(celsius) + fmt.Printf("%.2f°C is equal to %.2f°F\n", celsius, fahrenheit) + + fahrenheit = 68.0 + celsius = FahrenheitToCelsius(fahrenheit) + fmt.Printf("%.2f°F is equal to %.2f°C\n", fahrenheit, celsius) +} \ No newline at end of file From 521369b26b847e313d89ed1e326dd4c7e8f9530e Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 26 Sep 2025 12:59:37 +0330 Subject: [PATCH 14/23] Add solution for Challenge 21 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 challenge-21/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-21/submissions/Ali-Fartoot/solution-template.go b/challenge-21/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..38c13fb3 --- /dev/null +++ b/challenge-21/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" +) + +func main() { + // Example sorted array for testing + arr := []int{1, 3, 5, 7, 9, 11, 13, 15, 17, 19} + + // Test binary search + target := 7 + index := BinarySearch(arr, target) + fmt.Printf("BinarySearch: %d found at index %d\n", target, index) + + // Test recursive binary search + recursiveIndex := BinarySearchRecursive(arr, target, 0, len(arr)-1) + fmt.Printf("BinarySearchRecursive: %d found at index %d\n", target, recursiveIndex) + + // Test find insert position + insertTarget := 8 + insertPos := FindInsertPosition(arr, insertTarget) + fmt.Printf("FindInsertPosition: %d should be inserted at index %d\n", insertTarget, insertPos) +} + +// BinarySearch performs a standard binary search to find the target in the sorted array. +// Returns the index of the target if found, or -1 if not found. +func BinarySearch(arr []int, target int) int { + low := 0 + high := len(arr) - 1 + + for low <= high { + mid := low + (high - low ) / 2 + + if target == arr[mid] { + return mid + } else if target < arr[mid] { + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 +} + +// BinarySearchRecursive performs binary search using recursion. +// Returns the index of the target if found, or -1 if not found. +func BinarySearchRecursive(arr []int, target int, left int, right int) int { + if left > right { + return -1 + } + + + mid := left + (right - left) / 2 + + if target == arr[mid] { + return mid + + } else if target < arr[mid]{ + return BinarySearchRecursive(arr, target, left , mid - 1) + + } else{ + return BinarySearchRecursive(arr, target, mid + 1, right) + } + +} + +// FindInsertPosition returns the index where the target should be inserted +// to maintain the sorted order of the array. +func FindInsertPosition(arr []int, target int) int { + low := 0 + high := len(arr) - 1 + + for low <= high { + mid := low + (high-low)/2 + + if arr[mid] == target { + return mid + } else if target < arr[mid] { + high = mid - 1 + } else { + low = mid + 1 + } + } + return low +} From 37902de8354427c3c1979d68a3f68a1f51732eb0 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Fri, 26 Sep 2025 13:06:07 +0330 Subject: [PATCH 15/23] Add solution for Challenge 22 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 challenge-22/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-22/submissions/Ali-Fartoot/solution-template.go b/challenge-22/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..fc0833d2 --- /dev/null +++ b/challenge-22/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,92 @@ +package main + +import ( + "fmt" + "sort" +) + +func main() { + // Standard U.S. coin denominations in cents + denominations := []int{1, 5, 10, 25, 50} + + // Test amounts + amounts := []int{87, 42, 99, 33, 7} + + for _, amount := range amounts { + // Find minimum number of coins + minCoins := MinCoins(amount, denominations) + + // Find coin combination + coinCombo := CoinCombination(amount, denominations) + + // Print results + fmt.Printf("Amount: %d cents\n", amount) + fmt.Printf("Minimum coins needed: %d\n", minCoins) + fmt.Printf("Coin combination: %v\n", coinCombo) + fmt.Println("---------------------------") + } +} + +// MinCoins returns the minimum number of coins needed to make the given amount. +// If the amount cannot be made with the given denominations, return -1. +func MinCoins(amount int, denominations []int) int { + // Create a copy of denominations and sort in descending order + denoms := make([]int, len(denominations)) + copy(denoms, denominations) + sort.Sort(sort.Reverse(sort.IntSlice(denoms))) + + coins := 0 + remaining := amount + + for _, coin := range denoms { + if remaining <= 0 { + break + } + if coin <= remaining { + // Calculate how many of this coin we can use + count := remaining / coin + coins += count + remaining -= count * coin + } + } + + // If we couldn't make the exact amount, return -1 + if remaining != 0 { + return -1 + } + + return coins +} + +// CoinCombination returns a map with the specific combination of coins that gives +// the minimum number. The keys are coin denominations and values are the number of +// coins used for each denomination. +// If the amount cannot be made with the given denominations, return an empty map. +func CoinCombination(amount int, denominations []int) map[int]int { + // Create a copy of denominations and sort in descending order + denoms := make([]int, len(denominations)) + copy(denoms, denominations) + sort.Sort(sort.Reverse(sort.IntSlice(denoms))) + + coinMap := make(map[int]int) + remaining := amount + + for _, coin := range denoms { + if remaining <= 0 { + break + } + if coin <= remaining { + // Calculate how many of this coin we can use + count := remaining / coin + coinMap[coin] = count + remaining -= count * coin + } + } + + // If we couldn't make the exact amount, return empty map + if remaining != 0 { + return make(map[int]int) + } + + return coinMap +} \ No newline at end of file From 1b5cd803c7b42dc2f8871c169410ae8736fc4251 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Sun, 28 Sep 2025 10:39:07 +0330 Subject: [PATCH 16/23] Add solution for Challenge 30 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 challenge-30/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-30/submissions/Ali-Fartoot/solution-template.go b/challenge-30/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..f748514f --- /dev/null +++ b/challenge-30/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,176 @@ +package main + +import ( + "context" + "fmt" + "time" +) + +// ContextManager defines a simplified interface for basic context operations +type ContextManager interface { + // Create a cancellable context from a parent context + CreateCancellableContext(parent context.Context) (context.Context, context.CancelFunc) + + // Create a context with timeout + CreateTimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) + + // Add a value to context + AddValue(parent context.Context, key, value interface{}) context.Context + + // Get a value from context + GetValue(ctx context.Context, key interface{}) (interface{}, bool) + + // Execute a task with context cancellation support + ExecuteWithContext(ctx context.Context, task func() error) error + + // Wait for context cancellation or completion + WaitForCompletion(ctx context.Context, duration time.Duration) error +} + +// Simple context manager implementation +type simpleContextManager struct{} + +// NewContextManager creates a new context manager +func NewContextManager() ContextManager { + return &simpleContextManager{} +} + +// CreateCancellableContext creates a cancellable context +func (cm *simpleContextManager) CreateCancellableContext(parent context.Context) (context.Context, context.CancelFunc) { + // TODO: Implement cancellable context creation + // Hint: Use context.WithCancel(parent) + ctxWithCancel, cancel := context.WithCancel(parent) + return ctxWithCancel, cancel +} + +// CreateTimeoutContext creates a context with timeout +func (cm *simpleContextManager) CreateTimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) { + // TODO: Implement timeout context creation + // Hint: Use context.WithTimeout(parent, timeout) + return context.WithTimeout(parent, timeout) +} + +// AddValue adds a key-value pair to the context +func (cm *simpleContextManager) AddValue(parent context.Context, key, value interface{}) context.Context { + // TODO: Implement value context creation + // Hint: Use context.WithValue(parent, key, value) + return context.WithValue(parent, key, value) + +} + +// GetValue retrieves a value from the context +func (cm *simpleContextManager) GetValue(ctx context.Context, key interface{}) (interface{}, bool) { + // TODO: Implement value retrieval from context + // Hint: Use ctx.Value(key) and check if it's nil + // Return the value and a boolean indicating if it was found + value := ctx.Value(key) + + if value == nil { + return nil, false + } + + return value, true +} + +// ExecuteWithContext executes a task that can be cancelled via context +func (cm *simpleContextManager) ExecuteWithContext(ctx context.Context, task func() error) error { + // TODO: Implement task execution with context cancellation + // Hint: Run the task in a goroutine and use select with ctx.Done() + resultChan := make(chan error, 1) + + go func () { + resultChan <- task() + }() + + select { + case err := <- resultChan: + return err + + case <- ctx.Done(): + return ctx.Err() + } + +} + +// WaitForCompletion waits for a duration or until context is cancelled +func (cm *simpleContextManager) WaitForCompletion(ctx context.Context, duration time.Duration) error { + // TODO: Implement waiting with context awareness + // Hint: Use select with ctx.Done() and time.After(duration) + // Return context error if cancelled, nil if duration completes + timer := time.NewTimer(duration) + defer timer.Stop() + + select { + case <- ctx.Done(): + return ctx.Err() + + case <- timer.C: + return nil + } +} + +// Helper function - simulate work that can be cancelled +func SimulateWork(ctx context.Context, workDuration time.Duration, description string) error { + fmt.Printf("Starting work: %s (will take %v)\n", description, workDuration) + + // Create a timer for the work duration + timer := time.NewTimer(workDuration) + defer timer.Stop() + + select { + case <-timer.C: + // Work completed + fmt.Printf("Work completed: %s\n", description) + return nil + + case <-ctx.Done(): + // Context was cancelled + fmt.Printf("Work cancelled: %s\n", description) + return ctx.Err() + } +} + +// Helper function - process multiple items with context +func ProcessItems(ctx context.Context, items []string) ([]string, error) { + results := make([]string, 0, len(items)) + + for i, item := range items { + // Check for cancellation before processing each item + select { + case <-ctx.Done(): + fmt.Printf("Processing cancelled after %d items\n", i) + return results, ctx.Err() + default: + // Process the item + processedItem := fmt.Sprintf("processed_%s", item) + results = append(results, processedItem) + + // Sleep to simulate work, but only if not the last item + // This prevents unnecessary delay in successful completion + if i < len(items)-1 { + time.Sleep(100 * time.Millisecond) + } + } + } + return results, nil +} + +// Example usage +func main() { + fmt.Println("Context Management Challenge") + fmt.Println("Implement the context manager methods!") + + // Example of how the context manager should work: + cm := NewContextManager() + + // Create a cancellable context + ctx, cancel := cm.CreateCancellableContext(context.Background()) + defer cancel() + + // Add some values + ctx = cm.AddValue(ctx, "user", "alice") + ctx = cm.AddValue(ctx, "requestID", "12345") + + // Use the context + fmt.Println("Context created with values!") +} From f671faecd042e8baebafa8cc645b58dc8a58e2bf Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Sun, 28 Sep 2025 11:04:33 +0330 Subject: [PATCH 17/23] Add solution for Challenge 16 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 challenge-16/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-16/submissions/Ali-Fartoot/solution-template.go b/challenge-16/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..75e469ac --- /dev/null +++ b/challenge-16/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,201 @@ +package main + +import ( + "sort" + "strings" + "time" +) + +// SlowSort sorts a slice of integers using a very inefficient algorithm (bubble sort) +// TODO: Optimize this function to be more efficient +func SlowSort(data []int) []int { + // Make a copy to avoid modifying the original + result := make([]int, len(data)) + copy(result, data) + + // Bubble sort implementation + for i := 0; i < len(result); i++ { + for j := 0; j < len(result)-1; j++ { + if result[j] > result[j+1] { + result[j], result[j+1] = result[j+1], result[j] + } + } + } + + return result +} + +// OptimizedSort uses Go's built-in sort package which implements introsort +// (intro sort: a hybrid of quicksort, heapsort, and insertion sort) +// Time complexity: O(n log n) vs O(n²) for bubble sort +func OptimizedSort(data []int) []int { + // Make a copy to avoid modifying the original + result := make([]int, len(data)) + copy(result, data) + + // Use Go's highly optimized sort function + sort.Ints(result) + + return result +} + +// InefficientStringBuilder builds a string by repeatedly concatenating +// TODO: Optimize this function to be more efficient +func InefficientStringBuilder(parts []string, repeatCount int) string { + result := "" + + for i := 0; i < repeatCount; i++ { + for _, part := range parts { + result += part + } + } + + return result +} + +// OptimizedStringBuilder uses strings.Builder for efficient string concatenation +// strings.Builder minimizes memory copying by growing its internal buffer +func OptimizedStringBuilder(parts []string, repeatCount int) string { + // Calculate total length to minimize reallocations + totalLen := 0 + for _, part := range parts { + totalLen += len(part) + } + totalLen *= repeatCount + + var builder strings.Builder + builder.Grow(totalLen) // Pre-allocate capacity + + for i := 0; i < repeatCount; i++ { + for _, part := range parts { + builder.WriteString(part) + } + } + + return builder.String() +} + +// ExpensiveCalculation performs a computation with redundant work +// It computes the sum of all fibonacci numbers up to n +// TODO: Optimize this function to be more efficient +func ExpensiveCalculation(n int) int { + if n <= 0 { + return 0 + } + + sum := 0 + for i := 1; i <= n; i++ { + sum += fibonacci(i) + } + + return sum +} + +// Helper function that computes the fibonacci number at position n +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +// OptimizedCalculation uses dynamic programming to avoid redundant calculations +// Instead of recalculating fibonacci numbers, we compute them iteratively +func OptimizedCalculation(n int) int { + if n <= 0 { + return 0 + } + + sum := 0 + a, b := 0, 1 + + // Compute fibonacci numbers iteratively and sum them + for i := 1; i <= n; i++ { + if i == 1 { + sum += 1 + } else { + fib := a + b + sum += fib + a, b = b, fib + } + } + + return sum +} + +// HighAllocationSearch searches for all occurrences of a substring and creates a map with their positions +// TODO: Optimize this function to reduce allocations +func HighAllocationSearch(text, substr string) map[int]string { + result := make(map[int]string) + + // Convert to lowercase for case-insensitive search + lowerText := strings.ToLower(text) + lowerSubstr := strings.ToLower(substr) + + for i := 0; i < len(lowerText); i++ { + // Check if we can fit the substring starting at position i + if i+len(lowerSubstr) <= len(lowerText) { + // Extract the potential match + potentialMatch := lowerText[i : i+len(lowerSubstr)] + + // Check if it matches + if potentialMatch == lowerSubstr { + // Store the original case version + result[i] = text[i : i+len(substr)] + } + } + } + + return result +} + +// OptimizedSearch reduces allocations by avoiding temporary string creation +// and using more efficient string comparison methods +func OptimizedSearch(text, substr string) map[int]string { + if len(substr) == 0 { + return make(map[int]string) + } + + result := make(map[int]string) + textLen := len(text) + substrLen := len(substr) + + // Convert substr to lowercase once + lowerSubstr := strings.ToLower(substr) + + for i := 0; i <= textLen-substrLen; i++ { + // Compare characters directly without creating substring + match := true + for j := 0; j < substrLen; j++ { + // Convert to lowercase during comparison to avoid allocation + textChar := text[i+j] + if textChar >= 'A' && textChar <= 'Z' { + textChar += 32 // Convert to lowercase + } + + if textChar != lowerSubstr[j] { + match = false + break + } + } + + if match { + // Only allocate when we have a match + result[i] = text[i : i+substrLen] + } + } + + return result +} + +// A function to simulate CPU-intensive work for benchmarking +// You don't need to optimize this; it's just used for testing +func SimulateCPUWork(duration time.Duration) { + start := time.Now() + for time.Since(start) < duration { + // Just waste CPU cycles + for i := 0; i < 1000000; i++ { + _ = i + } + } +} \ No newline at end of file From e23ff56d32e539efe69543b64d31e8a5287a196d Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Mon, 29 Sep 2025 17:19:30 +0330 Subject: [PATCH 18/23] Add solution for Challenge 13 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 challenge-13/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-13/submissions/Ali-Fartoot/solution-template.go b/challenge-13/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..9c51d91d --- /dev/null +++ b/challenge-13/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,263 @@ +package main + +import ( + "database/sql" + "fmt" + + _ "github.com/mattn/go-sqlite3" +) + +// Product represents a product in the inventory system +type Product struct { + ID int64 + Name string + Price float64 + Quantity int + Category string +} + +// ProductStore manages product operations +type ProductStore struct { + db *sql.DB +} + +// NewProductStore creates a new ProductStore with the given database connection +func NewProductStore(db *sql.DB) *ProductStore { + return &ProductStore{db: db} +} + +var DB *sql.DB + +// InitDB sets up a new SQLite database and creates the products table +func InitDB(dbPath string) (*sql.DB, error) { + // Open a SQLite database connection + db, err := sql.Open("sqlite3", dbPath) + if err != nil { + return nil, err + } + + // Create the products table if it doesn't exist + sqlStmt := ` + CREATE TABLE IF NOT EXISTS products ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + price REAL NOT NULL, + quantity INTEGER NOT NULL, + category TEXT + ) + ` + _, err = db.Exec(sqlStmt) + if err != nil { + return nil, err + } + + return db, nil +} + +// CreateProduct adds a new product to the database +func (ps *ProductStore) CreateProduct(product *Product) error { + // Insert the product into the database + sqlQuery := ` + INSERT INTO products (name, price, quantity, category) + VALUES (?, ?, ?, ?) + ` + + result, err := ps.db.Exec(sqlQuery, product.Name, product.Price, product.Quantity, product.Category) + if err != nil { + return err + } + + // Update the product.ID with the database-generated ID + id, err := result.LastInsertId() + if err != nil { + return err + } + + product.ID = id + return nil +} + +// GetProduct retrieves a product by ID +func (ps *ProductStore) GetProduct(id int64) (*Product, error) { + // Query the database for a product with the given ID + sqlQuery := ` + SELECT id, name, price, quantity, category + FROM products + WHERE id = ? + ` + + var product Product + err := ps.db.QueryRow(sqlQuery, id).Scan( + &product.ID, + &product.Name, + &product.Price, + &product.Quantity, + &product.Category, + ) + + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("product not found with ID: %d", id) + } + return nil, fmt.Errorf("error querying product: %v", err) + } + + return &product, nil +} + +// UpdateProduct updates an existing product +func (ps *ProductStore) UpdateProduct(product *Product) error { + // Update the product in the database + sqlQuery := ` + UPDATE products + SET name = ?, price = ?, quantity = ?, category = ? + WHERE id = ? + ` + + result, err := ps.db.Exec(sqlQuery, + product.Name, + product.Price, + product.Quantity, + product.Category, + product.ID, + ) + + if err != nil { + return fmt.Errorf("error updating product: %v", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("error checking affected rows: %v", err) + } + + if rowsAffected == 0 { + return fmt.Errorf("product not found with ID: %d", product.ID) + } + + return nil +} + +// DeleteProduct removes a product by ID +func (ps *ProductStore) DeleteProduct(id int64) error { + // Delete the product from the database + sqlQuery := ` + DELETE FROM products + WHERE id = ? + ` + + result, err := ps.db.Exec(sqlQuery, id) + if err != nil { + return fmt.Errorf("error deleting product: %v", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("error checking affected rows: %v", err) + } + + if rowsAffected == 0 { + return fmt.Errorf("product not found with ID: %d", id) + } + + return nil +} + +// ListProducts returns all products with optional filtering by category +func (ps *ProductStore) ListProducts(category string) ([]*Product, error) { + sqlQuery := ` + SELECT id, name, price, quantity, category + FROM products + ` + + var args []interface{} + + if category != "" { + sqlQuery += " WHERE category = ?" + args = append(args, category) + } + + sqlQuery += " ORDER BY name ASC" + + rows, err := ps.db.Query(sqlQuery, args...) + if err != nil { + return nil, fmt.Errorf("error querying products: %v", err) + } + defer rows.Close() + + var products []*Product + + for rows.Next() { + var product Product + err := rows.Scan( + &product.ID, + &product.Name, + &product.Price, + &product.Quantity, + &product.Category, + ) + if err != nil { + return nil, fmt.Errorf("error scanning product row: %v", err) + } + + products = append(products, &product) + } + + if err = rows.Err(); err != nil { + return nil, fmt.Errorf("error iterating product rows: %v", err) + } + + return products, nil +} + +// BatchUpdateInventory updates the quantity of multiple products in a single transaction +// BatchUpdateInventory updates the quantity of multiple products in a single transaction +func (ps *ProductStore) BatchUpdateInventory(updates map[int64]int) error { + // Start a transaction + tx, err := ps.db.Begin() + if err != nil { + return fmt.Errorf("error beginning transaction: %v", err) + } + + // Defer a rollback in case anything fails + defer func() { + if err != nil { + tx.Rollback() + } + }() + + // Prepare the update statement + stmt, err := tx.Prepare(` + UPDATE products + SET quantity = ? + WHERE id = ? + `) + if err != nil { + return fmt.Errorf("error preparing update statement: %v", err) + } + defer stmt.Close() + + for productID, newQuantity := range updates { + // Update the product with the new quantity (not adding to it) + result, err := stmt.Exec(newQuantity, productID) + if err != nil { + return fmt.Errorf("error updating product %d: %v", productID, err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("error checking affected rows for product %d: %v", productID, err) + } + + if rowsAffected == 0 { + return fmt.Errorf("product not found with ID: %d", productID) + } + } + + err = tx.Commit() + if err != nil { + return fmt.Errorf("error committing transaction: %v", err) + } + + return nil +} \ No newline at end of file From f008d724306e7c8bfd9de9da455397bdab58b1d1 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Mon, 29 Sep 2025 18:47:57 +0330 Subject: [PATCH 19/23] Add solution for Challenge 10 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 challenge-10/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-10/submissions/Ali-Fartoot/solution-template.go b/challenge-10/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..bdb4b2ba --- /dev/null +++ b/challenge-10/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,184 @@ +// Package challenge10 contains the solution for Challenge 10. +package challenge10 + +import ( + "fmt" + "math" + // Add any necessary imports here +) + +// Shape interface defines methods that all shapes must implement +type Shape interface { + Area() float64 + Perimeter() float64 + fmt.Stringer // Includes String() string method +} + +// Rectangle represents a four-sided shape with perpendicular sides +type Rectangle struct { + Width float64 + Height float64 +} + +// NewRectangle creates a new Rectangle with validation +func NewRectangle(width, height float64) (*Rectangle, error) { + if width <= 0 || height <= 0 { + return nil, fmt.Errorf("zero input") + } + rectangle := Rectangle{ + Width: width, + Height: height, + } + return &rectangle, nil +} + +// Area calculates the area of the rectangle +func (r *Rectangle) Area() float64 { + return r.Width * r.Height +} + +// Perimeter calculates the perimeter of the rectangle +func (r *Rectangle) Perimeter() float64 { + return 2 * (r.Height + r.Width) +} + +// String returns a string representation of the rectangle +func (r *Rectangle) String() string { + return fmt.Sprintf("rectangle with width %.2f and height %.2f", r.Width, r.Height) + +} + +// Circle represents a perfectly round shape +type Circle struct { + Radius float64 +} + +// NewCircle creates a new Circle with validation +func NewCircle(radius float64) (*Circle, error) { + if radius <=0 { + return nil, fmt.Errorf("zero input") + } + circle := Circle { + Radius: radius, + } + + return &circle, nil +} + +// Area calculates the area of the circle +func (c *Circle) Area() float64 { + return c.Radius * c.Radius * math.Pi +} + +// Perimeter calculates the circumference of the circle +func (c *Circle) Perimeter() float64 { + return c.Radius * 2 * math.Pi +} + +// String returns a string representation of the circle +func (c *Circle) String() string { + // TODO: Implement string representation + return fmt.Sprintf("circle with radius %.2f", c.Radius) + +} + +// Triangle represents a three-sided polygon +type Triangle struct { + SideA float64 + SideB float64 + SideC float64 +} + +// NewTriangle creates a new Triangle with validation +func NewTriangle(a, b, c float64) (*Triangle, error) { + + if a >= b + c || b >= a + c || c >= a + b { + return nil, fmt.Errorf("inequality theorem") + } + if a <= 0 || b <= 0 || c<=0 { + return nil, fmt.Errorf("zero input") + } + triangle := Triangle { + SideA: a, + SideB: b, + SideC: c, + } + return &triangle, nil +} + +// Area calculates the area of the triangle using Heron's formula +func (t *Triangle) Area() float64 { + s := t.Perimeter() / 2 + return math.Sqrt(s * (s - t.SideA) * (s - t.SideB) * (s - t.SideC)) +} + +// Perimeter calculates the perimeter of the triangle +func (t *Triangle) Perimeter() float64 { + return t.SideA + t.SideB + t.SideC +} + +// String returns a string representation of the triangle +func (t *Triangle) String() string { + return fmt.Sprintf("triangle with sides %.2f, %.2f, and %.2f", t.SideA, t.SideB, t.SideC) + +} + +// ShapeCalculator provides utility functions for shapes +type ShapeCalculator struct{} + +// NewShapeCalculator creates a new ShapeCalculator +func NewShapeCalculator() *ShapeCalculator { + shapeCalculator := ShapeCalculator{} + return &shapeCalculator +} + +// PrintProperties prints the properties of a shape +func (sc *ShapeCalculator) PrintProperties(s Shape) { + s.String() +} + +// TotalArea calculates the sum of areas of all shapes +func (sc *ShapeCalculator) TotalArea(shapes []Shape) float64 { + totalArea := 0.0 + for _, shape := range shapes { + totalArea += shape.Area() + } + return totalArea +} + +// LargestShape finds the shape with the largest area +func (sc *ShapeCalculator) LargestShape(shapes []Shape) Shape { + latgestShape := 0.0 + var selectedShape Shape + + for _, shape := range shapes { + if latgestShape < shape.Area(){ + latgestShape = shape.Area() + selectedShape = shape + } + } + return selectedShape +} + +func (sc *ShapeCalculator) SortByArea(shapes []Shape, ascending bool) []Shape { + sortedShapes := make([]Shape, len(shapes)) + copy(sortedShapes, shapes) + + n := len(sortedShapes) + for i := 0; i < n-1; i++ { + for j := 0; j < n-i-1; j++ { + shouldSwap := false + if ascending { + shouldSwap = sortedShapes[j].Area() > sortedShapes[j+1].Area() + } else { + shouldSwap = sortedShapes[j].Area() < sortedShapes[j+1].Area() + } + + if shouldSwap { + sortedShapes[j], sortedShapes[j+1] = sortedShapes[j+1], sortedShapes[j] + } + } + } + + return sortedShapes +} \ No newline at end of file From 6204b4a6e3db8cf1e65c99ac1ba60381fb8405ef Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Mon, 29 Sep 2025 18:52:22 +0330 Subject: [PATCH 20/23] Add solution for Challenge 17 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 challenge-17/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-17/submissions/Ali-Fartoot/solution-template.go b/challenge-17/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..316c1d7a --- /dev/null +++ b/challenge-17/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,47 @@ +package main + + +import ( + "fmt" + "unicode" +) + + +func main() { + // Get input from the user + var input string + fmt.Print("Enter a string to check if it's a palindrome: ") + fmt.Scanln(&input) + + // Call the IsPalindrome function and print the result + result := IsPalindrome(input) + if result { + fmt.Println("The string is a palindrome.") + } else { + fmt.Println("The string is not a palindrome.") + } +} + +// IsPalindrome checks if a string is a palindrome. +// A palindrome reads the same backward as forward, ignoring case, spaces, and punctuation. +// IsPalindrome checks if a string is a palindrome. +// A palindrome reads the same backward as forward, ignoring case, spaces, and punctuation. +func IsPalindrome(s string) bool { + // Clean the string: convert to lowercase and remove non-alphanumeric characters + cleaned := make([]rune, 0, len(s)) + for _, r := range s { + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') { + cleaned = append(cleaned, unicode.ToLower(r)) + } + } + + // Check if the cleaned string is a palindrome + length := len(cleaned) + for i := 0; i < length/2; i++ { + if cleaned[i] != cleaned[length-1-i] { + return false + } + } + + return true +} \ No newline at end of file From e87f7e662c1ad3808dfb6085e59b9742b83bc069 Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Mon, 29 Sep 2025 19:09:02 +0330 Subject: [PATCH 21/23] Add solution for Challenge 19 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 challenge-19/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-19/submissions/Ali-Fartoot/solution-template.go b/challenge-19/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..de082291 --- /dev/null +++ b/challenge-19/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,95 @@ +package main + +import ( + "fmt" +) + +func main() { + // Example slice for testing + numbers := []int{3, 1, 4, 1, 5, 9, 2, 6} + + // Test FindMax + max := FindMax(numbers) + fmt.Printf("Maximum value: %d\n", max) + + // Test RemoveDuplicates + unique := RemoveDuplicates(numbers) + fmt.Printf("After removing duplicates: %v\n", unique) + + // Test ReverseSlice + reversed := ReverseSlice(numbers) + fmt.Printf("Reversed: %v\n", reversed) + + // Test FilterEven + evenOnly := FilterEven(numbers) + fmt.Printf("Even numbers only: %v\n", evenOnly) +} + +// FindMax returns the maximum value in a slice of integers. +// If the slice is empty, it returns 0. +func FindMax(numbers []int) int { + if len(numbers) == 0 { + return 0 + } + + max := numbers[0] + for _, num := range numbers { + if num > max { + max = num + } + } + return max +} + +// RemoveDuplicates returns a new slice with duplicate values removed, +// preserving the original order of elements. +func RemoveDuplicates(numbers []int) []int { + if len(numbers) == 0 { + return []int{} + } + + // Use a map to track seen values + seen := make(map[int]bool) + result := make([]int, 0) + + for _, num := range numbers { + if !seen[num] { + seen[num] = true + result = append(result, num) + } + } + return result +} + +// ReverseSlice returns a new slice with elements in reverse order. +func ReverseSlice(slice []int) []int { + if len(slice) == 0 { + return []int{} + } + + // Create a new slice to avoid modifying the original + reversed := make([]int, len(slice)) + + // Copy elements in reverse order + for i, j := 0, len(slice)-1; i < len(slice); i, j = i+1, j-1 { + reversed[i] = slice[j] + } + return reversed +} + +// FilterEven returns a new slice containing only the even numbers +// from the original slice. +func FilterEven(numbers []int) []int { + if len(numbers) == 0 { + return []int{} + } + + even := make([]int, 0) + + for _, num := range numbers { + if num%2 == 0 { + even = append(even, num) + } + } + return even +} \ No newline at end of file From 81fa08485963f8c25ff3c5347b69fc3217499efa Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Mon, 29 Sep 2025 19:17:39 +0330 Subject: [PATCH 22/23] Add solution for Challenge 23 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 challenge-23/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-23/submissions/Ali-Fartoot/solution-template.go b/challenge-23/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..d8fe0b44 --- /dev/null +++ b/challenge-23/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,186 @@ +package main + +import ( + "fmt" +) + +func main() { + testCases := []struct { + text string + pattern string + }{ + {"ABABDABACDABABCABAB", "ABABCABAB"}, + {"AABAACAADAABAABA", "AABA"}, + {"GEEKSFORGEEKS", "GEEK"}, + {"AAAAAA", "AA"}, + } + + for i, tc := range testCases { + fmt.Printf("Test Case %d:\n", i+1) + fmt.Printf("Text: %s\n", tc.text) + fmt.Printf("Pattern: %s\n", tc.pattern) + + naiveResults := NaivePatternMatch(tc.text, tc.pattern) + fmt.Printf("Naive Pattern Match: %v\n", naiveResults) + + kmpResults := KMPSearch(tc.text, tc.pattern) + fmt.Printf("KMP Search: %v\n", kmpResults) + + rkResults := RabinKarpSearch(tc.text, tc.pattern) + fmt.Printf("Rabin-Karp Search: %v\n", rkResults) + + fmt.Println("------------------------------") + } +} + +func NaivePatternMatch(text, pattern string) []int { + result := make([]int, 0) + n := len(text) + m := len(pattern) + + // Empty pattern should return empty result + if m == 0 { + return result + } + + // If text is empty or pattern is longer than text, no matches possible + if n == 0 || n < m { + return result + } + + for i := 0; i <= n-m; i++ { + match := true + for j := 0; j < m; j++ { + if text[i+j] != pattern[j] { + match = false + break + } + } + if match { + result = append(result, i) + } + } + + return result +} + +func KMPSearch(text, pattern string) []int { + result := make([]int, 0) + n := len(text) + m := len(pattern) + + // Empty pattern should return empty result + if m == 0 { + return result + } + + // If text is empty or pattern is longer than text, no matches possible + if n == 0 || n < m { + return result + } + + lps := computeLPSArray(pattern) + + i := 0 + j := 0 + + for i < n { + if text[i] == pattern[j] { + i++ + j++ + + if j == m { + result = append(result, i-j) + j = lps[j-1] + } + } else { + if j != 0 { + j = lps[j-1] + } else { + i++ + } + } + } + + return result +} + +func computeLPSArray(pattern string) []int { + m := len(pattern) + lps := make([]int, m) + length := 0 + + i := 1 + for i < m { + if pattern[i] == pattern[length] { + length++ + lps[i] = length + i++ + } else { + if length != 0 { + length = lps[length-1] + } else { + lps[i] = 0 + i++ + } + } + } + + return lps +} + +func RabinKarpSearch(text, pattern string) []int { + result := make([]int, 0) + n := len(text) + m := len(pattern) + + // Empty pattern should return empty result + if m == 0 { + return result + } + + // If text is empty or pattern is longer than text, no matches possible + if n == 0 || n < m { + return result + } + + const d = 256 + const q = 101 + + patternHash := 0 + textHash := 0 + h := 1 + + for i := 0; i < m-1; i++ { + h = (h * d) % q + } + + for i := 0; i < m; i++ { + patternHash = (d*patternHash + int(pattern[i])) % q + textHash = (d*textHash + int(text[i])) % q + } + + for i := 0; i <= n-m; i++ { + if patternHash == textHash { + match := true + for j := 0; j < m; j++ { + if text[i+j] != pattern[j] { + match = false + break + } + } + if match { + result = append(result, i) + } + } + + if i < n-m { + textHash = (d*(textHash-int(text[i])*h) + int(text[i+m])) % q + if textHash < 0 { + textHash += q + } + } + } + + return result +} \ No newline at end of file From f6b5c7435d1dc17f3daebdb55fb4c13c8ad42e0f Mon Sep 17 00:00:00 2001 From: Ali Fartoot Date: Tue, 30 Sep 2025 19:41:00 +0330 Subject: [PATCH 23/23] Add solution for Challenge 27 by Ali-Fartoot --- .../Ali-Fartoot/solution-template.go | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 challenge-27/submissions/Ali-Fartoot/solution-template.go diff --git a/challenge-27/submissions/Ali-Fartoot/solution-template.go b/challenge-27/submissions/Ali-Fartoot/solution-template.go new file mode 100644 index 00000000..3384000c --- /dev/null +++ b/challenge-27/submissions/Ali-Fartoot/solution-template.go @@ -0,0 +1,233 @@ +package generics + +import "errors" + +// ============================================================================ +// 1. Generic Pair +// ============================================================================ + +type Pair[T, U any] struct { + First T + Second U +} + +func NewPair[T, U any](first T, second U) Pair[T, U] { + return Pair[T, U]{First: first, Second: second} +} + +func (p Pair[T, U]) Swap() Pair[U, T] { + return Pair[U, T]{First: p.Second, Second: p.First} +} + +// ============================================================================ +// 2. Generic Stack +// ============================================================================ + +type Stack[T any] struct { + items []T +} + +func NewStack[T any]() *Stack[T] { + return &Stack[T]{items: make([]T, 0)} +} + +func (s *Stack[T]) Push(value T) { + s.items = append(s.items, value) +} + +func (s *Stack[T]) Pop() (T, error) { + var zero T + if len(s.items) == 0 { + return zero, errors.New("stack is empty") + } + index := len(s.items) - 1 + value := s.items[index] + s.items = s.items[:index] + return value, nil +} + +func (s *Stack[T]) Peek() (T, error) { + var zero T + if len(s.items) == 0 { + return zero, errors.New("stack is empty") + } + return s.items[len(s.items)-1], nil +} + +func (s *Stack[T]) Size() int { + return len(s.items) +} + +func (s *Stack[T]) IsEmpty() bool { + return len(s.items) == 0 +} + +// ============================================================================ +// 3. Generic Queue +// ============================================================================ + +type Queue[T any] struct { + items []T +} + +func NewQueue[T any]() *Queue[T] { + return &Queue[T]{items: make([]T, 0)} +} + +func (q *Queue[T]) Enqueue(value T) { + q.items = append(q.items, value) +} + +func (q *Queue[T]) Dequeue() (T, error) { + var zero T + if len(q.items) == 0 { + return zero, errors.New("queue is empty") + } + value := q.items[0] + q.items = q.items[1:] + return value, nil +} + +func (q *Queue[T]) Front() (T, error) { + var zero T + if len(q.items) == 0 { + return zero, errors.New("queue is empty") + } + return q.items[0], nil +} + +func (q *Queue[T]) Size() int { + return len(q.items) +} + +func (q *Queue[T]) IsEmpty() bool { + return len(q.items) == 0 +} + +// ============================================================================ +// 4. Generic Set +// ============================================================================ + +type Set[T comparable] struct { + items map[T]struct{} +} + +func NewSet[T comparable]() *Set[T] { + return &Set[T]{items: make(map[T]struct{})} +} + +func (s *Set[T]) Add(value T) { + s.items[value] = struct{}{} +} + +func (s *Set[T]) Remove(value T) { + delete(s.items, value) +} + +func (s *Set[T]) Contains(value T) bool { + _, exists := s.items[value] + return exists +} + +func (s *Set[T]) Size() int { + return len(s.items) +} + +func (s *Set[T]) Elements() []T { + elements := make([]T, 0, len(s.items)) + for k := range s.items { + elements = append(elements, k) + } + return elements +} + +func Union[T comparable](s1, s2 *Set[T]) *Set[T] { + result := NewSet[T]() + for k := range s1.items { + result.Add(k) + } + for k := range s2.items { + result.Add(k) + } + return result +} + +func Intersection[T comparable](s1, s2 *Set[T]) *Set[T] { + result := NewSet[T]() + for k := range s1.items { + if s2.Contains(k) { + result.Add(k) + } + } + return result +} + +func Difference[T comparable](s1, s2 *Set[T]) *Set[T] { + result := NewSet[T]() + for k := range s1.items { + if !s2.Contains(k) { + result.Add(k) + } + } + return result +} + +// ============================================================================ +// 5. Generic Utility Functions +// ============================================================================ + +func Filter[T any](slice []T, predicate func(T) bool) []T { + result := make([]T, 0) + for _, v := range slice { + if predicate(v) { + result = append(result, v) + } + } + return result +} + +func Map[T, U any](slice []T, mapper func(T) U) []U { + result := make([]U, len(slice)) + for i, v := range slice { + result[i] = mapper(v) + } + return result +} + +func Reduce[T, U any](slice []T, initial U, reducer func(U, T) U) U { + result := initial + for _, v := range slice { + result = reducer(result, v) + } + return result +} + +func Contains[T comparable](slice []T, element T) bool { + for _, v := range slice { + if v == element { + return true + } + } + return false +} + +func FindIndex[T comparable](slice []T, element T) int { + for i, v := range slice { + if v == element { + return i + } + } + return -1 +} + +func RemoveDuplicates[T comparable](slice []T) []T { + seen := make(map[T]struct{}) + result := make([]T, 0) + for _, v := range slice { + if _, exists := seen[v]; !exists { + seen[v] = struct{}{} + result = append(result, v) + } + } + return result +} \ No newline at end of file