Skip to content

Commit d0b1c14

Browse files
authored
grains exercise: test against integer values as strings. (#326)
* To work around Vimscripts 2^63 limit for integers, the tests has been created to expect the integral values as strings.
1 parent c0034ab commit d0b1c14

File tree

6 files changed

+88
-21
lines changed

6 files changed

+88
-21
lines changed

config.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,12 @@
185185
"uuid": "99408193-d0ce-4c68-8cab-e680f3ed56a4",
186186
"practices": [],
187187
"prerequisites": [],
188-
"difficulty": 2,
189-
"status": "wip"
188+
"difficulty": 5,
189+
"topics": [
190+
"math",
191+
"strings",
192+
"loops"
193+
]
190194
},
191195
{
192196
"slug": "hello-world",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Maximum integer value
2+
3+
According to [the Vim docs][number]:
4+
5+
> Assuming 64 bit numbers are used (see v:numbersize) an unsigned number is truncated to 0x7fffffffffffffff or 9223372036854775807.
6+
7+
In other words, Vimscript cannot express any number `2^63` or greater as an integer.
8+
9+
Some of the tests for this exercise require 64 bit integers which is beyond the integer size limitation ov Vimscript.
10+
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.
11+
Can you solve this by avoiding numbers that are larger than the language will allow directly?
12+
13+
[number]: https://vimhelp.org/eval.txt.html#expr-number

exercises/practice/grains/.meta/config.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{
22
"authors": [
3-
"BNAndras"
3+
"BNAndras",
4+
"KOTP",
5+
"glennj"
46
],
57
"files": {
68
"solution": [
+55-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,59 @@
1-
function! Square(number) abort
2-
if a:number < 1 || a:number > 64
3-
throw 'square must be between 1 and 64'
4-
endif
1+
" Helper function to add two numbers represented as strings
2+
function! StringAdd(num1, num2)
3+
let carry = 0
4+
let result = ''
55

6-
return float2nr(pow(2, (a:number-1)))
6+
" Pad the shorter number with leading zeros
7+
let len1 = strlen(a:num1)
8+
let len2 = strlen(a:num2)
9+
if len1 < len2
10+
let a:num1 = repeat('0', len2 - len1) . a:num1
11+
elseif len2 < len1
12+
let a:num2 = repeat('0', len1 - len2) . a:num2
13+
endif
14+
15+
" Add digits from right to left
16+
for i in range(strlen(a:num1) - 1, 0, -1)
17+
let sum = str2nr(a:num1[i]) + str2nr(a:num2[i]) + carry
18+
let carry = sum >= 10 ? 1 : 0
19+
let result = string(sum % 10) . result
20+
endfor
21+
22+
" Add the last carry if it exists
23+
if carry > 0
24+
let result = '1' . result
25+
endif
26+
27+
return result
728
endfunction
829

9-
function! Total() abort
10-
return float2nr(pow(2, 64) - 1)
30+
" Function to calculate grains on a specific square using string manipulation
31+
function! Square(n)
32+
if a:n < 1 || a:n > 64
33+
throw 'square must be between 1 and 64'
34+
endif
35+
36+
" Start with 1 grain on the first square
37+
let grains = '1'
38+
for i in range(2, a:n)
39+
" Double the grains by adding it to itself
40+
let grains = StringAdd(grains, grains)
41+
endfor
42+
43+
return grains
44+
endfunction
45+
46+
" Function to calculate the total grains on the chessboard using string manipulation
47+
function! Total()
48+
let total = '0'
49+
50+
" Accumulate grains for each square from 1 to 64
51+
let grains = '1'
52+
for i in range(1, 64)
53+
let total = StringAdd(total, grains)
54+
" Double grains for the next square
55+
let grains = StringAdd(grains, grains)
56+
endfor
57+
58+
return total
1159
endfunction

exercises/practice/grains/grains.vader

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11

22
Execute (grains on square 1):
33
let g:square = 1
4-
let g:expected = 1
4+
let g:expected = "1"
55
AssertEqual g:expected, Square(g:square)
66

77
Execute (grains on square 2):
88
let g:square = 2
9-
let g:expected = 2
9+
let g:expected = "2"
1010
AssertEqual g:expected, Square(g:square)
1111

1212
Execute (grains on square 3):
1313
let g:square = 3
14-
let g:expected = 4
14+
let g:expected = "4"
1515
AssertEqual g:expected, Square(g:square)
1616

1717
Execute (grains on square 4):
1818
let g:square = 4
19-
let g:expected = 8
19+
let g:expected = "8"
2020
AssertEqual g:expected, Square(g:square)
2121

2222
Execute (grains on square 16):
2323
let g:square = 16
24-
let g:expected = 32768
24+
let g:expected = "32768"
2525
AssertEqual g:expected, Square(g:square)
2626

2727
Execute (grains on square 32):
2828
let g:square = 32
29-
let g:expected = 2147483648
29+
let g:expected = "2147483648"
3030
AssertEqual g:expected, Square(g:square)
3131

3232
Execute (grains on square 64):
3333
let g:square = 64
34-
let g:expected = 9223372036854775807
34+
let g:expected = "9223372036854775808"
3535
AssertEqual g:expected, Square(g:square)
3636

3737
Execute (square 0 is invalid):
@@ -53,5 +53,5 @@ Execute (square greater than 64 is invalid):
5353
AssertEqual g:expected, g:vader_exception
5454

5555
Execute (returns the total number of grains on the board):
56-
let g:expected = 9223372036854775807
56+
let g:expected = "18446744073709551615"
5757
AssertEqual g:expected, Total()

exercises/practice/grains/grains.vim

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"
2-
" Returns the number of grains on a chessboard square given the grains on each square
3-
" double from the previous square.
2+
" Returns the number of grains (as a string) on a chessboard square given the
3+
" grains on each square double from the previous square.
44
" Throws an error if the square is below 1 or above 64.
55
"
66
" Examples:
@@ -16,7 +16,7 @@ function! Square(number) abort
1616
endfunction
1717

1818
"
19-
" Returns the total number of grains for a filled chessboard
19+
" Returns the total number of grains (as a string) for a filled chessboard
2020
"
2121
function! Total() abort
2222
" your code goes here

0 commit comments

Comments
 (0)