Skip to content

Commit

Permalink
grains exercise: test against integer values as strings. (#326)
Browse files Browse the repository at this point in the history
* To work around Vimscripts 2^63 limit for integers, the tests
has been created to expect the integral values as strings.
  • Loading branch information
glennj authored Nov 9, 2024
1 parent c0034ab commit d0b1c14
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 21 deletions.
8 changes: 6 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
13 changes: 13 additions & 0 deletions exercises/practice/grains/.docs/instructions.append.md
Original file line number Diff line number Diff line change
@@ -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 beyond 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
4 changes: 3 additions & 1 deletion exercises/practice/grains/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"authors": [
"BNAndras"
"BNAndras",
"KOTP",
"glennj"
],
"files": {
"solution": [
Expand Down
62 changes: 55 additions & 7 deletions exercises/practice/grains/.meta/example.vim
Original file line number Diff line number Diff line change
@@ -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 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
16 changes: 8 additions & 8 deletions exercises/practice/grains/grains.vader
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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()
6 changes: 3 additions & 3 deletions exercises/practice/grains/grains.vim
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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
Expand Down

0 comments on commit d0b1c14

Please sign in to comment.