commite46f8f24becd61686a7f6d339e93c986aacb6b1eparent3d3ab591b93471dfbd32f5056ce26dbfb379ffb1Author:dwrz <dwrz@dwrz.net>Date:Wed, 26 Jun 2019 21:14:07 +0000 Add elisp/grainsDiffstat:

A | elisp/grains/README.md | | | 34 | ++++++++++++++++++++++++++++++++++ |

A | elisp/grains/grains-test.el | | | 38 | ++++++++++++++++++++++++++++++++++++++ |

A | elisp/grains/grains.el | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |

3 files changed, 195 insertions(+), 0 deletions(-)diff --git a/elisp/grains/README.md b/elisp/grains/README.md@@ -0,0 +1,34 @@ +# Grains + +Calculate the number of grains of wheat on a chessboard given that the number +on each square doubles. + +There once was a wise servant who saved the life of a prince. The king +promised to pay whatever the servant could dream up. Knowing that the +king loved chess, the servant told the king he would like to have grains +of wheat. One grain on the first square of a chess board. Two grains on +the next. Four on the third, and so on. + +There are 64 squares on a chessboard. + +Write code that shows: +- how many grains were on each square, and +- the total number of grains + + +## For bonus points + +Did you get the tests passing and the code clean? If you want to, these +are some additional things you could try: + +- Optimize for speed. +- Optimize for readability. + +Then please share your thoughts in a comment on the submission. Did this +experiment make the code better? Worse? Did you learn anything from it? +## Source + +JavaRanch Cattle Drive, exercise 6 [http://www.javaranch.com/grains.jsp](http://www.javaranch.com/grains.jsp) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise.diff --git a/elisp/grains/grains-test.el b/elisp/grains/grains-test.el@@ -0,0 +1,38 @@ +;;; grains-test.el --- Test for Grains (exercism) + +;;; Commentary: + +;;; Code: + +(load-file "grains.el") + +(ert-deftest square-1 () + (should (= 1 (square 1)))) + +(ert-deftest square-2 () + (should (= 2 (square 2)))) + +(ert-deftest square-3 () + (should (= 4 (square 3)))) + +(ert-deftest square-4 () + (should (= 8 (square 4)))) + +(ert-deftest square-16 () + (should (= 32768 + (square 16)))) + +(ert-deftest square-32 () + (should (= 2147483648 + (square 32)))) + +(ert-deftest square-64 () + (should (= 9223372036854775808 + (square 64)))) + +(ert-deftest total-grains () + (should (= 18446744073709551615 + (total)))) + +(provide 'grains-test.el) +;;; grains-test.el ends here.diff --git a/elisp/grains/grains.el b/elisp/grains/grains.el@@ -0,0 +1,123 @@ +;;; grains.el --- Grains exercise (exercism) + +;;; Commentary: +;;; I solved this problem on the C track. There, the solution was +;;; simpler: simply shift an unsigned long long to get the number of +;;; grains at square n. +;;; +;;; In Emacs, that approach doesn't seem to work. Only 30 bits are used +;;; for integers, resulting in overflows above square 60. +;;; +;;; The solution, if one wants to calculate it, seems to be to rely on +;;; the calc package to calculate bigger numbers. The functions +;;; calculate-square and calculate-total rely on that approach. +;;; +;;; However, it also occurred to me that the values here are known, +;;; limited, and not likely to change anytime soon. By using contants, +;;; we can get constant time determination of the number of grains for +;;; a square. The functions used by the tests, square and total, simply +;;; return constant values, with the number of grains for a square +;;; relying on a vector that matches the n-th index to the corresponding +;;; grains. +;;; +;;; Emacs itself was useful in effectuating this solution. I used a +;;; macro to evaluate calculate-square for n, and then insert the +;;; results in this buffer. There's probably a more elegant way to do +;;; this in Emacs, but this approach was adequate for the task. +;;; Sometimes, making the programmer's life easier can lead to more +;;; efficient code. + +;;; Code: + +(require 'calc) + +(defun calculate-square(n) + "Return the number of grains at square N. Use left shifts when n is equal to or below 60, and calc for numbers up to 65." + (cond ((< n 0) 0) + ((> n 65) 0) + ((<= n 60) (lsh 1 (- n 1))) + (t (string-to-number (calc-eval (format "2^%d" (1- n))))))) + +(defun calculate-total() + "Return the total number of grains on a chessboard with 64 squares." + (1- (square 65))) + +(defvar grains [0 + 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512 + 1024 + 2048 + 4096 + 8192 + 16384 + 32768 + 65536 + 131072 + 262144 + 524288 + 1048576 + 2097152 + 4194304 + 8388608 + 16777216 + 33554432 + 67108864 + 134217728 + 268435456 + 536870912 + 1073741824 + 2147483648 + 4294967296 + 8589934592 + 17179869184 + 34359738368 + 68719476736 + 137438953472 + 274877906944 + 549755813888 + 1099511627776 + 2199023255552 + 4398046511104 + 8796093022208 + 17592186044416 + 35184372088832 + 70368744177664 + 140737488355328 + 281474976710656 + 562949953421312 + 1125899906842624 + 2251799813685248 + 4503599627370496 + 9007199254740992 + 18014398509481984 + 36028797018963968 + 72057594037927936 + 144115188075855872 + 288230376151711744 + 576460752303423488 + 1152921504606846976 + 2305843009213693952 + 4611686018427387904 + 9223372036854775808] + "Vector containing the number of grains for a square with the corresponding index.") + +(defun square(n) + "Return the number of grans at square n; 0 for negative numbers and numbers above 64." + (cond ((< n 0) 0) + ((> n 64) 0) + (t (aref grains n)))) + +(defun total() + "Return the total number of grains on a chessboard with 64 squares." + 18446744073709551616) + +(provide 'grains) +;;; grains.el ends here