trackler 2.2.0.0 → 2.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/CONTRIBUTING.md +1 -1
- data/tracks/bash/.travis.yml +1 -1
- data/tracks/bash/config.json +30 -3
- data/tracks/c/README.md +1 -1
- data/tracks/c/config.json +131 -39
- data/tracks/ceylon/README.md +6 -6
- data/tracks/ceylon/config.json +21 -3
- data/tracks/chapel/.travis.yml +1 -1
- data/tracks/clojurescript/.travis.yml +1 -1
- data/tracks/clojurescript/README.md +6 -6
- data/tracks/clojurescript/exercises/.keep +0 -0
- data/tracks/coffeescript/.travis.yml +1 -1
- data/tracks/coldfusion/.travis.yml +1 -1
- data/tracks/coq/.travis.yml +1 -1
- data/tracks/cpp/CMakeLists.txt +1 -0
- data/tracks/cpp/README.md +1 -1
- data/tracks/cpp/config.json +8 -0
- data/tracks/cpp/exercises/atbash-cipher/CMakeLists.txt +52 -0
- data/tracks/cpp/exercises/atbash-cipher/atbash_cipher_test.cpp +68 -0
- data/tracks/cpp/exercises/atbash-cipher/example.cpp +54 -0
- data/tracks/cpp/exercises/atbash-cipher/example.h +13 -0
- data/tracks/csharp/config.json +315 -6
- data/tracks/d/.travis.yml +1 -1
- data/tracks/dart/README.md +2 -2
- data/tracks/dart/config.json +21 -3
- data/tracks/delphi/README.md +1 -1
- data/tracks/delphi/config.json +83 -1
- data/tracks/ecmascript/config.json +10 -0
- data/tracks/ecmascript/exercises/accumulate/accumulate.spec.js +3 -9
- data/tracks/ecmascript/exercises/acronym/acronym.spec.js +2 -2
- data/tracks/ecmascript/exercises/all-your-base/all-your-base.spec.js +131 -133
- data/tracks/ecmascript/exercises/all-your-base/example.js +1 -3
- data/tracks/ecmascript/exercises/allergies/allergies.spec.js +8 -10
- data/tracks/ecmascript/exercises/allergies/example.js +3 -5
- data/tracks/ecmascript/exercises/alphametics/alphametics.spec.js +61 -63
- data/tracks/ecmascript/exercises/alphametics/example.js +99 -99
- data/tracks/ecmascript/exercises/anagram/anagram.spec.js +35 -37
- data/tracks/ecmascript/exercises/anagram/example.js +1 -3
- data/tracks/ecmascript/exercises/atbash-cipher/atbash-cipher.spec.js +1 -3
- data/tracks/ecmascript/exercises/atbash-cipher/example.js +3 -3
- data/tracks/ecmascript/exercises/beer-song/beer-song.spec.js +0 -2
- data/tracks/ecmascript/exercises/beer-song/example.js +9 -9
- data/tracks/ecmascript/exercises/binary/binary.spec.js +1 -2
- data/tracks/ecmascript/exercises/binary/example.js +3 -3
- data/tracks/ecmascript/exercises/binary-search/binary-search.spec.js +1 -3
- data/tracks/ecmascript/exercises/binary-search-tree/binary-search-tree.spec.js +13 -15
- data/tracks/ecmascript/exercises/binary-search-tree/example.js +2 -2
- data/tracks/ecmascript/exercises/bob/bob.spec.js +1 -3
- data/tracks/ecmascript/exercises/bob/example.js +3 -3
- data/tracks/ecmascript/exercises/bracket-push/example.js +2 -2
- data/tracks/ecmascript/exercises/circular-buffer/circular-buffer.spec.js +10 -12
- data/tracks/ecmascript/exercises/circular-buffer/example.js +12 -11
- data/tracks/ecmascript/exercises/clock/clock.spec.js +0 -8
- data/tracks/ecmascript/exercises/clock/example.js +11 -11
- data/tracks/ecmascript/exercises/connect/connect.spec.js +75 -77
- data/tracks/ecmascript/exercises/connect/example.js +27 -29
- data/tracks/ecmascript/exercises/crypto-square/crypto-square.spec.js +11 -11
- data/tracks/ecmascript/exercises/crypto-square/example.js +11 -10
- data/tracks/ecmascript/exercises/custom-set/custom-set.spec.js +2 -4
- data/tracks/ecmascript/exercises/custom-set/example.js +1 -1
- data/tracks/ecmascript/exercises/diamond/diamond.spec.js +20 -21
- data/tracks/ecmascript/exercises/diamond/example.js +12 -13
- data/tracks/ecmascript/exercises/difference-of-squares/difference-of-squares.spec.js +0 -5
- data/tracks/ecmascript/exercises/diffie-hellman/diffie-hellman.spec.js +7 -28
- data/tracks/ecmascript/exercises/etl/etl.spec.js +36 -18
- data/tracks/ecmascript/exercises/etl/example.js +3 -3
- data/tracks/ecmascript/exercises/flatten-array/example.js +1 -1
- data/tracks/ecmascript/exercises/flatten-array/flatten-array.spec.js +2 -3
- data/tracks/ecmascript/exercises/food-chain/example.js +12 -12
- data/tracks/ecmascript/exercises/food-chain/food-chain.spec.js +0 -1
- data/tracks/ecmascript/exercises/gigasecond/example.js +1 -1
- data/tracks/ecmascript/exercises/gigasecond/gigasecond.spec.js +0 -1
- data/tracks/ecmascript/exercises/grade-school/grade-school.spec.js +18 -19
- data/tracks/ecmascript/exercises/grains/grains.spec.js +0 -1
- data/tracks/ecmascript/exercises/hamming/example.js +3 -3
- data/tracks/ecmascript/exercises/hamming/hamming.spec.js +5 -6
- data/tracks/ecmascript/exercises/hello-world/example.js +1 -1
- data/tracks/ecmascript/exercises/hello-world/hello-world.spec.js +1 -1
- data/tracks/ecmascript/exercises/hexadecimal/example.js +2 -2
- data/tracks/ecmascript/exercises/hexadecimal/hexadecimal.spec.js +9 -11
- data/tracks/ecmascript/exercises/isogram/isogram.spec.js +22 -23
- data/tracks/ecmascript/exercises/kindergarten-garden/example.js +7 -7
- data/tracks/ecmascript/exercises/kindergarten-garden/kindergarten-garden.spec.js +0 -5
- data/tracks/ecmascript/exercises/largest-series-product/example.js +4 -8
- data/tracks/ecmascript/exercises/largest-series-product/largest-series-product.spec.js +5 -7
- data/tracks/ecmascript/exercises/leap/leap.spec.js +4 -6
- data/tracks/ecmascript/exercises/linked-list/example.js +2 -2
- data/tracks/ecmascript/exercises/list-ops/example.js +19 -19
- data/tracks/ecmascript/exercises/list-ops/list-ops.spec.js +2 -18
- data/tracks/ecmascript/exercises/luhn/example.js +1 -1
- data/tracks/ecmascript/exercises/luhn/luhn.spec.js +1 -3
- data/tracks/ecmascript/exercises/matrix/example.js +2 -4
- data/tracks/ecmascript/exercises/matrix/matrix.spec.js +0 -2
- data/tracks/ecmascript/exercises/meetup/example.js +12 -15
- data/tracks/ecmascript/exercises/meetup/meetup.spec.js +0 -2
- data/tracks/ecmascript/exercises/minesweeper/example.js +60 -0
- data/tracks/ecmascript/exercises/minesweeper/minesweeper.spec.js +174 -0
- data/tracks/ecmascript/exercises/minesweeper/package.json +69 -0
- data/tracks/ecmascript/exercises/nth-prime/example.js +3 -2
- data/tracks/ecmascript/exercises/nth-prime/nth-prime.spec.js +0 -1
- data/tracks/ecmascript/exercises/ocr-numbers/example.js +3 -3
- data/tracks/ecmascript/exercises/ocr-numbers/ocr-numbers.spec.js +16 -18
- data/tracks/ecmascript/exercises/octal/example.js +1 -1
- data/tracks/ecmascript/exercises/octal/octal.spec.js +0 -2
- data/tracks/ecmascript/exercises/palindrome-products/example.js +14 -11
- data/tracks/ecmascript/exercises/palindrome-products/palindrome-products.spec.js +15 -18
- data/tracks/ecmascript/exercises/pangram/example.js +6 -5
- data/tracks/ecmascript/exercises/pangram/pangram.spec.js +10 -12
- data/tracks/ecmascript/exercises/pascals-triangle/example.js +2 -2
- data/tracks/ecmascript/exercises/pascals-triangle/pascals-triangle.spec.js +6 -8
- data/tracks/ecmascript/exercises/perfect-numbers/example.js +3 -5
- data/tracks/ecmascript/exercises/perfect-numbers/perfect-numbers.spec.js +0 -10
- data/tracks/ecmascript/exercises/phone-number/example.js +2 -2
- data/tracks/ecmascript/exercises/phone-number/phone-number.spec.js +0 -2
- data/tracks/ecmascript/exercises/pig-latin/example.js +4 -4
- data/tracks/ecmascript/exercises/pig-latin/pig-latin.spec.js +0 -1
- data/tracks/ecmascript/exercises/prime-factors/example.js +2 -2
- data/tracks/ecmascript/exercises/prime-factors/prime-factors.spec.js +0 -2
- data/tracks/ecmascript/exercises/pythagorean-triplet/pythagorean-triplet.spec.js +3 -11
- data/tracks/ecmascript/exercises/queen-attack/example.js +17 -17
- data/tracks/ecmascript/exercises/queen-attack/queen-attack.spec.js +7 -8
- data/tracks/ecmascript/exercises/raindrops/example.js +1 -1
- data/tracks/ecmascript/exercises/raindrops/raindrops.spec.js +1 -2
- data/tracks/ecmascript/exercises/rna-transcription/example.js +5 -5
- data/tracks/ecmascript/exercises/rna-transcription/rna-transcription.spec.js +4 -5
- data/tracks/ecmascript/exercises/robot-name/example.js +6 -6
- data/tracks/ecmascript/exercises/robot-name/robot-name.spec.js +10 -11
- data/tracks/ecmascript/exercises/robot-simulator/example.js +1 -1
- data/tracks/ecmascript/exercises/robot-simulator/robot-simulator.spec.js +31 -32
- data/tracks/ecmascript/exercises/roman-numerals/example.js +16 -16
- data/tracks/ecmascript/exercises/saddle-points/saddle-points.spec.js +3 -3
- data/tracks/ecmascript/exercises/say/example.js +25 -25
- data/tracks/ecmascript/exercises/say/say.spec.js +2 -3
- data/tracks/ecmascript/exercises/scrabble-score/example.js +27 -9
- data/tracks/ecmascript/exercises/scrabble-score/scrabble-score.spec.js +6 -7
- data/tracks/ecmascript/exercises/secret-handshake/example.js +2 -3
- data/tracks/ecmascript/exercises/secret-handshake/secret-handshake.spec.js +3 -5
- data/tracks/ecmascript/exercises/series/series.spec.js +1 -3
- data/tracks/ecmascript/exercises/sieve/example.js +4 -3
- data/tracks/ecmascript/exercises/sieve/sieve.spec.js +0 -2
- data/tracks/ecmascript/exercises/simple-cipher/example.js +8 -9
- data/tracks/ecmascript/exercises/simple-cipher/simple-cipher.spec.js +4 -4
- data/tracks/ecmascript/exercises/space-age/example.js +1 -1
- data/tracks/ecmascript/exercises/space-age/space-age.spec.js +9 -11
- data/tracks/ecmascript/exercises/strain/example.js +4 -4
- data/tracks/ecmascript/exercises/strain/strain.spec.js +14 -16
- data/tracks/ecmascript/exercises/sum-of-multiples/example.js +4 -4
- data/tracks/ecmascript/exercises/triangle/triangle.spec.js +2 -4
- data/tracks/ecmascript/exercises/trinary/example.js +3 -3
- data/tracks/ecmascript/exercises/trinary/trinary.spec.js +0 -2
- data/tracks/ecmascript/exercises/two-bucket/example.js +30 -27
- data/tracks/ecmascript/exercises/two-bucket/two-bucket.spec.js +4 -8
- data/tracks/ecmascript/exercises/word-count/example.js +2 -2
- data/tracks/ecmascript/exercises/word-count/word-count.spec.js +2 -3
- data/tracks/ecmascript/exercises/wordy/example.js +6 -6
- data/tracks/ecmascript/exercises/wordy/wordy.spec.js +2 -4
- data/tracks/factor/config.json +15 -6
- data/tracks/fortran/.travis.yml +1 -1
- data/tracks/fsharp/config.json +312 -10
- data/tracks/go/README.md +1 -1
- data/tracks/go/config.json +523 -155
- data/tracks/haskell/README.md +2 -2
- data/tracks/haskell/config.json +256 -7
- data/tracks/haxe/.travis.yml +1 -1
- data/tracks/haxe/Makefile +2 -2
- data/tracks/haxe/config.json +8 -5
- data/tracks/java/CONTRIBUTING.md +2 -2
- data/tracks/java/config.json +277 -17
- data/tracks/java/exercises/rotational-cipher/build.gradle +17 -0
- data/tracks/java/exercises/rotational-cipher/src/example/java/RotationalCipher.java +37 -0
- data/tracks/java/exercises/rotational-cipher/src/main/java/.keep +0 -0
- data/tracks/java/exercises/rotational-cipher/src/test/java/RotationalCipherTest.java +81 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/java/exercises/twelve-days/src/main/java/TwelveDays.java +4 -0
- data/tracks/julia/.travis.yml +1 -1
- data/tracks/julia/README.md +1 -1
- data/tracks/kotlin/README.md +2 -2
- data/tracks/kotlin/exercises/hello-world/TUTORIAL.md +3 -3
- data/tracks/lisp/config.json +97 -3
- data/tracks/lisp/exercises/pascals-triangle/example.lisp +21 -0
- data/tracks/lisp/exercises/pascals-triangle/pascal.lisp +7 -0
- data/tracks/lisp/exercises/pascals-triangle/pascals-triangle-test.lisp +34 -0
- data/tracks/lua/.travis.yml +1 -1
- data/tracks/lua/README.md +1 -1
- data/tracks/mips/.travis.yml +1 -1
- data/tracks/mips/config.json +56 -17
- data/tracks/nasm/.travis.yml +1 -1
- data/tracks/nim/.travis.yml +1 -1
- data/tracks/ocaml/README.md +3 -3
- data/tracks/ocaml/config.json +130 -4
- data/tracks/perl5/docs/TESTS.md +40 -26
- data/tracks/plsql/.travis.yml +1 -1
- data/tracks/plsql/config.json +40 -13
- data/tracks/pony/.travis.yml +1 -1
- data/tracks/pony/bin/install-deps +4 -3
- data/tracks/prolog/.travis.yml +1 -1
- data/tracks/r/README.md +5 -5
- data/tracks/r/config.json +102 -30
- data/tracks/rust/.travis.yml +1 -1
- data/tracks/rust/config.json +172 -4
- data/tracks/rust/docs/EXERCISE_README_INSERT.md +1 -1
- data/tracks/sml/config.json +26 -3
- data/tracks/vimscript/config.json +60 -3
- metadata +16 -1
@@ -2,17 +2,16 @@ import circularBuffer from './circular-buffer';
|
|
2
2
|
import { BufferFullError, BufferEmptyError } from './circular-buffer';
|
3
3
|
|
4
4
|
describe('CircularBuffer', () => {
|
5
|
-
|
6
5
|
test('reading an empty buffer throws a BufferEmptyError', () => {
|
7
6
|
const buffer = circularBuffer(1);
|
8
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
7
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
9
8
|
});
|
10
9
|
|
11
10
|
xtest('write and read back one item', () => {
|
12
11
|
const buffer = circularBuffer(1);
|
13
12
|
buffer.write('1');
|
14
13
|
expect(buffer.read()).toBe('1');
|
15
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
14
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
16
15
|
});
|
17
16
|
|
18
17
|
xtest('write and read back multiple items', () => {
|
@@ -21,7 +20,7 @@ describe('CircularBuffer', () => {
|
|
21
20
|
buffer.write('2');
|
22
21
|
expect(buffer.read()).toBe('1');
|
23
22
|
expect(buffer.read()).toBe('2');
|
24
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
23
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
25
24
|
});
|
26
25
|
|
27
26
|
xtest('clearing a buffer', () => {
|
@@ -29,7 +28,7 @@ describe('CircularBuffer', () => {
|
|
29
28
|
buffer.write('1');
|
30
29
|
buffer.write('2');
|
31
30
|
buffer.clear();
|
32
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
31
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
33
32
|
buffer.write('3');
|
34
33
|
buffer.write('4');
|
35
34
|
expect(buffer.read()).toBe('3');
|
@@ -58,7 +57,7 @@ describe('CircularBuffer', () => {
|
|
58
57
|
const buffer = circularBuffer(3);
|
59
58
|
buffer.write(null);
|
60
59
|
buffer.write(undefined);
|
61
|
-
[1,2,3].map(i => buffer.write(i.toString()));
|
60
|
+
[1, 2, 3].map(i => buffer.write(i.toString()));
|
62
61
|
expect(buffer.read()).toBe('1');
|
63
62
|
});
|
64
63
|
|
@@ -76,7 +75,7 @@ describe('CircularBuffer', () => {
|
|
76
75
|
buffer.forceWrite('A');
|
77
76
|
expect(buffer.read()).toBe('2');
|
78
77
|
expect(buffer.read()).toBe('A');
|
79
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
78
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
80
79
|
});
|
81
80
|
|
82
81
|
xtest('forced writes act like write in a non-full buffer', () => {
|
@@ -85,17 +84,17 @@ describe('CircularBuffer', () => {
|
|
85
84
|
buffer.forceWrite('2');
|
86
85
|
expect(buffer.read()).toBe('1');
|
87
86
|
expect(buffer.read()).toBe('2');
|
88
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
87
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
89
88
|
});
|
90
89
|
|
91
90
|
xtest('alternate force write and read into full buffer', () => {
|
92
91
|
const buffer = circularBuffer(5);
|
93
|
-
[1,2,3].map(i => buffer.write(i.toString()));
|
92
|
+
[1, 2, 3].map(i => buffer.write(i.toString()));
|
94
93
|
buffer.read();
|
95
94
|
buffer.read();
|
96
95
|
buffer.write('4');
|
97
96
|
buffer.read();
|
98
|
-
[5,6,7,8].map(i => buffer.write(i.toString()));
|
97
|
+
[5, 6, 7, 8].map(i => buffer.write(i.toString()));
|
99
98
|
buffer.forceWrite('A');
|
100
99
|
buffer.forceWrite('B');
|
101
100
|
expect(buffer.read()).toBe('6');
|
@@ -103,7 +102,6 @@ describe('CircularBuffer', () => {
|
|
103
102
|
expect(buffer.read()).toBe('8');
|
104
103
|
expect(buffer.read()).toBe('A');
|
105
104
|
expect(buffer.read()).toBe('B');
|
106
|
-
expect(()=>buffer.read()).toThrow(BufferEmptyError);
|
105
|
+
expect(() => buffer.read()).toThrow(BufferEmptyError);
|
107
106
|
});
|
108
|
-
|
109
107
|
});
|
@@ -1,34 +1,35 @@
|
|
1
|
-
let buffer,
|
1
|
+
let buffer,
|
2
|
+
bufferMax;
|
2
3
|
|
3
4
|
export class BufferEmptyError extends Error {
|
4
5
|
constructor(message) {
|
5
6
|
super();
|
6
7
|
this.message = message || 'Buffer is empty.';
|
7
8
|
}
|
8
|
-
}
|
9
|
+
}
|
9
10
|
export class BufferFullError extends Error {
|
10
11
|
constructor(message) {
|
11
12
|
super();
|
12
13
|
this.message = message || 'Buffer is full.';
|
13
14
|
}
|
14
|
-
}
|
15
|
+
}
|
15
16
|
|
16
17
|
const read = () => {
|
17
|
-
if (buffer.length === 0){
|
18
|
+
if (buffer.length === 0) {
|
18
19
|
throw new BufferEmptyError();
|
19
20
|
}
|
20
|
-
return buffer.splice(0,1)[0];
|
21
|
+
return buffer.splice(0, 1)[0];
|
21
22
|
};
|
22
23
|
|
23
24
|
const write = (value) => {
|
24
|
-
if (buffer.length === bufferMax){
|
25
|
+
if (buffer.length === bufferMax) {
|
25
26
|
throw new BufferFullError();
|
26
27
|
}
|
27
28
|
value ? buffer.push(value) : null;
|
28
29
|
};
|
29
30
|
|
30
31
|
const forceWrite = (value) => {
|
31
|
-
if (buffer.length === bufferMax){
|
32
|
+
if (buffer.length === bufferMax) {
|
32
33
|
read();
|
33
34
|
}
|
34
35
|
write(value);
|
@@ -40,10 +41,10 @@ const CircularBuffer = (capacity) => {
|
|
40
41
|
buffer = [];
|
41
42
|
bufferMax = capacity;
|
42
43
|
return {
|
43
|
-
read
|
44
|
-
write
|
45
|
-
forceWrite
|
46
|
-
clear
|
44
|
+
read,
|
45
|
+
write,
|
46
|
+
forceWrite,
|
47
|
+
clear,
|
47
48
|
};
|
48
49
|
};
|
49
50
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
import at from './clock';
|
2
2
|
|
3
3
|
describe('Clock', () => {
|
4
|
-
|
5
4
|
describe('Creating a new clock with an initial time', () => {
|
6
|
-
|
7
5
|
test('on the hour', () => {
|
8
6
|
expect(at(8).toString()).toEqual('08:00');
|
9
7
|
});
|
@@ -81,7 +79,6 @@ describe('Clock', () => {
|
|
81
79
|
});
|
82
80
|
|
83
81
|
describe('Adding and subtracting minutes', () => {
|
84
|
-
|
85
82
|
xtest('add minutes', () => {
|
86
83
|
expect(at(10, 0).plus(3).toString()).toEqual('10:03');
|
87
84
|
});
|
@@ -145,11 +142,9 @@ describe('Clock', () => {
|
|
145
142
|
xtest('subtract more than two days', () => {
|
146
143
|
expect(at(2, 20).minus(3000).toString()).toEqual('00:20');
|
147
144
|
});
|
148
|
-
|
149
145
|
});
|
150
146
|
|
151
147
|
describe('Construct two separate clocks, set times, test if they are equal', () => {
|
152
|
-
|
153
148
|
xtest('clocks with same time', () => {
|
154
149
|
expect(at(15, 37).equals(at(15, 37))).toBeTruthy();
|
155
150
|
});
|
@@ -209,9 +204,6 @@ describe('Clock', () => {
|
|
209
204
|
xtest('clocks with negative hours and minutes that wrap', () => {
|
210
205
|
expect(at(18, 7).equals(at(-54, -11513))).toBeTruthy();
|
211
206
|
});
|
212
|
-
|
213
207
|
});
|
214
|
-
|
215
208
|
});
|
216
|
-
|
217
209
|
});
|
@@ -1,15 +1,15 @@
|
|
1
|
-
export default function(hour, minute) {
|
1
|
+
export default function (hour, minute) {
|
2
2
|
const MINUTESPERDAY = 1440;
|
3
3
|
const HOURSPERDAY = 24;
|
4
4
|
|
5
|
-
|
6
|
-
hour
|
7
|
-
minute: minute || 0
|
5
|
+
const clock = {
|
6
|
+
hour,
|
7
|
+
minute: minute || 0,
|
8
8
|
};
|
9
9
|
|
10
10
|
function formatNum(num) {
|
11
11
|
const numString = num.toString();
|
12
|
-
return numString.length === 1 ?
|
12
|
+
return numString.length === 1 ? `0${numString}` : numString;
|
13
13
|
}
|
14
14
|
|
15
15
|
function adjustTime(delta) {
|
@@ -27,10 +27,10 @@ export default function(hour, minute) {
|
|
27
27
|
adjustTime(0);
|
28
28
|
|
29
29
|
return {
|
30
|
-
clock
|
31
|
-
toString: () => formatNum(clock.hour)
|
32
|
-
plus
|
33
|
-
minus
|
34
|
-
equals:
|
35
|
-
}
|
30
|
+
clock,
|
31
|
+
toString: () => `${formatNum(clock.hour)}:${formatNum(clock.minute)}`,
|
32
|
+
plus(minutes) { adjustTime(minutes); return this; },
|
33
|
+
minus(minutes) { adjustTime(-minutes); return this; },
|
34
|
+
equals: otherClock => clock.hour === otherClock.clock.hour && clock.minute === otherClock.clock.minute,
|
35
|
+
};
|
36
36
|
}
|
@@ -1,110 +1,108 @@
|
|
1
1
|
import Board from './connect';
|
2
2
|
|
3
3
|
describe('Judging a game of connect', () => {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
" . . . . ."
|
4
|
+
test('an empty board has no winner', () => {
|
5
|
+
const board = [
|
6
|
+
'. . . . .',
|
7
|
+
' . . . . .',
|
8
|
+
' . . . . .',
|
9
|
+
' . . . . .',
|
10
|
+
' . . . . .',
|
12
11
|
];
|
13
|
-
expect(new Board(board).winner()).toEqual(
|
12
|
+
expect(new Board(board).winner()).toEqual('');
|
14
13
|
});
|
15
14
|
|
16
|
-
xtest(
|
17
|
-
|
18
|
-
|
15
|
+
xtest('X can win on a 1x1 board', () => {
|
16
|
+
const board = [
|
17
|
+
'X',
|
19
18
|
];
|
20
|
-
expect(new Board(board).winner()).toEqual(
|
19
|
+
expect(new Board(board).winner()).toEqual('X');
|
21
20
|
});
|
22
21
|
|
23
|
-
xtest(
|
24
|
-
|
25
|
-
|
22
|
+
xtest('O can win on a 1x1 board', () => {
|
23
|
+
const board = [
|
24
|
+
'O',
|
26
25
|
];
|
27
|
-
expect(new Board(board).winner()).toEqual(
|
26
|
+
expect(new Board(board).winner()).toEqual('O');
|
28
27
|
});
|
29
28
|
|
30
|
-
xtest(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
xtest('only edges does not make a winner', () => {
|
30
|
+
const board = [
|
31
|
+
'O O O X',
|
32
|
+
' X . . X',
|
33
|
+
' X . . X',
|
34
|
+
' X O O O',
|
36
35
|
];
|
37
|
-
expect(new Board(board).winner()).toEqual(
|
36
|
+
expect(new Board(board).winner()).toEqual('');
|
38
37
|
});
|
39
38
|
|
40
|
-
xtest(
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
xtest('illegal diagonal does not make a winner', () => {
|
40
|
+
const board = [
|
41
|
+
'X O . .',
|
42
|
+
' O X X X',
|
43
|
+
' O X O .',
|
44
|
+
' . O X .',
|
45
|
+
' X X O O',
|
47
46
|
];
|
48
|
-
expect(new Board(board).winner()).toEqual(
|
47
|
+
expect(new Board(board).winner()).toEqual('');
|
49
48
|
});
|
50
49
|
|
51
|
-
xtest(
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
xtest('nobody wins crossing adjacent angles', () => {
|
51
|
+
const board = [
|
52
|
+
'X . . .',
|
53
|
+
' . X O .',
|
54
|
+
' O . X O',
|
55
|
+
' . O . X',
|
56
|
+
' . . O .',
|
58
57
|
];
|
59
|
-
expect(new Board(board).winner()).toEqual(
|
58
|
+
expect(new Board(board).winner()).toEqual('');
|
60
59
|
});
|
61
60
|
|
62
|
-
xtest(
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
xtest('X wins crossing from left to right', () => {
|
62
|
+
const board = [
|
63
|
+
'. O . .',
|
64
|
+
' O X X X',
|
65
|
+
' O X O .',
|
66
|
+
' X X O X',
|
67
|
+
' . O X .',
|
69
68
|
];
|
70
|
-
expect(new Board(board).winner()).toEqual(
|
69
|
+
expect(new Board(board).winner()).toEqual('X');
|
71
70
|
});
|
72
71
|
|
73
|
-
xtest(
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
72
|
+
xtest('O wins crossing from top to bottom', () => {
|
73
|
+
const board = [
|
74
|
+
'. O . .',
|
75
|
+
' O X X X',
|
76
|
+
' O O O .',
|
77
|
+
' X X O X',
|
78
|
+
' . O X .',
|
80
79
|
];
|
81
|
-
expect(new Board(board).winner()).toEqual(
|
80
|
+
expect(new Board(board).winner()).toEqual('O');
|
82
81
|
});
|
83
82
|
|
84
|
-
xtest(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
83
|
+
xtest('X wins using a convoluted path', () => {
|
84
|
+
const board = [
|
85
|
+
'. X X . .',
|
86
|
+
' X . X . X',
|
87
|
+
' . X . X .',
|
88
|
+
' . X X . .',
|
89
|
+
' O O O O O',
|
91
90
|
];
|
92
|
-
expect(new Board(board).winner()).toEqual(
|
91
|
+
expect(new Board(board).winner()).toEqual('X');
|
93
92
|
});
|
94
93
|
|
95
|
-
xtest(
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
94
|
+
xtest('X wins using a spiral path', () => {
|
95
|
+
const board = [
|
96
|
+
'O X X X X X X X X',
|
97
|
+
' O X O O O O O O O',
|
98
|
+
' O X O X X X X X O',
|
99
|
+
' O X O X O O O X O',
|
100
|
+
' O X O X X X O X O',
|
101
|
+
' O X O O O X O X O',
|
102
|
+
' O X X X X X O X O',
|
103
|
+
' O O O O O O O X O',
|
104
|
+
' X X X X X X X X O',
|
106
105
|
];
|
107
|
-
expect(new Board(board).winner()).toEqual(
|
106
|
+
expect(new Board(board).winner()).toEqual('X');
|
108
107
|
});
|
109
|
-
|
110
108
|
});
|
@@ -4,67 +4,65 @@
|
|
4
4
|
*/
|
5
5
|
export default class {
|
6
6
|
constructor(board) {
|
7
|
-
this.board = board.map(
|
7
|
+
this.board = board.map(b => [...b]);
|
8
8
|
}
|
9
9
|
winner() {
|
10
|
-
const players = ['X','O'];
|
11
|
-
for(
|
12
|
-
if(this.checkWin(player)) {
|
10
|
+
const players = ['X', 'O'];
|
11
|
+
for (const player of players) {
|
12
|
+
if (this.checkWin(player)) {
|
13
13
|
return player;
|
14
14
|
}
|
15
15
|
}
|
16
|
-
return
|
16
|
+
return '';
|
17
17
|
}
|
18
18
|
checkWin(player) {
|
19
|
-
|
20
|
-
for(
|
21
|
-
if(this.search(position, player,[])) {
|
19
|
+
const positions = this.startPositions(player);
|
20
|
+
for (const position of positions) {
|
21
|
+
if (this.search(position, player, [])) {
|
22
22
|
return true;
|
23
23
|
}
|
24
24
|
}
|
25
25
|
return false;
|
26
26
|
}
|
27
27
|
search(pos, XorO, checked) {
|
28
|
-
if(!
|
28
|
+
if (!this.matches(pos, XorO)) {
|
29
29
|
return false;
|
30
30
|
}
|
31
|
-
if(this.winningSpot(pos, XorO)) {
|
31
|
+
if (this.winningSpot(pos, XorO)) {
|
32
32
|
return true;
|
33
33
|
}
|
34
34
|
checked = checked.slice(0);
|
35
35
|
checked.push(pos);
|
36
|
-
const matches = this.neighbors(pos).filter(({x,y}) => {
|
37
|
-
|
38
|
-
|
39
|
-
if(matches.length === 0) {
|
40
|
-
return false;
|
36
|
+
const matches = this.neighbors(pos).filter(({ x, y }) => this.matches({ x, y }, XorO) && checked.filter(spot => spot.x === x && spot.y === y).length === 0);
|
37
|
+
if (matches.length === 0) {
|
38
|
+
return false;
|
41
39
|
}
|
42
40
|
|
43
41
|
return matches.filter(spot => this.search(spot, XorO, checked)).length > 0;
|
44
42
|
}
|
45
|
-
neighbors({x,y}) {
|
43
|
+
neighbors({ x, y }) {
|
46
44
|
return [
|
47
|
-
{x, y: y + 2},
|
48
|
-
{x, y: y - 2},
|
45
|
+
{ x, y: y + 2 },
|
46
|
+
{ x, y: y - 2 },
|
49
47
|
|
50
|
-
{x: x + 1, y: y + 1},
|
51
|
-
{x: x - 1, y: y + 1},
|
48
|
+
{ x: x + 1, y: y + 1 },
|
49
|
+
{ x: x - 1, y: y + 1 },
|
52
50
|
|
53
|
-
{x: x + 1, y: y - 1},
|
54
|
-
{x: x - 1, y: y - 1}
|
51
|
+
{ x: x + 1, y: y - 1 },
|
52
|
+
{ x: x - 1, y: y - 1 },
|
55
53
|
];
|
56
54
|
}
|
57
55
|
startPositions(XorO) {
|
58
|
-
return XorO ===
|
59
|
-
this.board.map((pos, i) => ({x:i,y:i})) :
|
60
|
-
this.board[0].map((pos, i) => ({x:0, y:i}));
|
56
|
+
return XorO === 'X' ?
|
57
|
+
this.board.map((pos, i) => ({ x: i, y: i })) :
|
58
|
+
this.board[0].map((pos, i) => ({ x: 0, y: i }));
|
61
59
|
}
|
62
|
-
winningSpot({x,y},XorO) {
|
63
|
-
return XorO ===
|
64
|
-
y === this.board[0].length - 1 + x:
|
60
|
+
winningSpot({ x, y }, XorO) {
|
61
|
+
return XorO === 'X' ?
|
62
|
+
y === this.board[0].length - 1 + x :
|
65
63
|
x === this.board.length - 1;
|
66
64
|
}
|
67
|
-
matches({x,y}, XorO) {
|
65
|
+
matches({ x, y }, XorO) {
|
68
66
|
return this.board[x] !== undefined && this.board[x][y] === XorO;
|
69
67
|
}
|
70
68
|
}
|
@@ -1,52 +1,52 @@
|
|
1
1
|
import Crypto from './crypto-square';
|
2
2
|
|
3
|
-
describe('Crypto',() => {
|
4
|
-
test('normalize strange characters',() => {
|
3
|
+
describe('Crypto', () => {
|
4
|
+
test('normalize strange characters', () => {
|
5
5
|
const crypto = new Crypto('s#$%^&plunk');
|
6
6
|
expect(crypto.normalizePlaintext()).toEqual('splunk');
|
7
7
|
});
|
8
8
|
|
9
|
-
xtest('normalize numbers',() => {
|
9
|
+
xtest('normalize numbers', () => {
|
10
10
|
const crypto = new Crypto('1, 2, 3 GO!');
|
11
11
|
expect(crypto.normalizePlaintext()).toEqual('123go');
|
12
12
|
});
|
13
13
|
|
14
|
-
xtest('size of small square',() => {
|
14
|
+
xtest('size of small square', () => {
|
15
15
|
const crypto = new Crypto('1234');
|
16
16
|
expect(crypto.size()).toEqual(2);
|
17
17
|
});
|
18
18
|
|
19
|
-
xtest('size of small square with additional non-number chars',() => {
|
19
|
+
xtest('size of small square with additional non-number chars', () => {
|
20
20
|
const crypto = new Crypto('1 2 3 4');
|
21
21
|
expect(crypto.size()).toEqual(2);
|
22
22
|
});
|
23
23
|
|
24
|
-
xtest('size of slightly larger square',() => {
|
24
|
+
xtest('size of slightly larger square', () => {
|
25
25
|
const crypto = new Crypto('123456789');
|
26
26
|
expect(crypto.size()).toEqual(3);
|
27
27
|
});
|
28
28
|
|
29
|
-
xtest('size of non-perfect square',() => {
|
29
|
+
xtest('size of non-perfect square', () => {
|
30
30
|
const crypto = new Crypto('123456789abc');
|
31
31
|
expect(crypto.size()).toEqual(4);
|
32
32
|
});
|
33
33
|
|
34
|
-
xtest('plain text segments',() => {
|
34
|
+
xtest('plain text segments', () => {
|
35
35
|
const crypto = new Crypto('Never vex thine heart with idle woes');
|
36
36
|
expect(crypto.plaintextSegments()).toEqual(['neverv', 'exthin', 'eheart', 'withid', 'lewoes']);
|
37
37
|
});
|
38
38
|
|
39
|
-
xtest('plain text segments',() => {
|
39
|
+
xtest('plain text segments', () => {
|
40
40
|
const crypto = new Crypto('ZOMG! ZOMBIES!!!');
|
41
41
|
expect(crypto.plaintextSegments()).toEqual(['zomg', 'zomb', 'ies']);
|
42
42
|
});
|
43
43
|
|
44
|
-
xtest('cipher text',() => {
|
44
|
+
xtest('cipher text', () => {
|
45
45
|
const crypto = new Crypto('Time is an illusion. Lunchtime doubly so.');
|
46
46
|
expect(crypto.ciphertext()).toEqual('tasneyinicdsmiohooelntuillibsuuml');
|
47
47
|
});
|
48
48
|
|
49
|
-
xtest('cipher text',() => {
|
49
|
+
xtest('cipher text', () => {
|
50
50
|
const crypto = new Crypto('We all know interspecies romance is weird.');
|
51
51
|
expect(crypto.ciphertext()).toEqual('wneiaweoreneawssciliprerlneoidktcms');
|
52
52
|
});
|
@@ -1,29 +1,30 @@
|
|
1
1
|
export default class Square {
|
2
|
-
constructor
|
2
|
+
constructor(input) {
|
3
3
|
this.input = input;
|
4
4
|
}
|
5
5
|
|
6
|
-
normalizePlaintext
|
7
|
-
return this.input.toLowerCase().replace(/[^a-zA-Z0-9]/g,'');
|
6
|
+
normalizePlaintext() {
|
7
|
+
return this.input.toLowerCase().replace(/[^a-zA-Z0-9]/g, '');
|
8
8
|
}
|
9
9
|
|
10
|
-
size
|
10
|
+
size() {
|
11
11
|
const realLength = Math.sqrt(this.normalizePlaintext().length);
|
12
12
|
return Math.ceil(realLength);
|
13
13
|
}
|
14
14
|
|
15
|
-
plaintextSegments
|
15
|
+
plaintextSegments() {
|
16
16
|
const plainText = this.normalizePlaintext();
|
17
17
|
const chunkSize = this.size();
|
18
18
|
|
19
|
-
const splitRegex = new RegExp(
|
19
|
+
const splitRegex = new RegExp(`.{1,${chunkSize}}`, 'g');
|
20
20
|
return plainText.match(splitRegex);
|
21
21
|
}
|
22
22
|
|
23
|
-
ciphertext
|
23
|
+
ciphertext() {
|
24
24
|
const textSegments = this.plaintextSegments(),
|
25
25
|
columns = [];
|
26
|
-
let i,
|
26
|
+
let i,
|
27
|
+
j,
|
27
28
|
currentSegment,
|
28
29
|
currentLetter;
|
29
30
|
|
@@ -47,9 +48,9 @@ export default class Square {
|
|
47
48
|
return columns.join('');
|
48
49
|
}
|
49
50
|
|
50
|
-
normalizeCiphertext
|
51
|
+
normalizeCiphertext() {
|
51
52
|
const chunkSize = this.size();
|
52
|
-
const splitRegex = new RegExp(
|
53
|
+
const splitRegex = new RegExp(`.{1,${chunkSize}}`, 'g');
|
53
54
|
return this.ciphertext().match(splitRegex).join(' ');
|
54
55
|
}
|
55
56
|
}
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import CustomSet from './custom-set';
|
2
2
|
|
3
3
|
describe('CustomSet', () => {
|
4
|
-
|
5
|
-
test('can delete elements', () =>{
|
4
|
+
test('can delete elements', () => {
|
6
5
|
const expected = new CustomSet([1, 3]);
|
7
6
|
const actual = new CustomSet([3, 2, 1]).delete(2);
|
8
7
|
expect(actual.eql(expected)).toBe(true);
|
@@ -12,7 +11,7 @@ describe('CustomSet', () => {
|
|
12
11
|
expect(actual2.eql(expected2)).toBe(true);
|
13
12
|
});
|
14
13
|
|
15
|
-
xtest('can check for difference', () =>{
|
14
|
+
xtest('can check for difference', () => {
|
16
15
|
const expected = new CustomSet([1, 3]);
|
17
16
|
const actual = new CustomSet([3, 2, 1]).difference(new CustomSet([2, 4]));
|
18
17
|
expect(actual.eql(expected)).toBe(true);
|
@@ -113,5 +112,4 @@ describe('CustomSet', () => {
|
|
113
112
|
const expected4 = new CustomSet();
|
114
113
|
expect(actual4.eql(expected4)).toBe(true);
|
115
114
|
});
|
116
|
-
|
117
115
|
});
|