├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── abundant_numbers ├── abundant_numbers.v └── abundant_numbers_test.v ├── balanced_parenthesis ├── balanced_parenthesis.v └── balanced_parenthesis_test.v ├── collatz_conjectue ├── collatz_conjecture.v └── collatz_conjecture_test.v ├── deficient_numbers ├── deficient_numbers.v └── deficient_numbers_test.v ├── gapful_numbers ├── gapful_numbers.v └── gapful_numbers_test.v ├── happy_numbers ├── happy_numbers.v └── happy_numbers_test.v ├── ip_validator ├── ip_validator.v └── ip_validator_test.v ├── palindrome_numbers ├── palindrome_numbers.v └── palindrome_numbers_test.v ├── password_validator ├── password_validator.v └── password_validator_test.v ├── remove_spaces ├── remove_spaces.v └── remove_spaces_test.v ├── strange_root ├── strange_root.v └── strange_root_test.v ├── string_rotation ├── string_rotation.v └── string_rotation_test.v ├── string_sort ├── string_sort.v └── string_sort_test.v ├── sudoku_validator ├── sudoku_validator.v └── sudoku_validator_test.v ├── summations_calculator ├── summations_calculator.v └── summations_calculator_test.v ├── util ├── algorithm │ └── quick_sort.v └── factors │ ├── factors.v │ └── factors_test.v ├── v.mod ├── valid_binary_string ├── valid_binary_string.v └── valid_binary_test.v └── vowel_counter ├── vowel_counter.v └── vowel_counter_test.v /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: serkonda7 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | schedule: 9 | - cron: '0 0 * * 1' 10 | 11 | jobs: 12 | code-style: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout V 16 | uses: actions/checkout@v2 17 | with: 18 | repository: vlang/v 19 | - name: Build V 20 | run: make 21 | - name: Checkout v-coding-challenges 22 | uses: actions/checkout@v2 23 | with: 24 | path: challenges 25 | - name: Run vet 26 | run: ./v vet -W challenges/ 27 | - name: Verify formatting 28 | run: | 29 | ./v fmt -verify challenges/ 30 | ./v fmt -diff challenges/ 31 | 32 | test: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Checkout V 36 | uses: actions/checkout@v2 37 | with: 38 | repository: vlang/v 39 | - name: Build V 40 | run: make 41 | - name: Checkout v-coding-challenges 42 | uses: actions/checkout@v2 43 | with: 44 | path: challenges 45 | - name: Run tests 46 | run: ./v test challenges 47 | - name: Run tests with warnings as errors 48 | run: ./v -W test challenges 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore build binaries 2 | * 3 | !*/ 4 | !*.* 5 | *.exe 6 | 7 | # Ignore editor files 8 | *.code-workspace 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 Lukas Neubert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # V Coding Challenges 2 | ![CI][ci-master] 3 | 4 | This repo is a collection of various coding challenges implemented in V.
5 | It can help V newcomers by providing lots of short and straightforward code pieces. 6 | 7 | ## License 8 | Licensed under the [MIT License](LICENSE.md) 9 | 10 | 11 | [ci-master]: https://github.com/serkonda7/v-coding-challenges/workflows/CI/badge.svg?branch=master 12 | -------------------------------------------------------------------------------- /abundant_numbers/abundant_numbers.v: -------------------------------------------------------------------------------- 1 | module abundant_numbers 2 | 3 | /* 4 | https://en.wikipedia.org/wiki/Abundant_number 5 | 6 | If the sum of factors of a number is greater than that number, it is considered to be abundant. 7 | 8 | Tasks: 9 | - (Easy) Verify whether a given number is abundant or not. 10 | - (Medium) Find all the abundant numbers in a range. 11 | - (Hard) Given a number, display its factors, their sum and then verify whether it's abundant or not. 12 | */ 13 | import math 14 | import util.factors 15 | 16 | // is_abundant checks whether a numbers factor sum is greater than that number 17 | pub fn is_abundant(num int) bool { 18 | if num <= 0 { 19 | return false 20 | } 21 | facs := factors.get_proper_factors(num) or { panic(err) } 22 | sum := factors.factor_sum(facs) 23 | return sum > num 24 | } 25 | 26 | // abundant_in_range returns all abundant numbers between ´min´ and ´max´ (exclusive) 27 | pub fn abundant_in_range(min int, max int) ?[]int { 28 | if min >= max { 29 | return error('´min´ has to be smaller than ´max´') 30 | } 31 | rmin := int(math.max(min, 1)) 32 | mut are_abundant := []int{} 33 | for i in rmin .. max { 34 | if is_abundant(i) { 35 | are_abundant << i 36 | } 37 | } 38 | return are_abundant 39 | } 40 | 41 | // get_abundancy returns the difference between a given numbers factor sum and the number 42 | // Non-abundant numbers produce negative values 43 | pub fn get_abundancy(num int) int { 44 | if num < 0 { 45 | return num 46 | } 47 | facs := factors.get_proper_factors(num) or { return 0 } 48 | sum := factors.factor_sum(facs) 49 | return sum - num 50 | } 51 | -------------------------------------------------------------------------------- /abundant_numbers/abundant_numbers_test.v: -------------------------------------------------------------------------------- 1 | module abundant_numbers 2 | 3 | fn test_is_abundant() { 4 | // Abundant numbers 5 | abd_nums := [12, 42, 945] 6 | for num in abd_nums { 7 | assert is_abundant(num) 8 | } 9 | // Not abundant numbers 10 | unadb_nums := [1, 13, 28, 98] 11 | for num in unadb_nums { 12 | assert !is_abundant(num) 13 | } 14 | // 0 and negative 15 | other_nums := [-12, -1, 0] 16 | for num in other_nums { 17 | assert !is_abundant(num) 18 | } 19 | } 20 | 21 | fn test_abundant_in_range() { 22 | ranges := [[0, 19], [29, 42], [940, 950], [12, 18]] 23 | expected := [ 24 | [12, 18], 25 | [30, 36, 40], 26 | [940, 942, 945, 948], 27 | [12], 28 | ] 29 | for i, range in ranges { 30 | res := abundant_in_range(range[0], range[1]) or { panic(err) } 31 | exp := expected[i] 32 | assert res == exp 33 | } 34 | } 35 | 36 | fn test_errors_abundant_in_range() { 37 | input_map := { 38 | '´min´ has to be smaller than ´max´': [99, 77] 39 | } 40 | mut expexted_errors := 1 41 | for msg, range in input_map { 42 | abundant_in_range(range[0], range[1]) or { 43 | expexted_errors-- 44 | assert err.msg == msg 45 | } 46 | } 47 | assert expexted_errors == 0 48 | } 49 | 50 | fn test_abundancy() { 51 | inputs := [-11, 0, 1, 12, 15, 18, 28, 70] 52 | expected := [-11, 0, -1, 4, -6, 3, 0, 4] 53 | for i, inp in inputs { 54 | exp := expected[i] 55 | assert get_abundancy(inp) == exp 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /balanced_parenthesis/balanced_parenthesis.v: -------------------------------------------------------------------------------- 1 | module balanced_parenthesis 2 | 3 | /* 4 | Create a program that checks if in a given string expression all the parenthesis are balanced. 5 | Also, take into account the "\" escape sequences: 6 | */ 7 | 8 | // is_balanced checks whether all parenthesis in a string are enclosed 9 | pub fn is_balanced(str string) bool { 10 | mut open_paren := 0 11 | mut open_brackets := 0 12 | mut open_curly := 0 13 | for i := 0; i < str.len; i++ { 14 | c := str[i] 15 | match c { 16 | `\\` { 17 | i++ 18 | continue 19 | } 20 | `(` { 21 | open_paren++ 22 | } 23 | `[` { 24 | open_brackets++ 25 | } 26 | `{` { 27 | open_curly++ 28 | } 29 | `)` { 30 | open_paren-- 31 | } 32 | `]` { 33 | open_brackets-- 34 | } 35 | `}` { 36 | open_curly-- 37 | } 38 | else {} 39 | } 40 | if open_paren < 0 || open_brackets < 0 || open_curly < 0 { 41 | return false 42 | } 43 | } 44 | return open_paren == 0 && open_brackets == 0 && open_curly == 0 45 | } 46 | -------------------------------------------------------------------------------- /balanced_parenthesis/balanced_parenthesis_test.v: -------------------------------------------------------------------------------- 1 | module balanced_parenthesis 2 | 3 | fn test_balanced() { 4 | inputs := ['', 'no parens here', '(test)', '()(())', '{val()id}', 'a[]b', '([{)]}'] 5 | for inp in inputs { 6 | assert is_balanced(inp) 7 | } 8 | } 9 | 10 | fn test_unbalanced() { 11 | inputs := ['(no()', '(123(456)(7))(', '(', ')', ')(', '[}', '([)['] 12 | for inp in inputs { 13 | assert !is_balanced(inp) 14 | } 15 | } 16 | 17 | fn test_with_escape() { 18 | inputs := [r'(nope\)', r'(v\(al)', r'{\]}[(])', r'\)(\))'] 19 | expected := [false, true, true, true] 20 | for i, inp in inputs { 21 | res := is_balanced(inp) 22 | exp := expected[i] 23 | assert res == exp 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /collatz_conjectue/collatz_conjecture.v: -------------------------------------------------------------------------------- 1 | module collatz_conjecture 2 | 3 | /* 4 | The Collatz conjecture (also known as the Ulam conjecture or the Syracuse problem) is an unsolved mathematical problem, which is very easy to formulate: 5 | 6 | 1. Take any natural number 7 | 2. If it's even, half it, otherwise triple it and add one 8 | 3. Repeat step 2. until you reach 4, 2, 1 sequence 9 | 4. You will ALWAYS reach 1, eventually. 10 | 11 | That last sequence: 4, 2, 1 is an infinitely repeating loop. The formulated conjecture is 12 | that for any x the sequence will always reach 4, 2, 1 ultimately. 13 | 14 | While the problem cannot be proved, the assignment is to write a code that will produce 15 | and print out the whole sequence for an input number. 16 | 17 | Both recursive and iterative approaches count. 18 | Bonus points for printing out how many iterations it took for x to converge to 1. 19 | */ 20 | 21 | // get_sequence_iterative returns the sequence of calculations for a given number and the number of steps. 22 | pub fn get_sequence_iterative(num int) ?([]string, int) { 23 | if num <= 0 { 24 | return error('Input has to be an natural number') 25 | } 26 | mut n := num 27 | mut sequence := []string{} 28 | mut steps := 0 29 | for { 30 | if n % 2 == 0 { 31 | res := n / 2 32 | sequence << '$n / 2 = $res' 33 | n = res 34 | } else { 35 | res := n * 3 + 1 36 | sequence << '$n * 3 + 1 = $res' 37 | n = res 38 | } 39 | steps++ 40 | if n == 1 { 41 | break 42 | } 43 | } 44 | return sequence, steps 45 | } 46 | 47 | // get_sequence_recursive returns the sequence of calculations for a given number and the number of steps. 48 | // This approach uses recursion. 49 | pub fn get_sequence_recursive(num int) ?([]string, int) { 50 | if num <= 0 { 51 | return error('Input has to be an natural number') 52 | } else if num == 1 { 53 | return []string{}, 0 54 | } 55 | mut res := 0 56 | mut sequence := [''] 57 | if num % 2 == 0 { 58 | res = num / 2 59 | sequence = ['$num / 2 = $res'] 60 | } else { 61 | res = num * 3 + 1 62 | sequence = ['$num * 3 + 1 = $res'] 63 | } 64 | seq, steps := get_sequence_recursive(res) ? 65 | sequence << seq 66 | return sequence, steps + 1 67 | } 68 | -------------------------------------------------------------------------------- /collatz_conjectue/collatz_conjecture_test.v: -------------------------------------------------------------------------------- 1 | module collatz_conjecture 2 | 3 | struct Input { 4 | num int 5 | sequence []string 6 | } 7 | 8 | const inputs = build_inputs() 9 | 10 | fn build_inputs() []Input { 11 | mut inp_array := []Input{} 12 | inp_array << Input{ 13 | num: 17 14 | sequence: [ 15 | '17 * 3 + 1 = 52', 16 | '52 / 2 = 26', 17 | '26 / 2 = 13', 18 | '13 * 3 + 1 = 40', 19 | '40 / 2 = 20', 20 | '20 / 2 = 10', 21 | '10 / 2 = 5', 22 | '5 * 3 + 1 = 16', 23 | '16 / 2 = 8', 24 | '8 / 2 = 4', 25 | '4 / 2 = 2', 26 | '2 / 2 = 1', 27 | ] 28 | } 29 | return inp_array 30 | } 31 | 32 | fn test_get_sequence_iterative() { 33 | for inp in collatz_conjecture.inputs { 34 | seq, steps := get_sequence_iterative(inp.num) or { panic(err) } 35 | assert seq == inp.sequence 36 | assert steps == inp.sequence.len 37 | } 38 | } 39 | 40 | fn test_get_sequence_recursive() { 41 | for inp in collatz_conjecture.inputs { 42 | seq, steps := get_sequence_recursive(inp.num) or { panic(err) } 43 | assert seq == inp.sequence 44 | assert steps == inp.sequence.len 45 | } 46 | } 47 | 48 | fn test_errors() { 49 | input_map := { 50 | 'Input has to be an natural number': [0, -2] 51 | } 52 | mut expexted_errors := 4 53 | for msg, inputs in input_map { 54 | for inp in collatz_conjecture.inputs { 55 | get_sequence_iterative(inp) or { 56 | expexted_errors-- 57 | assert err.msg == msg 58 | } 59 | get_sequence_recursive(inp) or { 60 | expexted_errors-- 61 | assert err.msg == msg 62 | } 63 | } 64 | } 65 | assert expexted_errors == 0 66 | } 67 | -------------------------------------------------------------------------------- /deficient_numbers/deficient_numbers.v: -------------------------------------------------------------------------------- 1 | module deficient_numbers 2 | 3 | /* 4 | https://en.wikipedia.org/wiki/Deficient_number 5 | 6 | A number is considered deficient if the sum of its factors is less than that number. 7 | 8 | Tasks: 9 | - (Easy) Write a program to verify whether a given number is deficient or not. 10 | - (Medium) Write a program to find all the deficient numbers in a range. 11 | - (Hard) Given a number, write a program to display its factors, their sum and then verify whether it's deficient or not. 12 | */ 13 | import math 14 | import util.factors 15 | 16 | // is_deficient checks whether a numbers factor sum is smaller than that number 17 | pub fn is_deficient(num int) bool { 18 | if num <= 0 { 19 | return false 20 | } 21 | facs := factors.get_proper_factors(num) or { panic(err) } 22 | sum := factors.factor_sum(facs) 23 | return sum < num 24 | } 25 | 26 | // deficient_in_range returns all deficient numbers between ´min´ and ´max´ (exclusive) 27 | pub fn deficient_in_range(min int, max int) ?[]int { 28 | if min >= max { 29 | return error('´min´ has to be smaller than ´max´') 30 | } 31 | rmin := int(math.max(min, 1)) 32 | mut are_deficient := []int{} 33 | for i in rmin .. max { 34 | if is_deficient(i) { 35 | are_deficient << i 36 | } 37 | } 38 | return are_deficient 39 | } 40 | 41 | // get_deficiency returns the difference between a given number and its factor sum 42 | // Non-deficient numbers produce negative values 43 | pub fn get_deficiency(num int) int { 44 | facs := factors.get_proper_factors(num) or { return 0 } 45 | sum := factors.factor_sum(facs) 46 | return num - sum 47 | } 48 | -------------------------------------------------------------------------------- /deficient_numbers/deficient_numbers_test.v: -------------------------------------------------------------------------------- 1 | module deficient_numbers 2 | 3 | fn test_is_deficient() { 4 | // Deficient numbers 5 | def_nums := [1, 2, 10, 86, 107] 6 | for num in def_nums { 7 | assert is_deficient(num) 8 | } 9 | // Not deficient numbers 10 | undef_nums := [18, 6, 42] 11 | for num in undef_nums { 12 | assert !is_deficient(num) 13 | } 14 | // 0 and negative 15 | other_nums := [-12, -1, 0] 16 | for num in other_nums { 17 | assert !is_deficient(num) 18 | } 19 | } 20 | 21 | fn test_deficient_in_range() { 22 | ranges := [[0, 7], [36, 42], [99, 107]] 23 | expected := [ 24 | [1, 2, 3, 4, 5], 25 | [37, 38, 39, 41], 26 | [99, 101, 103, 105, 106], 27 | ] 28 | for i, range in ranges { 29 | res := deficient_in_range(range[0], range[1]) or { panic(err) } 30 | exp := expected[i] 31 | assert res == exp 32 | } 33 | } 34 | 35 | fn test_errors_deficient_in_range() { 36 | input_map := { 37 | '´min´ has to be smaller than ´max´': [99, 77] 38 | } 39 | mut expexted_errors := 1 40 | for msg, range in input_map { 41 | deficient_in_range(range[0], range[1]) or { 42 | expexted_errors-- 43 | assert err.msg == msg 44 | } 45 | } 46 | assert expexted_errors == 0 47 | } 48 | 49 | fn test_deficiency() { 50 | inputs := [-12, 0, 1, 21, 28, 42, 50] 51 | expected := [-12, 0, 1, 10, 0, -12, 7] 52 | for i, inp in inputs { 53 | exp := expected[i] 54 | assert get_deficiency(inp) == exp 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /gapful_numbers/gapful_numbers.v: -------------------------------------------------------------------------------- 1 | module gapful_numbers 2 | 3 | /* 4 | A gapful number is a number of at least 3 digits that is divisible by the number formed by 5 | the first and last digit of the original number. 6 | 7 | Write a program to check if the user input is a gapful number or not. 8 | */ 9 | 10 | // is_gapful checks whether a given number is gapful (see description above) 11 | pub fn is_gapful(num int) ?bool { 12 | if num < 100 { 13 | return error('Number should have at least three digits') 14 | } 15 | num_str := num.str().bytes() 16 | divisor_str := num_str[0].ascii_str() + num_str.last().ascii_str() 17 | divisor := divisor_str.int() 18 | res := num % divisor 19 | return res == 0 20 | } 21 | 22 | // gapful_in_range returns all gapful numbers between ´start´ and ´end´ (exclusive) 23 | pub fn gapful_in_range(start int, end int) ?[]int { 24 | if start >= end { 25 | return error('´start´ has to be smaller than ´end´') 26 | } 27 | mut are_gapful := []int{} 28 | for i in start .. end { 29 | if is_gapful(i) or { false } { 30 | are_gapful << i 31 | } 32 | } 33 | return are_gapful 34 | } 35 | -------------------------------------------------------------------------------- /gapful_numbers/gapful_numbers_test.v: -------------------------------------------------------------------------------- 1 | module gapful_numbers 2 | 3 | fn test_is_gapful() { 4 | gapful_nums := [192, 583] 5 | for num in gapful_nums { 6 | res := is_gapful(num) or { panic(err) } 7 | assert res 8 | } 9 | ungapful_nums := [210, 1042] 10 | for num in ungapful_nums { 11 | res := is_gapful(num) or { panic(err) } 12 | assert !res 13 | } 14 | } 15 | 16 | fn test_errors_is_gapful() { 17 | input_map := { 18 | 'Number should have at least three digits': [13, 99] 19 | } 20 | mut expected_err_count := 2 21 | for msg, inputs in input_map { 22 | for num in inputs { 23 | is_gapful(num) or { 24 | expected_err_count-- 25 | assert err.msg == msg 26 | } 27 | } 28 | } 29 | assert expected_err_count == 0 30 | } 31 | 32 | fn test_gapful_range() { 33 | inputs := [[200, 250], [1030, 1045], [374, 396]] 34 | expected := [ 35 | [200, 220, 225, 231, 240, 242], 36 | [1030, 1032, 1035, 1037, 1040], 37 | [374, 385, 390], 38 | ] 39 | for i, inp in inputs { 40 | res := gapful_in_range(inp[0], inp[1]) or { panic(err) } 41 | exp := expected[i] 42 | assert res == exp 43 | } 44 | } 45 | 46 | fn test_errors_gapful_in_range() { 47 | input_map := { 48 | '´start´ has to be smaller than ´end´': [[200, 100], 49 | [100, 100]] 50 | } 51 | mut expected_err_count := 2 52 | for msg, inputs in input_map { 53 | for inp in inputs { 54 | gapful_in_range(inp[0], inp[1]) or { 55 | expected_err_count-- 56 | assert err.msg == msg 57 | } 58 | } 59 | } 60 | assert expected_err_count == 0 61 | } 62 | -------------------------------------------------------------------------------- /happy_numbers/happy_numbers.v: -------------------------------------------------------------------------------- 1 | module happy_numbers 2 | 3 | /* 4 | https://en.wikipedia.org/wiki/Happy_number 5 | 6 | If the repeated sum of squares of the digits of a number is equal to 1, it is considered to be happy. 7 | If the sum of squares of digits reaches 4, 1 can never be reached thus making the number unhappy or sad. 8 | 9 | Tasks: 10 | - (Easy) Write a program to verify whether a given number is happy or not. 11 | - (Medium) Write a program to find all the happy numbers in a range. 12 | - (Hard) Given a number, write a program to verify whether it's happy or not and to display every sum of squares operation performed till the result is obtained. 13 | */ 14 | 15 | // is_happy checks whether a numbers repeated sum of squares of the digits is equal to 1 16 | pub fn is_happy(num int) bool { 17 | res, _ := is_happy_with_optional_steps(num, false) 18 | return res 19 | } 20 | 21 | // happy_in_range returns all happy numbers between ´min´ and ´max´ (exclusive) 22 | pub fn happy_in_range(min int, max int) []int { 23 | mut are_happy := []int{} 24 | for i in min .. max { 25 | if is_happy(i) { 26 | are_happy << i 27 | } 28 | } 29 | return are_happy 30 | } 31 | 32 | // square_steps returns whether a number is happy and an array of the operations performed 33 | pub fn square_steps(num int) (bool, []string) { 34 | return is_happy_with_optional_steps(num, true) 35 | } 36 | 37 | fn is_happy_with_optional_steps(num int, with_steps bool) (bool, []string) { 38 | if num <= 0 { 39 | return false, []string{} 40 | } 41 | mut num2 := num 42 | mut steps := []string{} 43 | for { 44 | if num2 == 1 || num2 == 4 { 45 | break 46 | } 47 | mut sum := 0 48 | mut squares := []string{} 49 | for { 50 | if num2 <= 0 { 51 | break 52 | } 53 | rem := num2 % 10 54 | sum += (rem * rem) 55 | num2 = num2 / 10 56 | if with_steps { 57 | squares << '$rem * $rem' 58 | } 59 | } 60 | if with_steps { 61 | sqr_str := squares.reverse().join(' + ') 62 | steps << '$sqr_str = $sum' 63 | } 64 | num2 = sum 65 | } 66 | return num2 == 1, steps 67 | } 68 | -------------------------------------------------------------------------------- /happy_numbers/happy_numbers_test.v: -------------------------------------------------------------------------------- 1 | module happy_numbers 2 | 3 | fn test_is_happy() { 4 | happy_nums := [1, 23, 100] 5 | for num in happy_nums { 6 | assert is_happy(num) 7 | } 8 | sad_nums := [4, 15, 22] 9 | for num in sad_nums { 10 | assert !is_happy(num) 11 | } 12 | other_nums := [-12, -1, 0] 13 | for num in other_nums { 14 | assert !is_happy(num) 15 | } 16 | } 17 | 18 | fn test_happy_range() { 19 | inputs := [[1, 18], [95, 105], [10, 13]] 20 | expected := [ 21 | [1, 7, 10, 13], 22 | [97, 100, 103], 23 | [10], 24 | ] 25 | for i, inp in inputs { 26 | res := happy_in_range(inp[0], inp[1]) 27 | exp := expected[i] 28 | assert res == exp 29 | } 30 | } 31 | 32 | fn test_square_steps() { 33 | inputs := [13, 24] 34 | expected := [ 35 | ['1 * 1 + 3 * 3 = 10', '1 * 1 + 0 * 0 = 1'], 36 | ['2 * 2 + 4 * 4 = 20', '2 * 2 + 0 * 0 = 4'], 37 | ] 38 | for i, inp in inputs { 39 | _, steps := square_steps(inp) 40 | exp := expected[i] 41 | assert steps == exp 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ip_validator/ip_validator.v: -------------------------------------------------------------------------------- 1 | module ip_validator 2 | 3 | /* 4 | Given a string as input, create a program to evaluate whether or not it is a valid IPv4 address. 5 | 6 | A valid IP address should be in the form of: a.b.c.d where a, b, c and d are integer values ranging from 0 to 255 inclusive. 7 | 8 | To keep things simple, you do not need to consider subnets or special octet values. 9 | */ 10 | import regex 11 | 12 | // is_valid_ipv4 checks whether a IP adress is in valid IPv4 format 13 | pub fn is_valid_ipv4(ip string) bool { 14 | nums := ip.split('.') 15 | if nums.len != 4 { 16 | return false 17 | } 18 | mut no_digit_re := regex.regex_opt(r'\D') or { panic(err) } 19 | for n in nums { 20 | _, re_match := no_digit_re.find(n) 21 | if re_match != -1 { 22 | return false 23 | } 24 | if n.int() < 0 || n.int() > 255 { 25 | return false 26 | } 27 | } 28 | return true 29 | } 30 | -------------------------------------------------------------------------------- /ip_validator/ip_validator_test.v: -------------------------------------------------------------------------------- 1 | module ip_validator 2 | 3 | fn test_valid_ips() { 4 | ips := ['127.0.0.1', '127.255.255.255'] 5 | for ip in ips { 6 | assert is_valid_ipv4(ip) 7 | } 8 | } 9 | 10 | fn test_invalid_ips() { 11 | ips := ['257.0.0.1', '255a.0.0.1', '127.0.0.0.1', '1.2.3'] 12 | for ip in ips { 13 | assert !is_valid_ipv4(ip) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /palindrome_numbers/palindrome_numbers.v: -------------------------------------------------------------------------------- 1 | module palindrome_numbers 2 | 3 | /* 4 | Palindromic number is a number that is the same when written forwards or backwards. 5 | 6 | Create a program that takes a number as input and return whether the number is palindromic, or not. 7 | */ 8 | 9 | // is_palindrome checks whether a number is the same written forwards or backwards 10 | pub fn is_palindrome(num int) bool { 11 | return num.str() == num.str().reverse() 12 | } 13 | -------------------------------------------------------------------------------- /palindrome_numbers/palindrome_numbers_test.v: -------------------------------------------------------------------------------- 1 | module palindrome_numbers 2 | 3 | fn test_is_palindrome() { 4 | palindromes := [656, 111, 7337] 5 | for num in palindromes { 6 | assert is_palindrome(num) 7 | } 8 | others := [234, 42, 7347] 9 | for num in others { 10 | assert !is_palindrome(num) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /password_validator/password_validator.v: -------------------------------------------------------------------------------- 1 | module password_validator 2 | 3 | /* 4 | Password validator is a program that validates passwords to match specific rules. 5 | 6 | Write a program to checks if the user input is a valid password or not. 7 | */ 8 | import regex 9 | 10 | // Rule definitions 11 | const ( 12 | min_len = 6 13 | max_len = 14 14 | require_num = true 15 | require_lower = true 16 | require_upper = true 17 | require_special = true 18 | allow_spaces = false 19 | ) 20 | 21 | // is_valid checks whether a password conforms with the defined rules 22 | pub fn is_valid(password string) bool { 23 | if password.len < password_validator.min_len || password.len > password_validator.max_len { 24 | return false 25 | } 26 | if !password_validator.allow_spaces && password.count(' ') > 0 { 27 | return false 28 | } 29 | if password_validator.require_num { 30 | mut number_re := regex.regex_opt(r'\d') or { panic(err) } 31 | if number_re.find_all(password).len == 0 { 32 | return false 33 | } 34 | } 35 | if password_validator.require_lower { 36 | mut lower_re := regex.regex_opt(r'\a') or { panic(err) } 37 | if lower_re.find_all(password).len == 0 { 38 | return false 39 | } 40 | } 41 | if password_validator.require_upper { 42 | mut upper_re := regex.regex_opt(r'\A') or { panic(err) } 43 | if upper_re.find_all(password).len == 0 { 44 | return false 45 | } 46 | } 47 | if password_validator.require_special { 48 | mut special_re := regex.regex_opt(r'[^A-Za-z0-9]') or { panic(err) } 49 | if special_re.find_all(password).len == 0 { 50 | return false 51 | } 52 | } 53 | return true 54 | } 55 | -------------------------------------------------------------------------------- /password_validator/password_validator_test.v: -------------------------------------------------------------------------------- 1 | module password_validator 2 | 3 | fn test_pw_length() { 4 | passwords := ['1&Abc', '2&Abcde', '3&thisIsTooLong'] 5 | expected := [false, true, false] 6 | for i, pw in passwords { 7 | res := is_valid(pw) 8 | exp := expected[i] 9 | assert res == exp 10 | } 11 | } 12 | 13 | fn test_spaces() { 14 | passwords := ['1&Ab cde', '2&Abcde'] 15 | expected := [false, true] 16 | for i, pw in passwords { 17 | res := is_valid(pw) 18 | exp := expected[i] 19 | assert res == exp 20 | } 21 | } 22 | 23 | fn test_numbers() { 24 | passwords := ['@ABCdef', '&123hasNUM'] 25 | expected := [false, true] 26 | for i, pw in passwords { 27 | res := is_valid(pw) 28 | exp := expected[i] 29 | assert res == exp 30 | } 31 | } 32 | 33 | fn test_letter_case() { 34 | passwords := ['@1onlylower', '@2HIGHCASE', '3@miXEd'] 35 | expected := [false, false, true] 36 | for i, pw in passwords { 37 | res := is_valid(pw) 38 | exp := expected[i] 39 | assert res == exp 40 | } 41 | } 42 | 43 | fn test_special_chars() { 44 | passwords := ['noSpec1als', 'also3NONE', 'per?F3ct'] 45 | expected := [false, false, true] 46 | for i, pw in passwords { 47 | res := is_valid(pw) 48 | exp := expected[i] 49 | assert res == exp 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /remove_spaces/remove_spaces.v: -------------------------------------------------------------------------------- 1 | module remove_spaces 2 | 3 | // remove_spaces returns a input string with all spaces removed 4 | pub fn remove_spaces(str string) string { 5 | s := str.replace(' ', '') 6 | return s 7 | } 8 | -------------------------------------------------------------------------------- /remove_spaces/remove_spaces_test.v: -------------------------------------------------------------------------------- 1 | module remove_spaces 2 | 3 | fn test_remove_spaces() { 4 | inputs := [ 5 | 'ab c d e fgh i j kl mn opqr stuvwxyz', 6 | 'null', 7 | ' ', 8 | ' before', 9 | 'after ', 10 | '\tfo o\t', 11 | 'spam\neggs And Ham', 12 | ] 13 | expected := [ 14 | 'abcdefghijklmnopqrstuvwxyz', 15 | 'null', 16 | '', 17 | 'before', 18 | 'after', 19 | '\tfoo\t', 20 | 'spam\neggsAndHam', 21 | ] 22 | for i, inp in inputs { 23 | res := remove_spaces(inp) 24 | exp := expected[i] 25 | assert res == exp 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /strange_root/strange_root.v: -------------------------------------------------------------------------------- 1 | module strange_root 2 | 3 | /* 4 | A number has a strange root if its square and square root share any digit. 5 | 6 | > For example, 2 has a strange root because the square root of 2 equals 1.414 and it contains 4. 7 | 8 | Write a program to check if the user input has a strange root or not. 9 | Only consider the first three digits after the dot. 10 | */ 11 | import math 12 | 13 | // has_strange_root checks whether a number has a strange root (see description above) 14 | pub fn has_strange_root(num int) ?bool { 15 | if num < 0 { 16 | return error('Square root of negative numbers cannot be calculated') 17 | } 18 | 19 | square := num * num 20 | root := math.sqrtf(num) 21 | 22 | sqr_str := square.str() 23 | root_str := root.str() 24 | 25 | max_chars_count := if root_str.len >= 5 { 5 } else { root_str.len } 26 | root_chars := root.str()[0..max_chars_count] 27 | 28 | return sqr_str.contains_any(root_chars) 29 | } 30 | -------------------------------------------------------------------------------- /strange_root/strange_root_test.v: -------------------------------------------------------------------------------- 1 | module strange_root 2 | 3 | fn test_has_strange_root() { 4 | strange_root_nums := [0, 2, 11, 204] 5 | for num in strange_root_nums { 6 | res := has_strange_root(num) or { panic(err) } 7 | assert res 8 | } 9 | normal_nums := [3, 24] 10 | for num in normal_nums { 11 | res := has_strange_root(num) or { panic(err) } 12 | assert !res 13 | } 14 | } 15 | 16 | fn test_errors_has_strange_root() { 17 | input_map := { 18 | 'Square root of negative numbers cannot be calculated': [-4, -72] 19 | } 20 | mut expected_err_count := 2 21 | for msg, inputs in input_map { 22 | for num in inputs { 23 | has_strange_root(num) or { 24 | expected_err_count-- 25 | assert err.msg == msg 26 | } 27 | } 28 | } 29 | assert expected_err_count == 0 30 | } 31 | -------------------------------------------------------------------------------- /string_rotation/string_rotation.v: -------------------------------------------------------------------------------- 1 | module string_rotation 2 | 3 | /* 4 | Create a function that accepts a string argument and returns an array of strings, 5 | which are shifted versions of the argument string. 6 | 7 | The original string should be included in the output array. 8 | The order matters; each element of the output array should be the shifted version of the previous element. 9 | The output array should have the same length as the input string. 10 | The function should return an empty array when a zero-length String is provided as the argument. 11 | */ 12 | 13 | // rotated_string returns an array of shifted versions of the input string 14 | pub fn rotated_string(str string) []string { 15 | len := str.len 16 | mut rot_str := []string{len: len} 17 | for i in 0 .. len { 18 | last_str := if i > 0 { rot_str[i - 1] } else { str } 19 | s := last_str[1..len] + last_str[0].ascii_str() 20 | rot_str[i] = s 21 | } 22 | return rot_str 23 | } 24 | -------------------------------------------------------------------------------- /string_rotation/string_rotation_test.v: -------------------------------------------------------------------------------- 1 | module string_rotation 2 | 3 | fn test_rotated_string() { 4 | inputs := ['Hello', '', ' ', 'aBc1'] 5 | expected := [ 6 | ['elloH', 'lloHe', 'loHel', 'oHell', 'Hello'], 7 | [], 8 | [' ', ' '], 9 | ['Bc1a', 'c1aB', '1aBc', 'aBc1'], 10 | ] 11 | for i, inp in inputs { 12 | res := rotated_string(inp) 13 | exp := expected[i] 14 | assert res == exp 15 | assert res.len == inp.len 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /string_sort/string_sort.v: -------------------------------------------------------------------------------- 1 | module string_sort 2 | 3 | /* 4 | Given a string as input, output its characters alphabetically sorted from A to Z. 5 | 6 | Rules: 7 | - Special characters should go first. 8 | - Numbers should be before letters. 9 | - Whitespaces should be ignored. 10 | */ 11 | import util.algorithm 12 | 13 | // sort returns a given string sorted alphabetically 14 | pub fn sort(s string) string { 15 | mut chars := s.bytes().filter(it != ` `) 16 | algorithm.quick_sort(mut chars, 0, chars.len - 1) 17 | mut sorted := '' 18 | for c in chars { 19 | sorted += c.ascii_str() 20 | } 21 | return sorted 22 | } 23 | -------------------------------------------------------------------------------- /string_sort/string_sort_test.v: -------------------------------------------------------------------------------- 1 | module string_sort 2 | 3 | fn test_plain_text() { 4 | unsorted := ['challenge', 's p a c e', 'smallCAPS'] 5 | sorted := ['aceeghlln', 'aceps', 'ACPSallms'] 6 | for i, str in unsorted { 7 | exp := sorted[i] 8 | assert sort(str) == exp 9 | } 10 | } 11 | 12 | fn test_number_precedence() { 13 | input := 'happy42' 14 | exp := '24ahppy' 15 | assert sort(input) == exp 16 | } 17 | 18 | fn test_special_precedence() { 19 | unsorted := [r'$tar3', 'c_!e'] 20 | sorted := [r'$3art', '!_ce'] 21 | for i, str in unsorted { 22 | exp := sorted[i] 23 | assert sort(str) == exp 24 | } 25 | } 26 | 27 | fn test_empty_strings() { 28 | unsorted := [' ', ''] 29 | sorted := ['', ''] 30 | for i, str in unsorted { 31 | exp := sorted[i] 32 | assert sort(str) == exp 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sudoku_validator/sudoku_validator.v: -------------------------------------------------------------------------------- 1 | module sudoku_validator 2 | 3 | /* 4 | A solved sudoku puzzle is a matrix of typically 9*9 in which every row, every column 5 | and every block contains every number from 1 to 9 exactly once. 6 | 7 | > A block is a 3*3 area in the sudoku that you get by splitting it up into 9 even squares. 8 | 9 | Create an algorithm that checks any solved sudoku's validity. 10 | Bonus: Change the code to mark all mistakes in the sudoku puzzle. 11 | */ 12 | 13 | // is_valid returns whether a solved sudoku matrix is correct 14 | // and a map of all wrong fields per row 15 | pub fn is_valid(sudoku_rows [][]int) ?(bool, map[int][]int) { 16 | if sudoku_rows.len != 9 { 17 | return error('Expected 9 rows, got $sudoku_rows.len') 18 | } 19 | for i, row in sudoku_rows { 20 | if row.len != 9 { 21 | return error('Expected 9 columns, but row ${i + 1} only has $row.len') 22 | } 23 | } 24 | 25 | mut cols := [][]int{len: 9} 26 | for row in sudoku_rows { 27 | for j, val in row { 28 | if val < 1 || val > 9 { 29 | return false, map[int][]int{} 30 | } 31 | cols[j] << val 32 | } 33 | } 34 | 35 | mut wrong_fields := map[int][]int{} 36 | for r, row in sudoku_rows { 37 | for n in 1 .. 10 { 38 | idx1 := row.index(n) 39 | idx2 := 8 - row.reverse().index(n) 40 | if idx1 >= 0 && idx1 != idx2 { 41 | wrong_fields[r] << idx1 42 | wrong_fields[r] << idx2 43 | } 44 | } 45 | } 46 | for c, col in cols { 47 | for n in 1 .. 10 { 48 | idx1 := col.index(n) 49 | idx2 := 8 - col.reverse().index(n) 50 | if idx1 >= 0 && idx1 != idx2 { 51 | if c !in wrong_fields[idx1] { 52 | wrong_fields[idx1] << c 53 | } 54 | if c !in wrong_fields[idx2] { 55 | wrong_fields[idx2] << c 56 | } 57 | } 58 | } 59 | } 60 | 61 | return wrong_fields.keys().len == 0, wrong_fields 62 | } 63 | -------------------------------------------------------------------------------- /sudoku_validator/sudoku_validator_test.v: -------------------------------------------------------------------------------- 1 | module sudoku_validator 2 | 3 | fn test_valid_sudokus() { 4 | mut sudokus := [][][]int{} 5 | sudokus << [ 6 | [3, 5, 2, 9, 1, 8, 6, 7, 4], 7 | [8, 9, 7, 2, 4, 6, 5, 1, 3], 8 | [6, 4, 1, 7, 5, 3, 2, 8, 9], 9 | [7, 8, 3, 5, 6, 9, 4, 2, 1], 10 | [9, 2, 6, 1, 3, 4, 7, 5, 8], 11 | [4, 1, 5, 8, 2, 7, 9, 3, 6], 12 | [1, 6, 4, 3, 7, 5, 8, 9, 2], 13 | [2, 7, 8, 4, 9, 1, 3, 6, 5], 14 | [5, 3, 9, 6, 8, 2, 1, 4, 7], 15 | ] 16 | for s in sudokus { 17 | res, _ := is_valid(s) or { panic(err) } 18 | assert res 19 | } 20 | } 21 | 22 | struct InvalidInput { 23 | sudoku [][]int 24 | indices map[int][]int 25 | } 26 | 27 | fn test_invalid_sudokus() { 28 | mut inputs := []InvalidInput{} 29 | inputs << InvalidInput{[ 30 | [3, 5, 2, 9, 1, 8, 6, 7, 4], 31 | [8, 9, 7, 2, 4, 6, 5, 1, 3], 32 | [6, 4, 1, 7, 5, 3, 2, 8, 9], 33 | [7, 8, 3, 5, 6, 9, 4, 2, 1], 34 | [9, 2, 6, 1, 3, 4, 7, 5, 8], 35 | [4, 1, 5, 8, 2, 7, 9, 3, 6], 36 | [9, 6, 4, 3, 7, 5, 8, 9, 2], 37 | [2, 7, 8, 4, 9, 1, 3, 6, 5], 38 | [5, 3, 9, 6, 8, 2, 1, 4, 7], 39 | ], { 40 | 4: [0] 41 | 6: [0, 7] 42 | }} 43 | for inp in inputs { 44 | res, indices := is_valid(inp.sudoku) or { panic(err) } 45 | assert !res 46 | assert indices == inp.indices 47 | } 48 | } 49 | 50 | fn test_sudoku_errors() { 51 | input_map := { 52 | 'Expected 9 rows, got 7': [[0], [1], 53 | [2], [3], [4], [5], [6]] 54 | 'Expected 9 columns, but row 1 only has 5': [[0, 1, 2, 3, 4], 55 | [1], [2], [3], [4], [5], [6], [7], [8]] 56 | 'Expected 9 columns, but row 2 only has 3': [[0, 1, 2, 3, 4, 5, 6, 7, 8], 57 | [1, 2, 3], [2], [3], [4], [5], [6], [7], [8]] 58 | } 59 | mut expexted_errors := 3 60 | for msg, sudoku_rows in input_map { 61 | is_valid(sudoku_rows) or { 62 | expexted_errors-- 63 | assert err.msg == msg 64 | } 65 | } 66 | assert expexted_errors == 0 67 | } 68 | -------------------------------------------------------------------------------- /summations_calculator/summations_calculator.v: -------------------------------------------------------------------------------- 1 | module summations_calculator 2 | 3 | /* 4 | Create a program that takes 3 inputs, a lower bound, an upper bound and the expression. Calculate the sum of that range based on the given expression and output the result. 5 | */ 6 | 7 | const expr_funcs = { 8 | '+': add 9 | '-': sub 10 | '*': mult 11 | 'x': mult 12 | '/': div 13 | '%': modulo 14 | } 15 | 16 | // get_summation returns the sum using the given expression for the range from ´min´ to ´max´ (inclusive) 17 | pub fn get_summation(min int, max int, expression string) ?int { 18 | expr := expression.replace(' ', '') 19 | expr_type := expr[0].ascii_str() 20 | if expr_type !in summations_calculator.expr_funcs { 21 | return error('Unknown type for expression: `$expression`') 22 | } 23 | expr_num := expr[1..].int() 24 | func := summations_calculator.expr_funcs[expr_type] 25 | mut sum := 0 26 | for i in min .. max + 1 { 27 | step := func(i, expr_num) 28 | sum += step 29 | } 30 | return sum 31 | } 32 | 33 | // Mathematic helper functions 34 | fn add(a int, b int) int { 35 | return a + b 36 | } 37 | 38 | fn sub(a int, b int) int { 39 | return a - b 40 | } 41 | 42 | fn mult(a int, b int) int { 43 | return a * b 44 | } 45 | 46 | fn div(a int, b int) int { 47 | return a / b 48 | } 49 | 50 | fn modulo(a int, b int) int { 51 | return a % b 52 | } 53 | -------------------------------------------------------------------------------- /summations_calculator/summations_calculator_test.v: -------------------------------------------------------------------------------- 1 | module summations_calculator 2 | 3 | struct Input { 4 | min int 5 | max int 6 | expression string 7 | } 8 | 9 | fn test_get_summation() { 10 | summations := [ 11 | Input{1, 3, '+3'}, 12 | Input{2, 4, '+ 2'}, 13 | Input{10, 12, '-10'}, 14 | Input{2, 4, '*2'}, 15 | Input{3, 5, 'x3'}, 16 | Input{4, 8, '/2'}, 17 | Input{1, 5, '%2'}, 18 | ] 19 | expected := [15, 15, 3, 18, 36, 14, 3] 20 | for i, inp in summations { 21 | res := get_summation(inp.min, inp.max, inp.expression) or { panic(err) } 22 | exp := expected[i] 23 | assert res == exp 24 | } 25 | } 26 | 27 | fn test_errors() { 28 | mut errors := 0 29 | inp := Input{1, 3, 'y 3'} 30 | get_summation(inp.min, inp.max, inp.expression) or { 31 | errors++ 32 | assert err.msg == 'Unknown type for expression: `y 3`' 33 | } 34 | assert errors == 1 35 | } 36 | -------------------------------------------------------------------------------- /util/algorithm/quick_sort.v: -------------------------------------------------------------------------------- 1 | module algorithm 2 | 3 | // quick_sort sorts an array of bytes 4 | pub fn quick_sort(mut chars []byte, l int, r int) { 5 | if l >= r { 6 | return 7 | } 8 | mut piv := l 9 | for i in l + 1 .. r + 1 { 10 | if chars[i] < chars[l] { 11 | piv++ 12 | chars[i], chars[piv] = chars[piv], chars[i] 13 | } 14 | } 15 | chars[l], chars[piv] = chars[piv], chars[l] 16 | quick_sort(mut chars, l, piv - 1) 17 | quick_sort(mut chars, piv + 1, r) 18 | } 19 | -------------------------------------------------------------------------------- /util/factors/factors.v: -------------------------------------------------------------------------------- 1 | module factors 2 | 3 | import math 4 | 5 | // get_proper_factors returns all factors of a number except the number itself 6 | pub fn get_proper_factors(num int) ?[]int { 7 | if num == 0 { 8 | return error('Cannot get factors of `0`') 9 | } 10 | is_negative := num < 0 11 | abs_num := int(math.abs(num)) 12 | mut factors := []int{} 13 | max_factor := (abs_num / 2) + 1 14 | if max_factor == 1 { 15 | return [] 16 | } 17 | for i in 1 .. max_factor { 18 | if num % i == 0 { 19 | factors << i 20 | if is_negative { 21 | factors << -i 22 | } 23 | } 24 | } 25 | return factors 26 | } 27 | 28 | // get_factors returns all factors of a number including the number itself 29 | pub fn get_factors(num int) ?[]int { 30 | mut factors := get_proper_factors(num) or { return err } 31 | is_negative := num < 0 32 | factors << num 33 | if is_negative { 34 | factors << -num 35 | } 36 | return factors 37 | } 38 | 39 | // factor_sum returns the sum of an array of factors 40 | pub fn factor_sum(factors []int) int { 41 | mut sum := 0 42 | for f in factors { 43 | sum += f 44 | } 45 | return sum 46 | } 47 | -------------------------------------------------------------------------------- /util/factors/factors_test.v: -------------------------------------------------------------------------------- 1 | module factors 2 | 3 | fn test_get_proper_factors() { 4 | numbers := [-1, 1, 2, 15] 5 | factors := [ 6 | []int{}, 7 | []int{}, 8 | [1], 9 | [1, 3, 5], 10 | ] 11 | for i, num in numbers { 12 | res := get_proper_factors(num) or { panic(err) } 13 | exp := factors[i] 14 | assert res == exp 15 | } 16 | } 17 | 18 | fn test_positive_num_factors() { 19 | numbers := [1, 12, 15, 945] 20 | factors := [ 21 | [1], 22 | [1, 2, 3, 4, 6, 12], 23 | [1, 3, 5, 15], 24 | [1, 3, 5, 7, 9, 15, 21, 27, 35, 45, 63, 105, 135, 189, 315, 945], 25 | ] 26 | for i, num in numbers { 27 | res := get_factors(num) or { panic(err) } 28 | exp := factors[i] 29 | assert res == exp 30 | } 31 | } 32 | 33 | fn test_factors_of_zero() { 34 | mut expected_err_count := 1 35 | get_factors(0) or { 36 | expected_err_count-- 37 | assert err.msg == 'Cannot get factors of `0`' 38 | } 39 | assert expected_err_count == 0 40 | } 41 | 42 | fn test_negative_num_factors() { 43 | numbers := [-1, -8, -15] 44 | factors := [ 45 | [-1, 1], 46 | [-8, -4, -2, -1, 1, 2, 4, 8], 47 | [-15, -5, -3, -1, 1, 3, 5, 15], 48 | ] 49 | for i, num in numbers { 50 | mut res := get_factors(num) or { panic(err) } 51 | res.sort() 52 | exp := factors[i] 53 | assert res == exp 54 | } 55 | } 56 | 57 | fn test_factor_sum() { 58 | // Positive 59 | pos_sum := factor_sum([1, 2, 3, 4, 6]) 60 | assert pos_sum == 16 61 | // With negative 62 | all_sum := factor_sum([-4, -2, -1, 1, 2, 4]) 63 | assert all_sum == 0 64 | } 65 | -------------------------------------------------------------------------------- /v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'v-coding-challenges' 3 | description: 'Various coding challenges from implemented in V.' 4 | author: 'Lukas Neubert ' 5 | license: 'MIT' 6 | repo_url: 'https://github.com/serkonda7/v-coding-challenges' 7 | dependencies: [] 8 | } 9 | -------------------------------------------------------------------------------- /valid_binary_string/valid_binary_string.v: -------------------------------------------------------------------------------- 1 | module valid_binary_string 2 | 3 | /* 4 | A valid binary string is a string that contains only 1's and 0's. 5 | 6 | Write a program to check if the user input is a valid binary string or not. 7 | */ 8 | 9 | // is_binary_string checks whether a string consists only of 0's and 1's 10 | pub fn is_binary_string(str string) bool { 11 | if str.len == 0 { 12 | return false 13 | } 14 | zeros := str.count('0') 15 | ones := str.count('1') 16 | return zeros + ones == str.len 17 | } 18 | -------------------------------------------------------------------------------- /valid_binary_string/valid_binary_test.v: -------------------------------------------------------------------------------- 1 | module valid_binary_string 2 | 3 | fn test_valid_strings() { 4 | inputs := ['101011', '000', '111'] 5 | for inp in inputs { 6 | assert is_binary_string(inp) 7 | } 8 | } 9 | 10 | fn test_invalid_strings() { 11 | inputs := ['Abc010', '', ' ', 'hello', '123'] 12 | for inp in inputs { 13 | assert !is_binary_string(inp) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vowel_counter/vowel_counter.v: -------------------------------------------------------------------------------- 1 | module vowel_counter 2 | 3 | /* 4 | Five of the 26 English alphabet letters are vowels: A, E, I, O, and U. 5 | 6 | Write a program that takes string input and outputs the count of the vowels in the string. 7 | */ 8 | 9 | const vowel_str = 'aeiou' 10 | 11 | // vowel_count returns the number of vowels in a given string 12 | pub fn vowel_count(str string) int { 13 | chars := str.to_lower().split('') 14 | vowels := chars.filter(vowel_counter.vowel_str.contains(it)) 15 | return vowels.len 16 | } 17 | -------------------------------------------------------------------------------- /vowel_counter/vowel_counter_test.v: -------------------------------------------------------------------------------- 1 | module vowel_counter 2 | 3 | fn test_vowel_count() { 4 | strings := ['SoloLearn', 'Programming', 'Lorem Ipsum', 'Hello, World!', ''] 5 | counts := [4, 3, 4, 3, 0] 6 | for i, str in strings { 7 | res := vowel_count(str) 8 | exp := counts[i] 9 | assert res == exp 10 | } 11 | } 12 | --------------------------------------------------------------------------------