├── .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 |
--------------------------------------------------------------------------------