diff --git a/config.json b/config.json index 2f2c238..3c4f6d2 100644 --- a/config.json +++ b/config.json @@ -185,8 +185,12 @@ "uuid": "99408193-d0ce-4c68-8cab-e680f3ed56a4", "practices": [], "prerequisites": [], - "difficulty": 2, - "status": "wip" + "difficulty": 5, + "topics": [ + "math", + "strings", + "loops" + ] }, { "slug": "hello-world", diff --git a/exercises/practice/grains/.docs/instructions.append.md b/exercises/practice/grains/.docs/instructions.append.md new file mode 100644 index 0000000..3a4ce49 --- /dev/null +++ b/exercises/practice/grains/.docs/instructions.append.md @@ -0,0 +1,13 @@ +## Maximum integer value + +According to [the Vim docs][number]: + +> Assuming 64 bit numbers are used (see v:numbersize) an unsigned number is truncated to 0x7fffffffffffffff or 9223372036854775807. + +In other words, Vimscript cannot express any number `2^63` or greater as an integer. + +Some of the tests for this exercise require 64 bit integers which is behond the integer size limitation ov Vimscript. +Because of this limitation, the results of the calculations are tested against a string which expresses the integer value, rather than expressing the answer as Integer. +Can you solve this by avoiding numbers that are larger than the language will allow directly? + +[number]: https://vimhelp.org/eval.txt.html#expr-number diff --git a/exercises/practice/grains/.meta/config.json b/exercises/practice/grains/.meta/config.json index c090ed4..a248d17 100644 --- a/exercises/practice/grains/.meta/config.json +++ b/exercises/practice/grains/.meta/config.json @@ -1,6 +1,8 @@ { "authors": [ - "BNAndras" + "BNAndras", + "KOTP", + "glennj" ], "files": { "solution": [ diff --git a/exercises/practice/grains/.meta/example.vim b/exercises/practice/grains/.meta/example.vim index 2848401..ea5fcf5 100644 --- a/exercises/practice/grains/.meta/example.vim +++ b/exercises/practice/grains/.meta/example.vim @@ -1,11 +1,59 @@ -function! Square(number) abort - if a:number < 1 || a:number > 64 - throw 'square must be between 1 and 64' - endif +" Helper function to add two large numbers represented as strings +function! StringAdd(num1, num2) + let carry = 0 + let result = '' - return float2nr(pow(2, (a:number-1))) + " Pad the shorter number with leading zeros + let len1 = strlen(a:num1) + let len2 = strlen(a:num2) + if len1 < len2 + let a:num1 = repeat('0', len2 - len1) . a:num1 + elseif len2 < len1 + let a:num2 = repeat('0', len1 - len2) . a:num2 + endif + + " Add digits from right to left + for i in range(strlen(a:num1) - 1, 0, -1) + let sum = str2nr(a:num1[i]) + str2nr(a:num2[i]) + carry + let carry = sum >= 10 ? 1 : 0 + let result = string(sum % 10) . result + endfor + + " Add the last carry if it exists + if carry > 0 + let result = '1' . result + endif + + return result endfunction -function! Total() abort - return float2nr(pow(2, 64) - 1) +" Function to calculate grains on a specific square using string manipulation +function! Square(n) + if a:n < 1 || a:n > 64 + throw 'square must be between 1 and 64' + endif + + " Start with 1 grain on the first square + let grains = '1' + for i in range(2, a:n) + " Double the grains by adding it to itself + let grains = StringAdd(grains, grains) + endfor + + return grains +endfunction + +" Function to calculate the total grains on the chessboard using string manipulation +function! Total() + let total = '0' + + " Accumulate grains for each square from 1 to 64 + let grains = '1' + for i in range(1, 64) + let total = StringAdd(total, grains) + " Double grains for the next square + let grains = StringAdd(grains, grains) + endfor + + return total endfunction diff --git a/exercises/practice/grains/grains.vader b/exercises/practice/grains/grains.vader index e2d44a2..a6b6906 100644 --- a/exercises/practice/grains/grains.vader +++ b/exercises/practice/grains/grains.vader @@ -1,37 +1,37 @@ Execute (grains on square 1): let g:square = 1 - let g:expected = 1 + let g:expected = "1" AssertEqual g:expected, Square(g:square) Execute (grains on square 2): let g:square = 2 - let g:expected = 2 + let g:expected = "2" AssertEqual g:expected, Square(g:square) Execute (grains on square 3): let g:square = 3 - let g:expected = 4 + let g:expected = "4" AssertEqual g:expected, Square(g:square) Execute (grains on square 4): let g:square = 4 - let g:expected = 8 + let g:expected = "8" AssertEqual g:expected, Square(g:square) Execute (grains on square 16): let g:square = 16 - let g:expected = 32768 + let g:expected = "32768" AssertEqual g:expected, Square(g:square) Execute (grains on square 32): let g:square = 32 - let g:expected = 2147483648 + let g:expected = "2147483648" AssertEqual g:expected, Square(g:square) Execute (grains on square 64): let g:square = 64 - let g:expected = 9223372036854775807 + let g:expected = "9223372036854775808" AssertEqual g:expected, Square(g:square) Execute (square 0 is invalid): @@ -53,5 +53,5 @@ Execute (square greater than 64 is invalid): AssertEqual g:expected, g:vader_exception Execute (returns the total number of grains on the board): - let g:expected = 9223372036854775807 + let g:expected = "18446744073709551615" AssertEqual g:expected, Total() diff --git a/exercises/practice/grains/grains.vim b/exercises/practice/grains/grains.vim index 7453bcf..c8e26cd 100644 --- a/exercises/practice/grains/grains.vim +++ b/exercises/practice/grains/grains.vim @@ -1,6 +1,6 @@ " -" Returns the number of grains on a chessboard square given the grains on each square -" double from the previous square. +" Returns the number of grains (as a string) on a chessboard square given the +" grains on each square double from the previous square. " Throws an error if the square is below 1 or above 64. " " Examples: @@ -16,7 +16,7 @@ function! Square(number) abort endfunction " -" Returns the total number of grains for a filled chessboard +" Returns the total number of grains (as a string) for a filled chessboard " function! Total() abort " your code goes here