mirror of
https://gitlab.com/mfocko/CodeWars.git
synced 2024-12-13 01:21:21 +01:00
chore: initial commit
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
commit
fc899b0b02
217 changed files with 5356 additions and 0 deletions
127
3kyu/battleship_field_validator/solution.cs
Normal file
127
3kyu/battleship_field_validator/solution.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
namespace Solution {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BattleshipField {
|
||||
private enum Direction {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
}
|
||||
|
||||
private class Ship {
|
||||
private int y, x;
|
||||
private Direction d;
|
||||
private int size;
|
||||
|
||||
public int Size {get => size;}
|
||||
|
||||
public Ship(int y, int x, Direction d, int size) {
|
||||
this.y = y;
|
||||
this.x = x;
|
||||
this.d = d;
|
||||
this.size = size;
|
||||
}
|
||||
public bool IsTouching(Ship b) {
|
||||
if (d == Direction.HORIZONTAL) {
|
||||
if ((b.y >= this.y - 1 && b.y <= this.y + 1) &&
|
||||
(b.x >= this.x - 1 && b.x <= this.x + this.size))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (d == Direction.VERTICAL) {
|
||||
if ((b.x >= this.x - 1 && b.x <= this.x + 1) &&
|
||||
(b.y >= this.y - 1 && b.y <= this.y + this.size))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public override string ToString() {
|
||||
string direction = this.d == Direction.HORIZONTAL ? "horizontal" : "vertical";
|
||||
return $"x: {this.x}\ty: {this.y}\tdir: {direction}\tsize: {this.size}";
|
||||
}
|
||||
}
|
||||
|
||||
private List<Ship> ships;
|
||||
private int battleships = 1,
|
||||
cruisers = 2,
|
||||
destroyers = 3,
|
||||
submarines = 4;
|
||||
|
||||
public BattleshipField() {
|
||||
this.ships = new List<Ship>();
|
||||
}
|
||||
|
||||
private void registerShip(int y, int x, Direction d, int count) {
|
||||
this.ships.Add(new Ship(y, x, d, count));
|
||||
switch (count) {
|
||||
case 1:
|
||||
this.submarines--;
|
||||
break;
|
||||
case 2:
|
||||
this.destroyers--;
|
||||
break;
|
||||
case 3:
|
||||
this.cruisers--;
|
||||
break;
|
||||
case 4:
|
||||
this.battleships--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool areTouching() {
|
||||
for (var i = 0; i < this.ships.Count - 1; i++)
|
||||
for (var j = i + 1; j < this.ships.Count; j++)
|
||||
if (this.ships[i].IsTouching(this.ships[j])) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsValidField() {
|
||||
if (this.submarines != 0 || this.destroyers != 0 ||
|
||||
this.cruisers != 0 || this.battleships != 0)
|
||||
return false;
|
||||
else if (this.areTouching())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ValidateBattlefield(int[,] field) {
|
||||
// Write your magic here
|
||||
var validator = new BattleshipField();
|
||||
int count = 0;
|
||||
|
||||
for (int y = 0, rows = field.GetLength(0); y < rows; y++) {
|
||||
for (int x = 0, cols = field.GetLength(0); x < cols; x++) {
|
||||
if (field[y, x] == 1) {
|
||||
// check for vertical ship
|
||||
if (count == 0) {
|
||||
if (y < rows - 1 && field[y + 1, x] == 1) {
|
||||
for (int dy = 0; y + dy < rows; dy++) {
|
||||
if (field[y + dy, x] == 1) {
|
||||
field[y + dy, x] = 0;
|
||||
count++;
|
||||
} else break;
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
validator.registerShip(y, x, Direction.VERTICAL, count);
|
||||
count = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
field[y, x] = 0;
|
||||
count++;
|
||||
} else if (field[y, x] == 0 && count > 0) {
|
||||
validator.registerShip(y, x - count, Direction.HORIZONTAL, count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return validator.IsValidField();
|
||||
}
|
||||
}
|
||||
}
|
103
3kyu/binomial_expansion/solution.cs
Normal file
103
3kyu/binomial_expansion/solution.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class KataSolution {
|
||||
public static IEnumerable<long> Combinations(long n) {
|
||||
if (n < 0) {
|
||||
Console.WriteLine("Error happened");
|
||||
throw new ArgumentException("n cannot be negative");
|
||||
}
|
||||
|
||||
for (
|
||||
long k = 0, nCk = 1;
|
||||
k <= n;
|
||||
nCk = nCk * (n - k) / (k + 1), k++
|
||||
) {
|
||||
yield return nCk;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<long> Range(long count) {
|
||||
for (var i = 0; i < count; i++) {
|
||||
yield return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<long> Expand(int a, int b, int n) {
|
||||
long aExpd = (long) Math.Pow(a, n);
|
||||
long bExpd = 1;
|
||||
foreach (var nCk in Combinations(n)) {
|
||||
yield return nCk * aExpd * bExpd;
|
||||
|
||||
aExpd /= a;
|
||||
bExpd *= b;
|
||||
}
|
||||
}
|
||||
|
||||
public static (int, int, string) ParseInner(string expr) {
|
||||
var innerPart = expr.Split('^')[0];
|
||||
innerPart = innerPart.Substring(1, innerPart.Length - 2);
|
||||
|
||||
var coeffA = new String(
|
||||
innerPart.TakeWhile(c => !char.IsLetter(c)).ToArray()
|
||||
);
|
||||
var variable = new String(
|
||||
innerPart.SkipWhile(c => !char.IsLetter(c)).TakeWhile(char.IsLetter).ToArray()
|
||||
);
|
||||
var coeffB = new String(
|
||||
innerPart.SkipWhile(c => !char.IsLetter(c)).SkipWhile(char.IsLetter).ToArray()
|
||||
);
|
||||
|
||||
var parsedCoeffA = coeffA switch {
|
||||
"" => 1,
|
||||
"-" => -1,
|
||||
_ => int.Parse(coeffA)
|
||||
};
|
||||
|
||||
return (parsedCoeffA, int.Parse(coeffB), variable);
|
||||
}
|
||||
|
||||
public static int ParseExponent(string expr) {
|
||||
var splitExpr = expr.Split('^');
|
||||
return int.Parse(splitExpr[1]);
|
||||
}
|
||||
|
||||
public static string FormatTerm(long coefficient, string variable, long exponent) {
|
||||
var prefix = (coefficient > 0) ? "+" : "";
|
||||
|
||||
if (coefficient == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if ((coefficient == 1 || coefficient == -1) && exponent == 0) {
|
||||
return $"{prefix}{coefficient}";
|
||||
}
|
||||
|
||||
var coeff = coefficient switch {
|
||||
0 => "",
|
||||
1 => prefix,
|
||||
-1 => "-",
|
||||
_ => $"{prefix}{coefficient}"
|
||||
};
|
||||
var varExp = exponent switch {
|
||||
0 => "",
|
||||
1 => variable,
|
||||
_ => $"{variable}^{exponent}"
|
||||
};
|
||||
return $"{coeff}{varExp}";
|
||||
}
|
||||
|
||||
public static string Expand(string expr) {
|
||||
var n = ParseExponent(expr);
|
||||
var (a, b, variable) = ParseInner(expr);
|
||||
|
||||
var result = "";
|
||||
|
||||
foreach (var (exponent, coefficient) in Range(n + 1).Reverse().Zip(Expand(a, b, n))) {
|
||||
result += FormatTerm(coefficient, variable, exponent);
|
||||
}
|
||||
|
||||
return result.TrimStart(new char[] {'+'});
|
||||
}
|
||||
}
|
88
3kyu/screen_locking_patterns/solution.cs
Normal file
88
3kyu/screen_locking_patterns/solution.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public static class Kata {
|
||||
private class Graph {
|
||||
private struct Edge {
|
||||
public char Through { get; set; }
|
||||
public char To { get; set; }
|
||||
};
|
||||
|
||||
public static readonly char NO_CONDITION = '\0';
|
||||
|
||||
private Dictionary<char, List<Edge>> edges = new Dictionary<char, List<Edge>>();
|
||||
private HashSet<char> visited = new HashSet<char>();
|
||||
|
||||
private Graph addEdge(char src, char through, char dst) {
|
||||
var newEdge = new Edge {
|
||||
Through = through,
|
||||
To = dst
|
||||
};
|
||||
|
||||
if (edges.TryGetValue(src, out var lst)) {
|
||||
lst.Add(newEdge);
|
||||
} else {
|
||||
edges.Add(src, new List<Edge>() { newEdge });
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Graph AddDirectEdge(char src, char dst)
|
||||
=> addEdge(src, NO_CONDITION, dst);
|
||||
public Graph AddIndirectEdge(char src, char through, char dst)
|
||||
=> addEdge(src, through, dst);
|
||||
public Graph AddBiDirectEdge(char src, char dst)
|
||||
=> AddBiIndirectEdge(src, NO_CONDITION, dst);
|
||||
public Graph AddBiIndirectEdge(char src, char through, char dst) =>
|
||||
addEdge(src, through, dst)
|
||||
.addEdge(dst, through, src);
|
||||
|
||||
public void ResetVisited() => visited.Clear();
|
||||
public bool BeenVisited(char vertex) => visited.Contains(vertex);
|
||||
public void Mark(char vertex) => visited.Add(vertex);
|
||||
public void Unmark(char vertex) => visited.Remove(vertex);
|
||||
|
||||
public bool HasEdge(char fromVertex, char toVertex)
|
||||
=> edges[fromVertex].Any(e => e.To == toVertex && (e.Through == NO_CONDITION || BeenVisited(e.Through)));
|
||||
|
||||
public Graph AddMultipleBiDirectEdges(char fromVertex, string toVertices) {
|
||||
foreach (var toVertex in toVertices) {
|
||||
AddBiDirectEdge(fromVertex, toVertex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static Graph g = new Graph()
|
||||
.AddMultipleBiDirectEdges('A', "BDEFH").AddMultipleBiDirectEdges('B', "CDEFGI")
|
||||
.AddMultipleBiDirectEdges('C', "DEFH").AddMultipleBiDirectEdges('D', "EGHI")
|
||||
.AddMultipleBiDirectEdges('E', "FGHI").AddMultipleBiDirectEdges('F', "GHI")
|
||||
.AddMultipleBiDirectEdges('G', "H").AddMultipleBiDirectEdges('H', "I")
|
||||
.AddBiIndirectEdge('A', 'B', 'C').AddBiIndirectEdge('A', 'D', 'G').AddBiIndirectEdge('A', 'E', 'I')
|
||||
.AddBiIndirectEdge('B', 'E', 'H').AddBiIndirectEdge('C', 'E', 'G').AddBiIndirectEdge('C', 'F', 'I')
|
||||
.AddBiIndirectEdge('D', 'E', 'F').AddBiIndirectEdge('G', 'H', 'I');
|
||||
|
||||
public static int CountPatternsFrom(char firstDot, int length) {
|
||||
if (length <= 0 || length >= 10) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (length == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
|
||||
g.Mark(firstDot);
|
||||
foreach (var vertex in "ABCDEFGHI") {
|
||||
if (!g.BeenVisited(vertex) && g.HasEdge(firstDot, vertex)) {
|
||||
total += CountPatternsFrom(vertex, length - 1);
|
||||
}
|
||||
}
|
||||
g.Unmark(firstDot);
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
181
4kyu/4_by_4_skyscrapers/solution.cs
Normal file
181
4kyu/4_by_4_skyscrapers/solution.cs
Normal file
|
@ -0,0 +1,181 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class Skyscrapers {
|
||||
private static IEnumerable<List<T>> Permutations<T>(List<T> initial)
|
||||
where T: IComparable<T> {
|
||||
yield return initial;
|
||||
|
||||
var hasNext = initial.Count > 1;
|
||||
while (hasNext) {
|
||||
var k = 0;
|
||||
var l = 0;
|
||||
hasNext = false;
|
||||
|
||||
for (var i = initial.Count - 1; i > 0; i--) {
|
||||
if (initial[i].CompareTo(initial[i - 1]) > 0) {
|
||||
k = i - 1;
|
||||
hasNext = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = initial.Count - 1; i > k; i--) {
|
||||
if (initial[i].CompareTo(initial[k]) > 0) {
|
||||
l = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(initial[k], initial[l]) = (initial[l], initial[k]);
|
||||
initial.Reverse(k + 1, initial.Count - k - 1);
|
||||
|
||||
if (hasNext) {
|
||||
yield return initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValid(List<int> heights, int clue) {
|
||||
var canSee = 1;
|
||||
var lastHeight = heights[0];
|
||||
|
||||
for (var i = 1; i < heights.Count; i++) {
|
||||
var currentHeight = heights[i];
|
||||
if (currentHeight > lastHeight) {
|
||||
lastHeight = currentHeight;
|
||||
canSee++;
|
||||
}
|
||||
}
|
||||
|
||||
return canSee == clue;
|
||||
}
|
||||
|
||||
private static IEnumerable<List<int>> PossibleHeights(int size, int clue) {
|
||||
var initial = new List<int>();
|
||||
for (var i = 0; i < size; i++) {
|
||||
initial.Add(i + 1);
|
||||
}
|
||||
|
||||
if (clue == 0) {
|
||||
return Permutations(initial);
|
||||
}
|
||||
|
||||
return Permutations(initial).Where(heights => IsValid(heights, clue));
|
||||
}
|
||||
|
||||
private static int Size {
|
||||
get => 4;
|
||||
}
|
||||
|
||||
private static (int, int) GetDiffs(int clueIndex) {
|
||||
if (clueIndex < Size) {
|
||||
return (0, 1);
|
||||
} else if (clueIndex < 2 * Size) {
|
||||
return (-1, 0);
|
||||
} else if (clueIndex < 3 * Size) {
|
||||
return (0, -1);
|
||||
}
|
||||
return (1, 0);
|
||||
}
|
||||
|
||||
private static (int, int) GetStarts(int clueIndex) {
|
||||
if (clueIndex < Size) {
|
||||
return (clueIndex, 0);
|
||||
} else if (clueIndex < 2 * Size) {
|
||||
return (Size - 1, clueIndex % Size);
|
||||
} else if (clueIndex < 3 * Size) {
|
||||
return (Size - 1 - clueIndex % Size, Size - 1);
|
||||
}
|
||||
return (0, Size - 1 - clueIndex % Size);
|
||||
}
|
||||
|
||||
private static List<int> BackupHeights(int[][] heights, int clueIndex) {
|
||||
var backup = new List<int>();
|
||||
|
||||
var (dx, dy) = GetDiffs(clueIndex);
|
||||
for (
|
||||
var (x, y) = GetStarts(clueIndex);
|
||||
x >= 0 && x < Size && y >= 0 && y < Size;
|
||||
x += dx, y += dy
|
||||
) {
|
||||
backup.Add(heights[y][x]);
|
||||
}
|
||||
|
||||
return backup;
|
||||
}
|
||||
|
||||
private static bool EmplaceHeights(
|
||||
int[][] heights, int clueIndex, List<int> newHeights, bool force
|
||||
) {
|
||||
int i = 0;
|
||||
|
||||
var (dx, dy) = GetDiffs(clueIndex);
|
||||
for (
|
||||
var (x, y) = GetStarts(clueIndex);
|
||||
x >= 0 && x < Size && y >= 0 && y < Size;
|
||||
x += dx, y += dy
|
||||
) {
|
||||
if (
|
||||
!force && heights[y][x] != 0 && heights[y][x] != newHeights[i]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
heights[y][x] = newHeights[i++];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool SolvePuzzle(
|
||||
int[][] heights, int[] clues, int clueIndex, bool ignoreZeroes
|
||||
) {
|
||||
while (clueIndex < 4 * Size && (
|
||||
(ignoreZeroes && clues[clueIndex] == 0) || (!ignoreZeroes && clues[clueIndex] != 0)
|
||||
)) {
|
||||
clueIndex++;
|
||||
}
|
||||
|
||||
if (clueIndex >= 4 * Size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// create copy of heights to ensure correct resetting
|
||||
var currentHeights = BackupHeights(heights, clueIndex);
|
||||
|
||||
// iterate through the options
|
||||
foreach (var possibleHeights in PossibleHeights(Size, clues[clueIndex])) {
|
||||
// emplace heights and if conflict occurs, reset and try next one
|
||||
if (!EmplaceHeights(heights, clueIndex, possibleHeights, false)) {
|
||||
EmplaceHeights(heights, clueIndex, currentHeights, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if no conflict present, try filling out other clues
|
||||
if (SolvePuzzle(heights, clues, clueIndex + 1, ignoreZeroes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise reset heights and try again
|
||||
EmplaceHeights(heights, clueIndex, currentHeights, true);
|
||||
}
|
||||
|
||||
// if we got here, there is no feasible configuration of buildings
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int[][] SolvePuzzle(int[] clues) {
|
||||
var result = new int[Size][];
|
||||
for (var i = 0; i < Size; i++) {
|
||||
result[i] = new int[Size];
|
||||
}
|
||||
SolvePuzzle(result, clues, 0, true);
|
||||
|
||||
// in case there are left zeroes
|
||||
SolvePuzzle(result, clues, 0, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
264
4kyu/4_by_4_skyscrapers/solution.java
Normal file
264
4kyu/4_by_4_skyscrapers/solution.java
Normal file
|
@ -0,0 +1,264 @@
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class SkyScrapers {
|
||||
private static class Permutations<T extends Comparable<T>> implements Iterable<List<T>> {
|
||||
public class PermutationsIterator implements Iterator<List<T>> {
|
||||
private List<T> elements;
|
||||
private boolean _hasNext;
|
||||
private boolean firstIteration = true;
|
||||
|
||||
public PermutationsIterator(List<T> elements) {
|
||||
this.elements = elements;
|
||||
_hasNext = elements.size() > 0;
|
||||
}
|
||||
|
||||
private void swap(int k, int l) {
|
||||
T tmp = elements.get(k);
|
||||
elements.set(k, elements.get(l));
|
||||
elements.set(l, tmp);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return _hasNext;
|
||||
}
|
||||
|
||||
public List<T> next() {
|
||||
if (!_hasNext) {
|
||||
throw new NoSuchElementException("No more permutations are left");
|
||||
}
|
||||
|
||||
var lastIteration = new ArrayList<T>(elements);
|
||||
|
||||
int k = 0, l = 0;
|
||||
_hasNext = false;
|
||||
for (int i = elements.size() - 1; i > 0; i--) {
|
||||
if (elements.get(i).compareTo(elements.get(i - 1)) > 0) {
|
||||
k = i - 1;
|
||||
_hasNext = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = elements.size() - 1; i > k; i--) {
|
||||
if (elements.get(i).compareTo(elements.get(k)) > 0) {
|
||||
l = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
swap(k, l);
|
||||
Collections.reverse(elements.subList(k + 1, elements.size()));
|
||||
|
||||
return lastIteration;
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> elements;
|
||||
|
||||
public Permutations(List<T> elements) {
|
||||
this.elements = elements;
|
||||
Collections.sort(this.elements);
|
||||
}
|
||||
|
||||
public Iterator<List<T>> iterator() {
|
||||
return new PermutationsIterator(elements);
|
||||
}
|
||||
|
||||
public Stream<List<T>> stream() {
|
||||
return StreamSupport.stream(this.spliterator(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PossibleConfigurations implements Iterable<List<Integer>> {
|
||||
private List<Integer> initial;
|
||||
private int clue;
|
||||
|
||||
private void generateInitial(int size) {
|
||||
initial = new ArrayList<Integer>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
initial.add(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public PossibleConfigurations(int size, int clue) {
|
||||
generateInitial(size);
|
||||
this.clue = clue;
|
||||
}
|
||||
|
||||
public Iterator<List<Integer>> iterator() {
|
||||
if (clue == 0) {
|
||||
return (new Permutations(initial)).iterator();
|
||||
}
|
||||
|
||||
return (new Permutations(initial))
|
||||
.stream()
|
||||
.filter(heights -> isValid((List<Integer>) heights, clue))
|
||||
.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValid(List<Integer> heights, int clue) {
|
||||
int canSee = 1;
|
||||
int lastHeight = heights.get(0);
|
||||
|
||||
for (int i = 1; i < heights.size(); i++) {
|
||||
int currentHeight = heights.get(i);
|
||||
if (currentHeight > lastHeight) {
|
||||
lastHeight = currentHeight;
|
||||
canSee++;
|
||||
}
|
||||
}
|
||||
|
||||
return canSee == clue;
|
||||
}
|
||||
|
||||
private static int getDx(int clueIndex) {
|
||||
if (clueIndex >= 4 && clueIndex <= 7) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (clueIndex >= 12) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int getDy(int clueIndex) {
|
||||
if (clueIndex <= 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (clueIndex >= 8 && clueIndex <= 11) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int getStartX(int clueIndex) {
|
||||
if (clueIndex < 4) {
|
||||
return clueIndex;
|
||||
}
|
||||
|
||||
if (clueIndex <= 7) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (clueIndex <= 11) {
|
||||
return 3 - clueIndex % 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int getStartY(int clueIndex) {
|
||||
if (clueIndex < 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (clueIndex <= 7) {
|
||||
return clueIndex % 4;
|
||||
}
|
||||
|
||||
if (clueIndex <= 11) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 3 - clueIndex % 4;
|
||||
}
|
||||
|
||||
private static List<Integer> backupHeights(int[][] heights, int clueIndex) {
|
||||
List<Integer> backup = new ArrayList<Integer>();
|
||||
|
||||
int dx = getDx(clueIndex);
|
||||
int dy = getDy(clueIndex);
|
||||
|
||||
for (
|
||||
int x = getStartX(clueIndex), y = getStartY(clueIndex);
|
||||
x >= 0 && x < 4 && y >= 0 && y < 4;
|
||||
x += dx, y += dy
|
||||
) {
|
||||
backup.add(heights[y][x]);
|
||||
}
|
||||
|
||||
return backup;
|
||||
}
|
||||
|
||||
private static boolean emplaceHeights(
|
||||
int[][] heights, int clueIndex, List<Integer> newHeights, boolean force
|
||||
) {
|
||||
int i = 0;
|
||||
int dx = getDx(clueIndex);
|
||||
int dy = getDy(clueIndex);
|
||||
|
||||
for (
|
||||
int x = getStartX(clueIndex), y = getStartY(clueIndex);
|
||||
x >= 0 && x < 4 && y >= 0 && y < 4;
|
||||
x += dx, y += dy
|
||||
) {
|
||||
if (
|
||||
!force && heights[y][x] != 0 && heights[y][x] != newHeights.get(i)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
heights[y][x] = newHeights.get(i++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean solvePuzzle(
|
||||
int[][] heights, int[] clues, int clueIndex, boolean ignoreZeroes
|
||||
) {
|
||||
while (clueIndex < 16 && ((ignoreZeroes && clues[clueIndex] == 0) || (!ignoreZeroes && clues[clueIndex] != 0))) {
|
||||
clueIndex++;
|
||||
}
|
||||
|
||||
if (clueIndex >= 16) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// create copy of heights to ensure correct resetting
|
||||
List<Integer> currentHeights = backupHeights(heights, clueIndex);
|
||||
|
||||
// iterate through the options
|
||||
for (List<Integer> possibleHeights : new PossibleConfigurations(4, clues[clueIndex])) {
|
||||
|
||||
// emplace heights and if conflict occurs, reset and try next one
|
||||
if (!emplaceHeights(heights, clueIndex, possibleHeights, false)) {
|
||||
emplaceHeights(heights, clueIndex, currentHeights, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if no conflict present, try filling out other clues
|
||||
if (solvePuzzle(heights, clues, clueIndex + 1, ignoreZeroes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise reset heights and try again
|
||||
emplaceHeights(heights, clueIndex, currentHeights, true);
|
||||
}
|
||||
|
||||
// if we got here, there is no feasible configuration of buildings
|
||||
return false;
|
||||
}
|
||||
|
||||
static int[][] solvePuzzle(int[] clues) {
|
||||
var result = new int[4][4];
|
||||
solvePuzzle(result, clues, 0, true);
|
||||
|
||||
// in case there are left zeroes
|
||||
solvePuzzle(result, clues, 0, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
44
4kyu/adding_big_numbers/solution.cs
Normal file
44
4kyu/adding_big_numbers/solution.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
|
||||
public class Kata {
|
||||
public static (uint remainder, uint digit) SumTwo(char a, char b, uint c = 0) {
|
||||
uint val_a = (uint) a - 48;
|
||||
uint val_b = (uint) b - 48;
|
||||
|
||||
var sum = val_a + val_b + c;
|
||||
return (sum / 10, sum % 10);
|
||||
}
|
||||
public static string Add(string a, string b) {
|
||||
var result = "";
|
||||
|
||||
if (a.Length > b.Length) {
|
||||
var temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
int idx_a = a.Length - 1;
|
||||
int idx_b = b.Length - 1;
|
||||
uint remainder = 0;
|
||||
uint last_digit = 0;
|
||||
|
||||
while (idx_a >= 0) {
|
||||
(remainder, last_digit) = SumTwo(a[idx_a], b[idx_b], remainder);
|
||||
result = last_digit.ToString() + result;
|
||||
idx_a--;
|
||||
idx_b--;
|
||||
}
|
||||
|
||||
while (idx_b >= 0) {
|
||||
(remainder, last_digit) = SumTwo('0', b[idx_b], remainder);
|
||||
result = last_digit.ToString() + result;
|
||||
idx_b--;
|
||||
}
|
||||
|
||||
if (remainder > 0) {
|
||||
result = remainder.ToString() + result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
61
4kyu/breadcrumb_generator/solution.js
Normal file
61
4kyu/breadcrumb_generator/solution.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
function checkExtension(name) {
|
||||
const extensions = ['.html', '.htm', '.php', '.asp'];
|
||||
return name.replace(/\.html/g, '').replace(/\.htm/g, '').replace(/\.php/g, '').replace(/\.asp/g, '');
|
||||
}
|
||||
|
||||
function shorten(name) {
|
||||
if (name.length <= 30) {
|
||||
name = name.replace(/-/g, ' ');
|
||||
} else {
|
||||
const ignore = ["the","of","in","from","by","with","and", "or", "for", "to", "at", "a"];
|
||||
|
||||
name = name.split('-').filter(e => !ignore.includes(e)).map(e => e[0]);
|
||||
name = name.join('');
|
||||
}
|
||||
|
||||
return name.toUpperCase();
|
||||
}
|
||||
|
||||
function buildSegment(url, name, last=false) {
|
||||
if (last) {
|
||||
return `<span class="active">${shorten(checkExtension(name))}</span>`;
|
||||
} else {
|
||||
return `<a href="${url}">${shorten(checkExtension(name))}</a>`;
|
||||
}
|
||||
}
|
||||
|
||||
function generateBC(url, separator) {
|
||||
console.log(url);
|
||||
if (url.includes('//')) {
|
||||
url = url.split('//')[1];
|
||||
}
|
||||
|
||||
url = url.split("/").filter(e => {
|
||||
return !e.startsWith('index');
|
||||
}).map(e => {
|
||||
if (e.includes("#"))
|
||||
return e.substring(0, e.indexOf("#"));
|
||||
else if (e.includes("?"))
|
||||
return e.substring(0, e.indexOf("?"));
|
||||
else
|
||||
return e;
|
||||
});
|
||||
|
||||
let result = [];
|
||||
let path = '/';
|
||||
if ((url.length == 2 && url[1] == '') || url.length == 1) {
|
||||
result.push(buildSegment('/', 'home', true));
|
||||
return result.join('');
|
||||
} else
|
||||
result.push(buildSegment('/', 'home'));
|
||||
|
||||
|
||||
for (let i = 1; i < url.length - 1; i++) {
|
||||
path += `${url[i]}/`;
|
||||
result.push(buildSegment(path, url[i]));
|
||||
}
|
||||
path += `/${url[url.length - 1]}`
|
||||
result.push(buildSegment(path, url[url.length - 1], true));
|
||||
|
||||
return result.join(separator);
|
||||
}
|
28
4kyu/counting_change_combinations/solution.cs
Normal file
28
4kyu/counting_change_combinations/solution.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
|
||||
public static class Kata {
|
||||
public static int CountCombinations(int money, int[] coins, bool recursivelyCalled = false) {
|
||||
if (money == 0 && recursivelyCalled) return 1;
|
||||
else if (coins.GetLength(0) == 1) {
|
||||
if (money % coins[0] == 0) return 1;
|
||||
else return 0;
|
||||
} else if (!recursivelyCalled) {
|
||||
Array.Sort(coins);
|
||||
Array.Reverse(coins);
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
|
||||
var times = money / coins[0];
|
||||
var newCoins = new int[coins.GetLength(0) - 1];
|
||||
|
||||
for (var i = 0; i < coins.GetLength(0) - 1; i++)
|
||||
newCoins[i] = coins[i + 1];
|
||||
|
||||
for (var i = 0; i <= times; i++) {
|
||||
result += CountCombinations(money - i * coins[0], newCoins, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
115
4kyu/es5_generators_i/solution.js
Normal file
115
4kyu/es5_generators_i/solution.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
function generator(sequencer) {
|
||||
return sequencer.apply(
|
||||
null,
|
||||
[]
|
||||
.slice
|
||||
.call(arguments)
|
||||
.slice(1)
|
||||
);
|
||||
}
|
||||
|
||||
function dummySeq() {
|
||||
this.next = function() {
|
||||
return "dummy";
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function factorialSeq() {
|
||||
this.n = 1;
|
||||
this.i = 0;
|
||||
|
||||
this.next = function() {
|
||||
const value = this.n;
|
||||
|
||||
this.i++;
|
||||
this.n *= this.i;
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function fibonacciSeq() {
|
||||
this.prev = 0;
|
||||
this.current = 1;
|
||||
|
||||
this.next = function() {
|
||||
const value = this.current;
|
||||
|
||||
const newValue = this.prev + this.current;
|
||||
this.prev = this.current;
|
||||
this.current= newValue;
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function rangeSeq(start, step) {
|
||||
this.value = start;
|
||||
this.step = step;
|
||||
|
||||
this.next = function() {
|
||||
const oldValue = this.value;
|
||||
this.value += this.step;
|
||||
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function primeSeq() {
|
||||
const isPrime = function(n) {
|
||||
const top = Math.floor(Math.sqrt(n));
|
||||
for (let i = 2; i <= top; i++) {
|
||||
if (n % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const nextPrime = function(n) {
|
||||
n++;
|
||||
while (!isPrime(n)) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
this.p = 1;
|
||||
|
||||
this.next = function() {
|
||||
this.p = nextPrime(this.p);
|
||||
|
||||
return this.p;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function partialSumSeq() {
|
||||
this.values = arguments;
|
||||
this.length = arguments.length;
|
||||
this.runningSum = 0;
|
||||
this.i = 0;
|
||||
|
||||
this.next = function() {
|
||||
if (this.i >= this.length) {
|
||||
throw new RangeError("All input was processed!");
|
||||
}
|
||||
|
||||
this.runningSum += this.values[this.i++];
|
||||
|
||||
return this.runningSum;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
39
4kyu/human_readable_duration_format/solution.cs
Normal file
39
4kyu/human_readable_duration_format/solution.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class HumanTimeFormat{
|
||||
private static Dictionary<string, int> conversions = new Dictionary<string, int>() {
|
||||
{"year", 31536000},
|
||||
{"day", 86400},
|
||||
{"hour", 3600},
|
||||
{"minute", 60},
|
||||
{"second", 1}
|
||||
};
|
||||
|
||||
public static string formatDuration(int seconds){
|
||||
if (seconds == 0) return "now";
|
||||
|
||||
var results = new List<string>();
|
||||
foreach (var pair in conversions) {
|
||||
var units = seconds / pair.Value;
|
||||
seconds %= pair.Value;
|
||||
if (units > 0) {
|
||||
var part = $"{units} {pair.Key}";
|
||||
if (units > 1) {
|
||||
part += "s";
|
||||
}
|
||||
results.Add(part);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.Count == 1) return results[0];
|
||||
else {
|
||||
var last = results.Last();
|
||||
results.Remove(last);
|
||||
|
||||
var result = String.Join(", ", results);
|
||||
return result + " and " + last;
|
||||
}
|
||||
}
|
||||
}
|
15
4kyu/magnet_particules_in_boxes/solution.cs
Normal file
15
4kyu/magnet_particules_in_boxes/solution.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
public class Magnets
|
||||
{
|
||||
public static double Doubles(int maxk, int maxn)
|
||||
{
|
||||
double val = 0;
|
||||
|
||||
for (int k = 1; k <= maxk; k++)
|
||||
for (int n = 1; n <= maxn; n++)
|
||||
val += 1 / (k * Math.Pow(n + 1, 2 * k));
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
44
4kyu/matrix_determinant/solution.cpp
Normal file
44
4kyu/matrix_determinant/solution.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<vector<long long>> transform(vector<vector<long long>> m, int row,
|
||||
int col) {
|
||||
vector<vector<long long>> result;
|
||||
|
||||
for (int i = 0; i < m.size(); i++) {
|
||||
if (i == row)
|
||||
continue;
|
||||
vector<long long> actual_row;
|
||||
for (int j = 0; j < m[i].size(); j++) {
|
||||
if (j == col)
|
||||
continue;
|
||||
actual_row.push_back(m[i][j]);
|
||||
}
|
||||
result.push_back(actual_row);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
long long determinant(vector<vector<long long>> m) {
|
||||
switch (m.size()) {
|
||||
case 1:
|
||||
return m[0][0];
|
||||
break;
|
||||
case 2:
|
||||
return m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
||||
break;
|
||||
}
|
||||
|
||||
long long result = 0;
|
||||
|
||||
for (int i = 0; i < m.size(); i++) {
|
||||
auto l_m = transform(m, i, 0);
|
||||
result += pow(-1, i + 2) * m[i][0] * determinant(l_m);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
65
4kyu/next_bigger_with_same_digits/solution.cs
Normal file
65
4kyu/next_bigger_with_same_digits/solution.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class Kata {
|
||||
public static List<long> ExtractDigits(long n) {
|
||||
var result = new List<long>();
|
||||
|
||||
while (n > 0) {
|
||||
result.Add(n % 10);
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
result.Reverse();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool NextPermutation(List<long> digits) {
|
||||
// foreach (var digit in digits) Console.Write($"{digit} ");
|
||||
// Console.WriteLine();
|
||||
|
||||
var k = -1;
|
||||
|
||||
for (var i = 0; i < digits.Count - 1; i++) {
|
||||
if (digits[i] < digits[i + 1])
|
||||
k = i;
|
||||
}
|
||||
if (k == -1) return false;
|
||||
|
||||
var l = k;
|
||||
for (var i = 0; i < digits.Count; i++)
|
||||
if (digits[k] < digits[i]) l = i;
|
||||
if (l == k) return false;
|
||||
|
||||
var tmp = digits[k];
|
||||
digits[k] = digits[l];
|
||||
digits[l] = tmp;
|
||||
|
||||
// foreach (var digit in digits) Console.Write($"{digit} ");
|
||||
// Console.WriteLine();
|
||||
|
||||
digits.Reverse(k + 1, digits.Count - k - 1);
|
||||
|
||||
// foreach (var digit in digits) Console.Write($"{digit} ");
|
||||
// Console.WriteLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static long NextBiggerNumber(long n) {
|
||||
if (n < 10) return -1;
|
||||
|
||||
var digits = ExtractDigits(n);
|
||||
if (!NextPermutation(digits)) {
|
||||
return -1;
|
||||
} else {
|
||||
var result = 0l;
|
||||
foreach (var digit in digits) {
|
||||
result *= 10;
|
||||
result += digit;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
47
4kyu/permutations/solution.cpp
Normal file
47
4kyu/permutations/solution.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <typename T> bool nextPermutation(std::vector<T> &vec) {
|
||||
// Find non-increasing suffix
|
||||
if (vec.empty())
|
||||
return false;
|
||||
typename std::vector<T>::iterator i = vec.end() - 1;
|
||||
while (i > vec.begin() && *(i - 1) >= *i)
|
||||
--i;
|
||||
if (i == vec.begin())
|
||||
return false;
|
||||
|
||||
// Find successor to pivot
|
||||
typename std::vector<T>::iterator j = vec.end() - 1;
|
||||
while (*j <= *(i - 1))
|
||||
--j;
|
||||
std::iter_swap(i - 1, j);
|
||||
|
||||
// Reverse suffix
|
||||
std::reverse(i, vec.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> permutations(std::string s) {
|
||||
std::set<std::string> strings;
|
||||
std::vector<std::string> result;
|
||||
std::vector<char> s_vec;
|
||||
|
||||
// copy string into vector
|
||||
|
||||
for (auto ch = s.begin(); ch != s.end(); ch++) {
|
||||
s_vec.push_back(*ch);
|
||||
}
|
||||
|
||||
// do the magic
|
||||
std::sort(s_vec.begin(), s_vec.end());
|
||||
do {
|
||||
strings.insert(std::string(s_vec.begin(), s_vec.end()));
|
||||
} while (nextPermutation(s_vec));
|
||||
|
||||
std::copy(strings.begin(), strings.end(), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
24
4kyu/priori_incantatem/solution.js
Normal file
24
4kyu/priori_incantatem/solution.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
class Wand {
|
||||
constructor(spells) {
|
||||
this.history = [];
|
||||
Object.assign(this, spells);
|
||||
|
||||
return new Proxy(this, {
|
||||
get: (target, property) => {
|
||||
const val = target[property];
|
||||
if (typeof val === 'function') {
|
||||
target.history.unshift(property);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prioriIncantatem() {
|
||||
return this.history.slice(1, MAX_PRIOR_SPELLS + 1);
|
||||
}
|
||||
|
||||
deletrius() {
|
||||
this.history = ['deletrius'];
|
||||
}
|
||||
}
|
19
4kyu/pyramid_slide_down/solution.cs
Normal file
19
4kyu/pyramid_slide_down/solution.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
public class PyramidSlideDown
|
||||
{
|
||||
public static int LongestSlideDown(int[][] pyramid)
|
||||
{
|
||||
for (var i = pyramid.GetLength(0) - 2; i >= 0; i--) {
|
||||
for (var j = 0; j <= i; j++) {
|
||||
if (pyramid[i + 1][j] > pyramid[i + 1][j + 1]) {
|
||||
pyramid[i][j] += pyramid[i + 1][j];
|
||||
} else {
|
||||
pyramid[i][j] += pyramid[i + 1][j + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pyramid[0][0];
|
||||
}
|
||||
}
|
28
4kyu/remove_zeros/solution.js
Normal file
28
4kyu/remove_zeros/solution.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
function swap(array, i, j) {
|
||||
let temporary = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temporary;
|
||||
}
|
||||
|
||||
function removeZeros(array) {
|
||||
// Sort "array" so that all elements with the value of zero are moved to the
|
||||
// end of the array, while the other elements maintain order.
|
||||
// [0, 1, 2, 0, 3] --> [1, 2, 3, 0, 0]
|
||||
// Zero elements also maintain order in which they occurred.
|
||||
// [0, "0", 1, 2, 3] --> [1, 2, 3, 0, "0"]
|
||||
|
||||
// Do not use any temporary arrays or objects. Additionally, you're not able
|
||||
// to use any Array or Object prototype methods such as .shift(), .push(), etc
|
||||
|
||||
// the correctly sorted array should be returned.
|
||||
|
||||
for (let i = array.length - 2; i > -1; i--) {
|
||||
if (array[i] === 0 || array[i] === '0') {
|
||||
for (let j = i; j < array.length - 1 && array[j + 1] !== 0 && array[j + 1] !== '0'; j++) {
|
||||
swap(array, j, j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
69
4kyu/route_calculator/solution.ts
Normal file
69
4kyu/route_calculator/solution.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
class Expression {
|
||||
private static readonly INVALID_REQUEST: string = "400: Bad request";
|
||||
|
||||
value: string;
|
||||
|
||||
l: Expression | null = null;
|
||||
r: Expression | null = null;
|
||||
|
||||
private splitBy(operation: string): boolean {
|
||||
let splitOperands = this.value.split(operation);
|
||||
if (splitOperands.length < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.value = operation;
|
||||
this.r = new Expression(splitOperands.pop());
|
||||
this.l = new Expression(splitOperands.join(operation));
|
||||
return true;
|
||||
}
|
||||
|
||||
constructor(expr: string) {
|
||||
this.value = expr;
|
||||
|
||||
for (let operation of "+-*$") {
|
||||
if (this.splitBy(operation)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public evaluate(): (number | string) {
|
||||
if (this.l === null && this.r === null) {
|
||||
// process constants
|
||||
if (![...this.value].every(c => "0123456789.".includes(c))) {
|
||||
return Expression.INVALID_REQUEST;
|
||||
}
|
||||
|
||||
const val = Number.parseFloat(this.value);
|
||||
return val;
|
||||
}
|
||||
|
||||
if (this.l === null || this.r === null || !("+-$*".includes(this.value))) {
|
||||
return Expression.INVALID_REQUEST;
|
||||
}
|
||||
|
||||
const left = this.l.evaluate();
|
||||
const right = this.r.evaluate();
|
||||
|
||||
if (typeof left !== "number" || typeof right !== "number") {
|
||||
return Expression.INVALID_REQUEST;
|
||||
}
|
||||
|
||||
let operation = null;
|
||||
switch (this.value) {
|
||||
case "+":
|
||||
return left + right;
|
||||
case "-":
|
||||
return left - right;
|
||||
case "$":
|
||||
return left / right;
|
||||
case "*":
|
||||
return left * right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const calculate = (sum: string): (number | string) => {
|
||||
return new Expression(sum).evaluate();
|
||||
}
|
57
4kyu/simplistic_tcp_fsm/solution.cs
Normal file
57
4kyu/simplistic_tcp_fsm/solution.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||