# RabbitFarm

### 2021-10-24

#### The Weekly Challenge 135 (Prolog Solutions)

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

## Part 1

You are given an integer. Write a script find out the middle 3-digits of the given integer, if possible, otherwise show a sensible error message.

### Solution

``````
:-initialization(main).

middle_three(N, Middle3):-
number_chars(N, Chars),
N > 0,
length(Chars, Length),
Length > 2,
IsOdd is Length mod 2, IsOdd == 1,
length(M3, 3),
PrefixLength is ceiling(Length / 2) - 2,
length(Prefix, PrefixLength),
append(Prefix, Middle, Chars),
append(M3, _, Middle),
number_chars(Middle3, M3).

middle_three(N, Middle3):-
(N < 0, N0 is abs(N), middle_three(N0, Middle3));
(number_chars(N, Chars), length(Chars, Length), Length < 3, format("too short~n", _));
(number_chars(N, Chars), length(Chars, Length), IsOdd is Length mod 2, IsOdd == 0, format("even number of digits~n", _));
middle_three(N, Middle3).

main:-
middle_three(1234567, Middle3),
((nonvar(Middle3), format("~d~n", [Middle3]), halt);
halt).
``````

### Sample Run

``````
\$ gplc prolog/ch-1.p
\$ prolog/ch-1
345
``````

### Notes

Interestingly this is one of the rare cases where a Prolog solution follows a fairly similar approach a [Perl solution to the same problem0(http://www.rabbitfarm.com/cgi-bin/blosxom/2021/10/24/perl).

## Part 2

You are given 7-characters alphanumeric SEDOL. Write a script to validate the given SEDOL. Print 1 if it is a valid SEDOL otherwise 0.

### Solution

``````
:-initialization(main).

weight(1, 1).
weight(2, 3).
weight(3, 1).
weight(4, 7).
weight(5, 3).
weight(6, 9).

base --> alphanumeric, alphanumeric, alphanumeric, alphanumeric, alphanumeric, alphanumeric.
alphanumeric --> [AlphaNumeric], {letter_or_digit(AlphaNumeric)}.

sedol(Sedol):-
var(Sedol),
sedol(_, Sedol).
sedol(Sedol):-
nonvar(Sedol),
length(Base, 6),
append(Base, [CheckDigit], Sedol),
phrase(base, Base),
compute_check(Base, ComputedCheckDigit),
CheckDigit == ComputedCheckDigit.

sedol(Base, Sedol):-
phrase(base, Base),
check_digit(Base, Sedol).

letter_or_digit(A):-
nonvar(A),
atom_codes(A, C),
((C >= 66, C =< 90);
(C >= 48, C =< 57)).

letter_or_digit(A):-
var(A),
((between(66, 90, C));  %B through Z
(between(48, 57, C))), %0-9
atom_codes(A, [C]).

compute_check(Base, CheckSum):-
compute_check(Base, 1, CheckSum, 0).
compute_check([], _, CheckSum, PartialCheckSum):-
CheckSum is mod(10 - mod(PartialCheckSum, 10), 10).
compute_check([H|T], Index, CheckSum, PartialCheckSum):-
atom_codes(H, [C]),
between(66, 90, C),
weight(Index, Weight),
LetterValue is C - 64 + 9,
Partial is PartialCheckSum + (LetterValue * Weight),
succ(Index, I),
compute_check(T, I, CheckSum, Partial).
compute_check([H|T], Index, CheckSum, PartialCheckSum):-
atom_codes(H, [C]),
between(48, 57, C),
weight(Index, Weight),
NumeralValue is C - 48,
Partial is PartialCheckSum + (NumeralValue * Weight),
succ(Index, I),
compute_check(T, I, CheckSum, Partial).

check_digit(Base, BaseCheckDigit):-
compute_check(Base, CheckDigit),
append(Base, [CheckDigit], BaseCheckDigit).

main:-
(sedol(['2','9','3','6','9','2',1]), format("1~n", _);
format("0~n", _)),
(sedol(['1','2','3','4','5','6',7]), format("1~n", _);
format("0~n", _)),
(sedol(['B','0','Y','B','K','L',9]), format("1~n", _);
format("0~n", _)),
halt.
``````

### Sample Run

``````
\$ gplc prolog/ch-2.p
\$ prolog/ch-2
1
0
1
``````

### Notes

I had originally hoped to have all code for this using almost exclusively DCGs. Things got a bit unwieldy with the checksum computation and so I dialed that back a bit, so to speak. Here the DCG part is for validating or generating a SEDOL base 6 digits sequence and the check digit is computed using regular Prolog predicates.

The rules around SEDOLs are a bit more complex than this problem lets on. I won't recount them all here, but suffice to say we are dealing with a quite idealized set of validations here. For example, prior to 2004 only numerals were allowed, but since then letters are allowed. But only a numeral can follow a letter. Again, though, those are only rules that apply for a certain time range.

Here we are just checking on length, whether or not the SEDOl contains all numerals and/or (uppercase) letter, and the checksum validation.

## References

Challenge 135

Stock Exchange Daily Official List (SEDOL)

posted at: 15:17 by: Adam Russell | path: /prolog | permanent link to this entry