Skip to content

Commit a4648c7

Browse files
Add alphametics exercise (#104)
1 parent 0e5bf3d commit a4648c7

File tree

11 files changed

+1194
-0
lines changed

11 files changed

+1194
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,14 @@
804804
"prerequisites": [],
805805
"difficulty": 7
806806
},
807+
{
808+
"slug": "alphametics",
809+
"name": "Alphametics",
810+
"uuid": "001eb6d6-0443-4326-888b-ed9d5e9bc120",
811+
"practices": [],
812+
"prerequisites": [],
813+
"difficulty": 8
814+
},
807815
{
808816
"slug": "connect",
809817
"name": "Connect",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Instructions
2+
3+
Given an alphametics puzzle, find the correct solution.
4+
5+
[Alphametics][alphametics] is a puzzle where letters in words are replaced with numbers.
6+
7+
For example `SEND + MORE = MONEY`:
8+
9+
```text
10+
S E N D
11+
M O R E +
12+
-----------
13+
M O N E Y
14+
```
15+
16+
Replacing these with valid numbers gives:
17+
18+
```text
19+
9 5 6 7
20+
1 0 8 5 +
21+
-----------
22+
1 0 6 5 2
23+
```
24+
25+
This is correct because every letter is replaced by a different number and the words, translated into numbers, then make a valid sum.
26+
27+
Each letter must represent a different digit, and the leading digit of a multi-digit number must not be zero.
28+
29+
[alphametics]: https://en.wikipedia.org/wiki/Alphametics
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"Alphametics.pas"
8+
],
9+
"test": [
10+
"TestCases.pas"
11+
],
12+
"example": [
13+
".meta/example.pas"
14+
]
15+
},
16+
"blurb": "Given an alphametics puzzle, find the correct solution."
17+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
unit Alphametics;
2+
3+
{$mode ObjFPC}{$H+}
4+
5+
interface
6+
7+
function solve(const puzzle : string) : string;
8+
9+
implementation
10+
11+
uses SysUtils;
12+
13+
type
14+
ESolved = class(Exception);
15+
16+
function solve(const puzzle : string) : string;
17+
type
18+
TLetter = record
19+
letter : char;
20+
rank : integer; { lowest column where letter appears }
21+
weight : array of integer;
22+
leading : boolean; { cannot be assigned 0 }
23+
digit : integer;
24+
end;
25+
TLetters = array of TLetter;
26+
var
27+
letters : TLetters;
28+
nColumns : integer;
29+
30+
function ParsePuzzle : TLetters;
31+
var
32+
table : array[0..25] of TLetter;
33+
34+
procedure Scan;
35+
var
36+
i, c, sign, place, prev : integer;
37+
begin
38+
for i := 0 to 25 do begin
39+
table[i].letter := chr(ord('A') + i);
40+
table[i].rank := High(integer);
41+
table[i].weight := nil;
42+
table[i].leading := false;
43+
end;
44+
45+
sign := -1;
46+
place := 0;
47+
prev := 0;
48+
for i := length(puzzle) downto 1 do begin
49+
c := ord(puzzle[i]) - ord('A');
50+
if (c >= 0) and (c < 26) then
51+
begin
52+
if place < table[c].rank then
53+
table[c].rank := place;
54+
55+
if length(table[c].weight) <= place then
56+
SetLength(table[c].weight, place + 1);
57+
58+
inc(table[c].weight[place], sign);
59+
prev := c;
60+
inc(place);
61+
end
62+
else
63+
begin
64+
if puzzle[i] = '=' then
65+
sign := 1;
66+
67+
if place > 0 then
68+
table[prev].leading := true;
69+
70+
place := 0;
71+
end;
72+
end;
73+
if place > 0 then
74+
table[prev].leading := true;
75+
end;
76+
77+
function Compact : TLetters;
78+
var
79+
i, j : integer;
80+
begin
81+
nColumns := 0;
82+
result := nil;
83+
for i := 0 to 25 do begin
84+
if table[i].rank = High(integer) then
85+
continue;
86+
87+
if length(table[i].weight) > nColumns then
88+
nColumns := length(table[i].weight);
89+
90+
j := length(result);
91+
SetLength(result, j + 1);
92+
while (j > 0) and (result[j - 1].rank > table[i].rank) do
93+
begin
94+
result[j] := result[j - 1];
95+
dec(j);
96+
end;
97+
result[j] := table[i];
98+
end;
99+
end;
100+
101+
begin
102+
Scan;
103+
result := Compact;
104+
end;
105+
106+
procedure Search(index, claimed, col, carry : integer);
107+
var
108+
digit, k, colSum : integer;
109+
begin
110+
if (index = length(letters)) or (letters[index].rank > col) then
111+
begin
112+
colSum := carry;
113+
for k := 0 to index - 1 do
114+
if col < length(letters[k].weight) then
115+
inc(colSum, letters[k].weight[col] * letters[k].digit);
116+
117+
if colSum mod 10 = 0 then
118+
begin
119+
if col + 1 < nColumns then
120+
Search(index, claimed, col + 1, colSum div 10)
121+
else if colSum div 10 = 0 then
122+
raise ESolved.Create('');
123+
end;
124+
end
125+
else
126+
for digit := ord(letters[index].leading) to 9 do
127+
begin
128+
if claimed and (1 shl digit) <> 0 then
129+
continue;
130+
131+
letters[index].digit := digit;
132+
Search(index + 1, claimed or (1 shl digit), col, carry);
133+
end;
134+
end;
135+
136+
function BuildResult : string;
137+
var
138+
i : integer;
139+
table : array['A'..'Z'] of char;
140+
ch : char;
141+
begin
142+
for i := 0 to length(letters) - 1 do
143+
table[letters[i].letter] := chr(ord('0') + letters[i].digit);
144+
145+
result := '';
146+
for ch in puzzle do
147+
if (ch >= 'A') and (ch <= 'Z') then
148+
result += table[ch]
149+
else
150+
result += ch;
151+
end;
152+
153+
begin
154+
letters := ParsePuzzle;
155+
try
156+
Search(0, 0, 0, 0);
157+
raise Exception.Create('no solution');
158+
except
159+
on ESolved do result := BuildResult;
160+
end;
161+
end;
162+
163+
end.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[e0c08b07-9028-4d5f-91e1-d178fead8e1a]
13+
description = "puzzle with three letters"
14+
15+
[a504ee41-cb92-4ec2-9f11-c37e95ab3f25]
16+
description = "solution must have unique value for each letter"
17+
18+
[4e3b81d2-be7b-4c5c-9a80-cd72bc6d465a]
19+
description = "leading zero solution is invalid"
20+
21+
[8a3e3168-d1ee-4df7-94c7-b9c54845ac3a]
22+
description = "puzzle with two digits final carry"
23+
24+
[a9630645-15bd-48b6-a61e-d85c4021cc09]
25+
description = "puzzle with four letters"
26+
27+
[3d905a86-5a52-4e4e-bf80-8951535791bd]
28+
description = "puzzle with six letters"
29+
30+
[4febca56-e7b7-4789-97b9-530d09ba95f0]
31+
description = "puzzle with seven letters"
32+
33+
[12125a75-7284-4f9a-a5fa-191471e0d44f]
34+
description = "puzzle with eight letters"
35+
36+
[fb05955f-38dc-477a-a0b6-5ef78969fffa]
37+
description = "puzzle with ten letters"
38+
39+
[9a101e81-9216-472b-b458-b513a7adacf7]
40+
description = "puzzle with ten letters and 199 addends"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
unit Alphametics;
2+
3+
{$mode ObjFPC}{$H+}
4+
5+
interface
6+
7+
function solve(const puzzle : string) : string;
8+
9+
implementation
10+
11+
uses SysUtils;
12+
13+
function solve(const puzzle : string) : string;
14+
begin
15+
raise ENotImplemented.Create('Please implement your solution.'); result := puzzle;
16+
end;
17+
18+
end.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
SHELL = /bin/bash
2+
MAKEFLAGS += --no-print-directory
3+
DESTDIR = build
4+
EXECUTABLE = $(DESTDIR)/test
5+
COMMAND = fpc -l- -v0 -g -gl -Sa -Cr -Sehnw -Fu./lib test.pas -FE"./$(DESTDIR)"
6+
7+
.ONESHELL:
8+
9+
test:
10+
@mkdir -p "./$(DESTDIR)"
11+
@cp -r ./lib "./$(DESTDIR)"
12+
@$(COMMAND) && ./$(EXECUTABLE) $(test)
13+
14+
clean:
15+
@rm -fr "./$(DESTDIR)"

0 commit comments

Comments
 (0)