Exercism #

My exercism profile: c6p

acronym #

Convert a phrase to its acronym. - view

import re


def abbreviate(words):
    """Abbreviates words

    First alphabetic character succeeding nonalphabetic characters is captured,
    then uppercased.
    """
    return re.sub(r'[^A-Za-z]*([A-Za-z])[A-Za-z\']*', r'\1', words).upper()

all-your-base #

Convert a number, represented as a sequence of digits in one base, to any other base. - view

export function convert(arr, from, to) {
  if (!Number.isInteger(from) || from < 2)
    throw Error('Wrong input base')
  if (!Number.isInteger(to) || to < 2)
    throw Error('Wrong output base')
  else if (arr.length === 0
    || (arr[0] === 0 && arr.length !== 1)
    || arr.some(x => x < 0 || x >= from))
    throw Error('Input has wrong format')

  let base10 = arr.reduce((acc, n) => acc * from + n, 0)
  if (base10 === 0) return arr

  const exp = Math.floor(Math.log(base10) / Math.log(to))
  return [...Array(exp + 1).keys()].reduceRight(({ arr, n }, e) => {
    const pow = to ** e
    return { arr: [...arr, Math.floor(n / pow)], n: n % pow }
  }, { arr: [], n: base10 }).arr
}

allergies #

Given a person’s allergy score, determine whether or not they’re allergic to a given item, and their full list of allergies. - view

class Allergies(object):
    allergens = ['eggs', 'peanuts', 'shellfish', 'strawberries',
                 'tomatoes', 'chocolate', 'pollen', 'cats']

    def __init__(self, score):
        self.lst = [Allergies.allergens[i]
                    for i in range(8) if (score >> i) & 1]

    def allergic_to(self, item):
        return item in self.lst

anagram #

Given a word and a list of possible anagrams, select the correct sublist. - view

from collections import Counter


def find_anagrams(word, candidates):
    word = word.lower()
    counter = Counter(word)

    def is_anagram(candidate):
        candidate = candidate.lower()
        if word == candidate:
            return False
        return counter == Counter(candidate)

    return [c for c in candidates if is_anagram(c)]

An anagram is a rearrangement of letters to form a new word. - view

use std::collections::HashSet;
extern crate itertools;
use itertools::Itertools;

fn chars_lowercase(word: &str) -> impl Iterator<Item = String> + Clone + '_ {
    word.chars().map(|c| c.to_lowercase().to_string())
}

fn anagram_for(word: &str, possible: &str) -> bool {
    let (w, p) = (chars_lowercase(word), chars_lowercase(possible));
    w.clone().ne(p.clone()) && w.sorted().eq(p.sorted())
}

pub fn anagrams_for<'a>(word: &str, possible_anagrams: &[&'a str]) -> HashSet<&'a str> {
    possible_anagrams.iter().filter(|p| anagram_for(word, p)).cloned().collect()
}

armstrong-numbers #

An Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits. - view

export function validate(input) {
  return [...input.toString()]
    .reduce((sum, digit, _, arr) =>
      sum + digit ** arr.length, 0) === input
}

An Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits. - view

def is_armstrong(number):
    digits = str(number)
    l = len(digits)
    return number == sum((int(d)**l for d in digits))

An Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits. - view

pub fn is_armstrong_number(num: u32) -> bool {
  let digits = num.to_string();
  let exp = digits.len() as u32;
  digits
    .chars()
    .map(|x| x.to_digit(10).unwrap().pow(exp))
    .sum::<u32>() == num
}

atbash-cipher #

Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East. - view

const A: u8 = b'a';
const Z: u8 = b'z';
const SEP_LEN: usize = 5;

fn invert_and_lowercase_letters(string: &str) -> impl Iterator<Item = char> + '_ {
    string.chars().filter_map(|c| match c {
        '0'..='9' => Some(c),
        'a'..='z' => Some((Z - (c as u8) + A) as char),
        'A'..='Z' => Some((Z - (c.to_ascii_lowercase() as u8) + A) as char),
        _ => None,
    })
}

/// "Encipher" with the Atbash cipher.
pub fn encode(plain: &str) -> String {
    invert_and_lowercase_letters(plain)
        .scan(0, |sep_len, c| match *sep_len {
            SEP_LEN => { *sep_len = 1;  Some(vec![' ', c]) }
            _ =>       { *sep_len += 1; Some(vec![c]) }
        })
        .flatten()
        .collect()
}

/// "Decipher" with the Atbash cipher.
pub fn decode(cipher: &str) -> String {
    invert_and_lowercase_letters(cipher).collect()
}

bank-account #

Simulate a bank account supporting opening/closing, withdrawals, and deposits - view

from threading import Lock


def with_lock(func):
    LOCK = '_lock'

    def wrapped(self, *args):
        if not hasattr(self, LOCK):
            setattr(self, LOCK, Lock())
        with getattr(self, LOCK):
            return func(self, *args)
    return wrapped


def is_open(_func=None, opened=True):
    def check_open(func):
        def wrapped(self, *args):
            if (self.balance is None) ^ (not opened):
                raise ValueError(
                    f"Account is not {'opened' if opened else 'closed'}!")
            return func(self, *args)
        return wrapped

    if _func is None:
        return check_open
    else:
        return check_open(_func)


class BankAccount(object):
    def __init__(self):
        self.balance = None

    @is_open
    def get_balance(self):
        return self.balance

    @is_open(opened=False)
    @with_lock
    def open(self):
        self.balance = 0

    @is_open
    @with_lock
    def deposit(self, amount):
        if amount < 0:
            raise ValueError("Cannot deposit negative!")
        self.balance += amount

    @is_open
    @with_lock
    def withdraw(self, amount):
        if amount < 0 or amount > self.balance:
            raise ValueError("Cannot withdraw negative or more than balance!")
        self.balance -= amount

    @is_open
    @with_lock
    def close(self):
        self.balance = None

beer-song #

Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall. - view

pub fn verse(n: i32) -> String {
  match n {
    0 => "No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.
"
      .to_owned(),
    1 => "1 bottle of beer on the wall, 1 bottle of beer.
Take it down and pass it around, no more bottles of beer on the wall.
"
      .to_owned(),
    2 => "2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
"
      .to_owned(),
    n => format!(
      "{} bottles of beer on the wall, {} bottles of beer.
Take one down and pass it around, {} bottles of beer on the wall.
",
      n,
      n,
      n - 1
    ),
  }
}

pub fn sing(start: i32, end: i32) -> String {
  let mut verses = String::new();
  for i in (end..=start).rev() {
    verses += &verse(i);
    if i != end {
      verses += "\n";
    }
  }
  verses
}

bob #

Bob is a lackadaisical teenager. In conversation, his responses are very limited. - view

export const hey = (message) => {
  message = message.trim()
  const isQuestion = message[message.length - 1] === '?'
  const isYelling = message.match(/[A-Z]/) && message === message.toUpperCase()

  if (message === '')
    return 'Fine. Be that way!'
  else {
    if (isYelling)
      return isQuestion
        ? "Calm down, I know what I'm doing!"
        : 'Whoa, chill out!'
    else if (isQuestion)
      return 'Sure.'
  }
  return 'Whatever.'
};

Bob is a lackadaisical teenager. In conversation, his responses are very limited. - view

def response(hey_bob):
    hey_bob = hey_bob.strip()
    if not hey_bob:
        return "Fine. Be that way!"
    is_yell = hey_bob.isupper()
    if hey_bob.endswith('?'):  # is_question
        if is_yell:
            return "Calm down, I know what I'm doing!"
        return "Sure."
    elif is_yell:
        return "Whoa, chill out!"
    return 'Whatever.'

Bob is a lackadaisical teenager. In conversation, his responses are very limited. - view

extern crate regex;
use regex::Regex;

pub fn reply(message: &str) -> &str {
  let special_chars = Regex::new(r"[0-9%@#$(,*^! \t]*").unwrap();
  let ask_question = Regex::new(r"^.*\?\s*$").unwrap();
  let yell = Regex::new(r"^[A-Z]+\s*$").unwrap();
  let yell_question = Regex::new(r"^[A-Z]+\?\s*$").unwrap();
  let address = Regex::new(r"^\s*$").unwrap();

  if address.is_match(message) {
    "Fine. Be that way!"
  } else {
    match &special_chars.replace_all(message, "") {
      m if yell_question.is_match(m) => "Calm down, I know what I'm doing!",
      m if ask_question.is_match(m) => "Sure.",
      m if yell.is_match(m) => "Whoa, chill out!",
      _ => "Whatever.",
    }
  }
}

clock #

Implement a clock that handles times without dates. - view

use modulo::Mod;
use std::fmt;
use num_integer::Integer;

const MINS_PER_HOUR: i32 = 60;
const MINS_PER_DAY: i32 = 24 * MINS_PER_HOUR;

#[derive(PartialEq, Debug)]
pub struct Clock {
    hours: i32,
    minutes: i32,
}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self { Clock { hours, minutes }.add_minutes(0) }

    pub fn add_minutes(&self, minutes: i32) -> Self {
        let total_minutes = (self.hours * MINS_PER_HOUR + self.minutes + minutes).modulo(MINS_PER_DAY);
        let (hours, minutes) = total_minutes.div_rem(&MINS_PER_HOUR);
        Clock { hours, minutes }
    }
}

impl fmt::Display for Clock {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:02}:{:02}", self.hours, self.minutes)
    }
}

collatz-conjecture #

The Collatz Conjecture or 3x+1 problem can be summarized as follows: - view

pub fn collatz(n: u64) -> Option<u64> {
  match n {
    0 => None, // 1 is not reachable
    _ => (0..)
      .try_fold(n, |i, step| match i {
        1 => Err(step), // reached 1 at step
        _ => Ok(match i % 2 {
          0 => i / 2,
          _ => 3 * i + 1,
        }),
      })
      .err(),
  }
}

darts #

Write a function that returns the earned points in a single toss of a Darts game. - view

const targets = [1,  5**2, 10**2],
      points  = [10, 5,    1]

export function solve(x, y) {
  const r2 = x ** 2 + y ** 2
  return points[targets.findIndex(t => t >= r2)] || 0
}

difference-of-squares #

Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. - view

def square_of_sum(number):
    return sum(range(number+1)) ** 2


def sum_of_squares(number):
    return sum(i**2 for i in range(number+1))


def difference_of_squares(number):
    return square_of_sum(number) - sum_of_squares(number)

Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. - view

pub fn square_of_sum(n: u32) -> u32 {
  (1..=n).fold(0, |acc, x| acc + x).pow(2)
}

pub fn sum_of_squares(n: u32) -> u32 {
  (1..=n).fold(0, |acc, x| acc + x.pow(2))
}

pub fn difference(n: u32) -> u32 {
  square_of_sum(n) - sum_of_squares(n)
}

diffie-hellman #

Diffie-Hellman key exchange. - view

extern crate num;
extern crate rand;
use num::bigint::BigUint;
use num::traits::cast::ToPrimitive;
use rand::Rng;

pub fn private_key(p: u64) -> u64 {
  rand::thread_rng().gen_range(2, p)
}

pub fn public_key(p: u64, g: u64, a: u64) -> u64 {
  BigUint::from(g)
    .modpow(&BigUint::from(a), &BigUint::from(p))
    .to_u64()
    .unwrap()
}

pub fn secret(p: u64, b_pub: u64, a: u64) -> u64 {
  public_key(p, b_pub, a)
}

dnd-character #

For a game of [Dungeons & Dragons][DND], each player starts by generating a - view

from random import randint

ABILITIES = ['strength', 'dexterity', 'constitution',
             'intelligence', 'wisdom', 'charisma']


def modifier(constitution):
    return (constitution - 10) // 2


class Character:

    def __init__(self):
        for ability in ABILITIES:
            setattr(self, ability, self.ability())
        self.hitpoints = 10 + modifier(self.constitution)

    def ability(self):
        return sum(sorted([randint(1, 6) for _ in range(4)])[1:])

error-handling #

Implement various kinds of error handling and resource management. - view

def handle_error_by_throwing_exception():
    raise Exception('Error message')


def handle_error_by_returning_none(variable):
    try:
        return int(variable)
    except ValueError:
        return None


def handle_error_by_returning_tuple(string):
    result = handle_error_by_returning_none(string)
    return (result is not None, result)


def filelike_objects_are_closed_on_exception(file_object):
    with file_object as f:
        f.do_something()

gigasecond #

Given a moment, determine the moment that would be after a gigasecond - view

const GIGASECOND = 1e12

export const gigasecond = (date) => {
  return new Date(date.getTime() + GIGASECOND)
};

Calculate the moment when someone has lived for 10^9 seconds. - view

from datetime import timedelta
GIGASECOND = timedelta(seconds=10**9)


def add_gigasecond(moment):
    return moment + GIGASECOND

Calculate the moment when someone has lived for 10^9 seconds. - view

extern crate chrono;
use chrono::{DateTime, TimeZone, Utc};

// Returns a Utc DateTime one billion seconds after start.
pub fn after(start: DateTime<Utc>) -> DateTime<Utc> {
  return Utc.timestamp(start.timestamp() + 1_000_000_000, 0);
}

grains #

Calculate the number of grains of wheat on a chessboard given that the number - view

def on_square(n):
    if n < 1 or n > 64:
        raise ValueError('Not an integer in [1-64]')
    return 2 ** (n-1)


def total_after(n):
    if n < 1 or n > 64:
        raise ValueError('Not an integer in [1-64]')
    return 2 ** n - 1

Calculate the number of grains of wheat on a chessboard given that the number - view

pub fn square(s: u32) -> u64 {
  match s {
    1...64 => 2u64.pow(s - 1),
    _ => panic!("Square must be between 1 and 64"),
  }
}

pub fn total() -> u64 {
  (1..=64).map(|s| square(s)).sum()
}

hamming #

Calculate the Hamming difference between two DNA strands. - view

def distance(strand_a, strand_b):
    if len(strand_a) != len(strand_b):
        raise ValueError('not of equal length')
    return len([1 for a, b in zip(strand_a, strand_b) if a != b])

hello-world #

The classical introductory exercise. Just say “Hello, World!”. - view

export const hello = () => {
  return "Hello, World!"
};

The classical introductory exercise. Just say “Hello, World!”. - view

def hello():
    return 'Hello, World!'

The classical introductory exercise. Just say “Hello, World!”. - view

pub fn hello() -> &'static str {
    "Hello, World!"
}

high-scores #

Manage a game player’s High Score list. - view

class HighScores(object):
    def __init__(self, scores):
        self.scores = scores

    def latest(self):
        return self.scores[-1]

    def personal_best(self):
        return max(self.scores)

    def personal_top(self):
        return sorted(self.scores, reverse=True)[:3]

    def report(self):
        latest, best = self.latest(), self.personal_best()
        short_of = f" {best - latest} short of " if best > latest else " "
        return f"Your latest score was {latest}. That's{short_of}your personal best!"

isbn-verifier #

The ISBN-10 verification process is used to validate book identification - view

import re
from operator import mul


isbn_pattern = re.compile(
    r'^(\d)-?(\d)(\d)(\d)-?(\d)(\d)(\d)(\d)(\d)-?([\dX])$')


def is_valid(isbn):
    return sum(map(mul, (int(i) for i in isbn), range(10, 0, -1))) % 11 == 0


def verify(isbn):
    m = isbn_pattern.match(isbn)
    if m:
        x = [i for i in m.group(*range(1, 11))]
        if x[-1] == 'X':
            x[-1] = 10
        return is_valid(x)
    return False

isogram #

Determine if a word or phrase is an isogram. - view

def is_isogram(string):
    letters = set()
    is_alpha = str.isalpha
    add = letters.add
    for c in string.lower():
        if not is_alpha(c): continue
        if c in letters: return False
        add(c)
    return True

Determine if a word or phrase is an isogram. - view

use itertools::sorted;

pub fn check(candidate: &str) -> bool {
  sorted(candidate.to_ascii_lowercase().as_bytes())
    .filter(|x| match **x as char {
      ' ' | '-' => false,
      _ => true,
    })
    .try_fold(
      0 as u8,
      |prev, &curr| {
        if prev == curr {
          Err(curr)
        } else {
          Ok(curr)
        }
      },
    )
    .is_ok()
}

kindergarten-garden #

Given a diagram, determine which plants each child in the kindergarten class is - view

from numpy import array

STUDENTS = ["Alice", "Bob", "Charlie", "David", "Eve", "Fred",
            "Ginny", "Harriet", "Ileana", "Joseph", "Kincaid", "Larry"]
PLANTS = {"G": "Grass", "C": "Clover", "R": "Radishes", "V": "Violets"}


class Garden:
    def __init__(self, diagram, students=STUDENTS):
        self.students = sorted(students)
        self.diagram = array([list(row) for row in diagram.split('\n')])

    def plants(self, student):
        i = self.students.index(student) * 2
        return [PLANTS[p] for p in self.diagram[:, i:i + 2].flatten()]

largest-series-product #

Given a string of digits, calculate the largest product for a contiguous - view

from functools import reduce
from operator import mul


def product(series):
    return reduce(lambda acc, i: acc*int(i), series, 1)


def largest_product(series, size):
    if size < 0:
        raise ValueError("Span should be positive!")
    length = len(series)
    return max(product(series[i:i+size]) for i in range(length-size+1))

leap #

Given a year, report if it is a leap year. - view

export function isLeap(year) {
  return year % 4 === 0
    && (year % 100 !== 0 || year % 400 === 0)
}

Given a year, report if it is a leap year. - view

def is_leap_year(year):
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

Given a year, report if it is a leap year. - view

pub fn is_leap_year(year: i32) -> bool {
  return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
}

linked-list #

Implement a doubly linked list. - view

class Node {
  constructor({ val = null, prev = null, next = null }) {
    Object.assign(this, { val, prev, next })
  }
}

export class LinkedList {
  constructor() {
    this.first = null
    this.last = this.first
  }

  push(val, last = 'last', prev = 'prev', next = 'next') {
    if (this[last] === null)
      this.first = this.last = new Node({ val })
    else {
      let node = { val, [prev]: this[last] }
      this[last] = new Node(node)
      node[prev][next] = this[last]
    }
  }
  unshift(val) { this.push(val, 'first', 'next', 'prev') }

  pop(first = 'first', last = 'last', prev = 'prev', next = 'next') {
    const val = this[last].val
    this[last] = this[last][prev]
    if (this[last] === null)
      this[first] = this[last]
    else
      this[last][next] = null
    return val
  }
  shift() { return this.pop('last', 'first', 'next', 'prev') }

  delete(val) {
    let item = this.first
    while (item) {
      if (item.val === val) {
        if (item.next) item.next.prev = item.prev
        else this.last = item.prev
        if (item.prev) item.prev.next = item.next
        else this.first = item.next
        return
      }
      item = item.next
    }
  }

  count() {
    let [c, item] = [0, this.first]
    while (item) {
      c++
      item = item.next
    }
    return c
  }
}

matching-brackets #

Given a string containing brackets [], braces {}, parentheses (), - view

fn close_bracket(c: char) -> char {
    match c {
        '{' => '}',
        '[' => ']',
        '(' => ')',
        _ => panic!("No matching close bracket!"),
    }
}

pub fn brackets_are_balanced(string: &str) -> bool {
    let mut unbalanced = Vec::<char>::new();
    for c in string.chars() {
        match c {
            '{' | '[' | '(' => unbalanced.push(close_bracket(c)),
            '}' | ']' | ')' => {
                if unbalanced.pop() != Some(c) {
                    return false;
                }
            }
            _ => (),
        }
    }
    unbalanced.is_empty()
}

matrix #

Given a string representing a matrix of numbers, return the rows and columns of - view

export class Matrix {
  constructor(matrix) {
    this.m = matrix.split('\n').map(row => row.split(' ').map(col => Number(col)))
  }

  get rows() { return this.m }

  get columns() {
    return this.t = this.t || this.m[0].map((_, i) => this.m.map(row => row[i]))
  }
}

Given a string representing a matrix of numbers, return the rows and columns of - view

class Matrix():
    def __init__(self, matrix_string):
        self.rows = [[int(num) for num in line.split(' ')]
                     for line in matrix_string.split('\n')]

    def row(self, index):
        return self.rows[index-1]

    def column(self, index):
        return [row[index-1] for row in self.rows]

meetup #

Calculate the date of meetups. - view

from calendar import monthrange, day_name
from datetime import date


class MeetupDayException(Exception):
    pass


def meetup(year, month, week, day_of_week):
    weekday = dict(zip(day_name, range(7)))[day_of_week]
    firstday, max_days = monthrange(year, month)
    days = range((weekday - firstday) % 7 + 1, max_days + 1, 7)

    if week == "teenth":
        day = next(i for i in days if i >= 13 and i <= 19)
    elif week == 'last':
        day = days[-1]
    else:   # week in ["1st", "2nd", "3rd", "4th", "5th"]:
        try:
            day = days[int(week[0]) - 1]
        except:
            raise MeetupDayException("No {0} {1}!".format(week, day_of_week))

    return date(year, month, day)

nth-prime #

Given a number n, determine what the nth prime is. - view

pub fn nth(n: usize) -> u32 {
  fn is_prime(x: u32, factors: &Vec<u32>) -> bool {
    return !factors.iter().any(|&i| x % i == 0);
  }
  const FIRST_PRIME: u32 = 2;
  let mut primes = vec![FIRST_PRIME];
  let mut num = FIRST_PRIME;
  while primes.len() <= n {
    num += 1;
    if is_prime(num, &primes) {
      primes.push(num);
    }
  }
  primes[n]
}

pangram #

Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, - view

const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'.split('')

export const isPangram = (sentence) => {
  let s = sentence.toLowerCase()
  return ALPHABET.every(c => s.includes(c))
}

Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, - view

def is_pangram(sentence):
    diff = ord('z') - ord('a')
    try:
        pangram = sorted(set(sentence.lower()))
        return diff == pangram.index('z') - pangram.index('a')
    except:
        return False

pascals-triangle #

Compute Pascal’s triangle up to a given number of rows. - view

export class Triangle {
  constructor(n) {
    if (n < 1) throw new Error("Minimum rows for Pascals Triangle is 1")

    this.tri = [...Array(n)].map(_ => [1])  // init n rows

    for (let i = 1; i < this.tri.length; i++) {
      this.tri[i] = [...Array(i + 1)].map((_, j) =>
        j === 0 || j === i
          ? 1 // first and last columns are 1
          : this.tri[i - 1][j - 1] + this.tri[i - 1][j])
    }
  }

  get lastRow() { return this.tri[this.tri.length - 1] }

  get rows() { return this.tri }
}

perfect-numbers #

Determine if a number is perfect, abundant, or deficient based on - view

def factors(number):
    if number == 1:
        return
    elif number < 1:
        raise ValueError("Not a positive integer!")

    yield 1
    for div in range(2, 1+int(number**0.5)):
        quo, rem = divmod(number, div)
        if not rem:
            yield div
            if quo is not div:
                yield quo


def classify(number):
    diff = sum(factors(number)) - number
    return "perfect" if diff == 0 else "abundant" if diff > 0 else "deficient"

phone-number #

Clean up user-entered phone numbers so that they can be sent SMS messages. - view

import re


class Phone(object):
    _pattern = re.compile(r'''
        \+?1?               # country code
        \s*?                # optional spaces
        \(?([2-9]\d{2})\)?  # area code \1
        [ .-]*?             # optional seperators
        ([2-9]\d{2})        # subscriber code \2
        [ .-]*?             # optional seperators
        (\d+).*             # subscriber number \3
    ''', re.VERBOSE)

    def __init__(self, phone_number):
        self.number = self._pattern.sub(r'\1\2\3', phone_number)
        if len(self.number) == 10:
            self.area_code = self.number[:3]
        else:
            raise ValueError("Invalid Phone Number!")

    def pretty(self):
        return f'({self.area_code}) {self.number[3:6]}-{self.number[6:]}'

prime-factors #

Compute the prime factors of a given natural number. - view

def prime_factors(number):
    factors, d = [], 2
    while number > 1:
        while True:
            q, r = divmod(number, d)
            if r:
                d += 1 if d == 2 else 2  # skip evens
            else:
                factors.append(d)
                number = q
                break
    return factors

Compute the prime factors of a given natural number. - view

pub fn factors(mut n: u64) -> Vec<u64> {
  let mut factors = Vec::new();
  while n > 1 {
    let factor = (2..=n).find(|x| n % x == 0).unwrap();
    factors.push(factor);
    n /= factor
  }
  factors
}

protein-translation #

Translate RNA sequences into proteins. - view

const codons = (() => {
  let AUG, UUU, UUC, UUA, UUG, UCU, UCC, UCA, UCG, UAU, UAC, UGU, UGC, UGG, UAA, UAG, UGA
  AUG = 'Methionine'
  UUU = UUC = 'Phenylalanine'
  UUA = UUG = 'Leucine'
  UCU = UCC = UCA = UCG = 'Serine'
  UAU = UAC = 'Tyrosine'
  UGU = UGC = 'Cysteine'
  UGG = 'Tryptophan'
  UAA = UAG = UGA = 'STOP'
  return Object.freeze({ AUG, UUU, UUC, UUA, UUG, UCU, UCC, UCA, UCG, UAU, UAC, UGU, UGC, UGG, UAA, UAG, UGA })
})()

export function translate(rna = '') {
  let proteins = []
  for (let i = 0; i < rna.length; i += 3) {
    const protein = codons[rna.slice(i, i + 3)]
    if (protein === undefined) throw new Error('Invalid codon')
    if (protein === 'STOP') break
    proteins.push(protein)
  }
  return proteins
}

Translate RNA sequences into proteins. - view

from itertools import takewhile

codons = {
    'AUG': "Methionine",
    'UUU': 'Phenylalanine', 'UUC': 'Phenylalanine',
    'UUA': 'Leucine', 'UUG': 'Leucine',
    'UCU': 'Serine', 'UCC': 'Serine', 'UCA': 'Serine', 'UCG': 'Serine',
    'UAU': 'Tyrosine', 'UAC': 'Tyrosine',
    'UGU': 'Cysteine', 'UGC': 'Cysteine',
    'UGG': 'Tryptophan',
    'UAA': 'STOP', 'UAG': 'STOP', 'UGA': 'STOP'
}


def proteins(strand):
    codon_gen = (strand[i:i+3] for i in range(0, len(strand), 3))
    protein_gen = (codons[codon] for codon in codon_gen)
    return list(takewhile(lambda p: p != 'STOP', protein_gen))

proverb #

For want of a horseshoe nail, a kingdom was lost, or so the saying goes. - view

pub fn build_proverb(list: Vec<&str>) -> String {
  match list.as_slice() {
    [] => "".to_owned(),
    _ => list
      .iter()
      .zip(list.iter().skip(1))
      .map(|(a, b)| format!("For want of a {} the {} was lost.", a, b))
      .chain(std::iter::once(format!(
        "And all for the want of a {}.",
        list[0]
      )))
      .collect::<Vec<String>>()
      .join("\n"),
  }
}

pythagorean-triplet #

A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for - view

from math import sqrt


def triplets_with_sum(number):
    return set(gen_triplets(number))


def gen_triplets(number):
    # limit at a==b
    for a in range(1, 1 + int(number / (2 + sqrt(2)))):
        b_plus_c = number - a
        n = b_plus_c**2 - a**2
        d = b_plus_c * 2
        if n % d == 0:
            b = n // d
            c = b_plus_c - b
            yield (a, b, c) if a < b else (b, a, c)

A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for - view

use rayon::prelude::*;
use std::collections::HashSet;

pub fn find(sum: u32) -> HashSet<[u32; 3]> {
  (1_u32..(sum / 3_u32))
    .into_par_iter()
    .map(|a| {
      let b_plus_c = sum - a;
      (a, b_plus_c, b_plus_c.pow(2) - a.pow(2), b_plus_c * 2)
    })
    .filter(|(_a, _b_plus_c, n, d)| n % d == 0)
    .map(|(a, b_plus_c, n, d)| {
      let b = n / d;
      let c = b_plus_c - b;
      match a < b {
        true => [a, b, c],
        false => [b, a, c],
      }
    })
    .collect::<HashSet<[u32; 3]>>()
}

raindrops #

Convert a number to a string, the contents of which depend on the number’s factors. - view

PL_NG = {3: 'Pling', 5: 'Plang', 7: 'Plong'}


def raindrops(number):
    return ''.join([speak for factor, speak in PL_NG.items()
                    if number % factor == 0]) or str(number)

Convert a number to a string, the contents of which depend on the number’s factors. - view

const PLING: &str = "Pling";
const PLANG: &str = "Plang";
const PLONG: &str = "Plong";

fn factor(x: u32, n: u32) -> bool {
  n % x == 0
}

pub fn raindrops(n: u32) -> String {
  let mut s = String::new();
  if factor(3, n) {
    s += PLING;
  }
  if factor(5, n) {
    s += PLANG;
  }
  if factor(7, n) {
    s += PLONG;
  }
  if s.is_empty() {
    return n.to_string();
  }
  s
}

rational-numbers #

A rational number is defined as the quotient of two integers a and b, called the numerator and denominator, respectively, where b != 0. - view

from __future__ import division


def gcd(a, b):
    if a == 0:
        return b
    return gcd(b % a, a)


class Rational(object):
    def __init__(self, numer, denom):
        d = gcd(numer, denom)
        self.numer = numer / d
        self.denom = denom / d

    def __eq__(self, other):
        return self.numer == other.numer and self.denom == other.denom

    def __repr__(self):
        return '{}/{}'.format(self.numer, self.denom)

    def __add__(self, other):
        return Rational(self.numer * other.denom + other.numer * self.denom, self.denom * other.denom)

    def __sub__(self, other):
        return Rational(self.numer * other.denom - other.numer * self.denom, self.denom * other.denom)

    def __mul__(self, other):
        return Rational(self.numer * other.numer, self.denom * other.denom)

    def __truediv__(self, other):
        return Rational(self.numer * other.denom, self.denom * other.numer)

    def __abs__(self):
        return Rational(abs(self.numer), abs(self.denom))

    def __pow__(self, power):
        numer, denom = (self.denom, self.numer) if power < 0 else (
            self.numer, self.denom)
        power = abs(power)
        return Rational(numer**power, denom**power)

    def __rpow__(self, base):
        return base ** (self.numer / self.denom)

resistor-color #

Resistors have color coded bands, where each color maps to a number. The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. - view

export const COLORS = ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"]

export function colorCode(color) {
  return COLORS.indexOf(color)
}

resistor-color-duo #

If you want to build something using a Raspberry Pi, you’ll probably use resistors. For this exercise, you need to know two things about them: - view

const COLORS = ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"]

export function value(bands) {
  return Number(bands.reduce((val, band) => val + COLORS.indexOf(band), ''))
}

reverse-string #

Reverse a string - view

def reverse(text):
    return text[::-1]

Reverse a string - view

extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

pub fn reverse(input: &str) -> String {
  input.graphemes(true).rev().collect()
}

rna-transcription #

Given a DNA strand, return its RNA complement (per RNA transcription). - view

const COMPLEMENT = { G: 'C', C: 'G', T: 'A', A: 'U' }

export const toRna = (dna) =>
  dna.split('').reduce((rna, c) => rna + (COMPLEMENT[c] || ''), '')

Given a DNA strand, return its RNA complement (per RNA transcription). - view

rna = str.maketrans("GCTA", "CGAU")


def to_rna(dna_strand):
    return dna_strand.translate(rna)

robot-name #

Manage robot factory settings. - view

import random

MOD = (26*10**3, 10**3, 10**2, 10, 1)
MAX = 26**2 * 10**3
A = ord('A')


def name_generator():
    global A, MOD, MAX
    num = random.randint(0, MAX)
    # in AA111 format
    for i in range(5):
        d, num = divmod(num, MOD[i])
        yield chr(A+d) if i < 2 else str(d)
    return


class Robot(object):
    names = set()

    def __init__(self):
        self.reset()

    def reset(self):
        while True:
            name = self.gen_name()
            if name not in self.names:
                self.names.add(name)
                break
        self.name = name

    def gen_name(self):
        return ''.join(name_generator())

roman-numerals #

Write a function to convert from normal numbers to Roman Numerals. - view

const NUMERALS = { 1: 'I', 5: 'V', 10: 'X', 50: 'L', 100: 'C', 500: 'D', 1000: 'M' }

function roman5(n, unit, left, right) {
  return n == 4
    ? `${unit}${right}`
    : `${left}${unit.repeat(n)}`
}
function roman10(n, one, five, ten) {
  const [ONE, FIVE, TEN] = [one, five, ten].map(x => NUMERALS[x])
  return n >= 5
    ? roman5(n % 5, ONE, FIVE, TEN)
    : roman5(n, ONE, '', FIVE)
}

export function toRoman(n) {
  return [1000, 100, 10, 1].reduce((acc, I) => {
    const MAX = 10 * n,
          num = Math.floor(n % (10*I) / I)
    return I <= MAX
      ? acc + roman10(num, I, 5*I, 10*I)
      : acc
  }, '')
}

run-length-encoding #

Implement run-length encoding and decoding. - view

export function encode(txt) {
  return txt.replace(/(.)\1+/g,
    (run) => run.length + run[0])
}

export function decode(txt) {
  return txt.replace(/(\d+)(.)/g,
    (_, run, char) => char.repeat(run))
}

saddle-points #

Detect saddle points in a matrix. - view

def saddle_points(matrix):
    if not matrix:
        return [{}]
    row_length = len(matrix[0])
    if [1 for row in matrix if row_length != len(row)]:
        raise ValueError("Irregular Matrix!")

    col_mins = [min(col) for col in zip(*matrix)]
    return [{"row": r, "column": c}
            for r, row_max in enumerate(map(max, matrix), 1)
            for c, col_min in enumerate(col_mins, 1)
            if row_max == col_min] or [{}]

Detect saddle points in a matrix. - view

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
  let len: usize = if input.len() > 0 { input[0].len() } else { 0 };
  let row_max: Vec<_> = input.iter().filter_map(|v| v.iter().max()).collect();
  let col_min: Vec<_> = (0..len)
    .filter_map(|i| input.iter().flatten().skip(i).step_by(len).min())
    .collect();

  input
    .iter()
    .enumerate()
    .flat_map(|(i, v)| v.iter().enumerate().map(move |(j, v)| (i.to_owned(), j, v)))
    .filter_map(|(i, j, v)| {
      if v >= row_max[i] && v <= col_min[j] {
        Some((i, j))
      } else {
        None
      }
    })
    .collect()
}

say #

Given a number from 0 to 999,999,999,999, spell out that number in English. - view

SAY = {
    0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
    11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen', 19: 'nineteen',
    20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'
 }


def _say_postfix(number, divisor, postfix):
    quo, rem = divmod(number, divisor)
    return f"{_say(quo)} {postfix}" + (f" {_say(rem)}" if rem else '')


def _say(number):
    if number < 20:
        return SAY[number]
    elif number < 100:
        ten, rem = divmod(number, 10)
        return SAY[ten * 10] + (f"-{SAY[rem]}" if rem else '')
    elif number < 1e3:
        return _say_postfix(number, 100, "hundred")

    for divisor, postfix in [(1e3, "thousand"), (1e6, "million"), (1e9, "billion")]:
        if number < 1e3 * divisor:
            return _say_postfix(number, divisor, postfix)


def say(number):
    if number < 0 or number >= 1e12:
        raise ValueError("Out of range")
    else:
        return _say(number)

scrabble-score #

Given a word, compute the scrabble score for that word. - view

from enum import IntEnum


class Score(IntEnum):
    A = E = I = O = U = L = N = R = S = T = 1
    D = G = 2
    B = C = M = P = 3
    F = H = V = W = Y = 4
    K = 5
    J = X = 8
    Q = Z = 10


def score(word):
    return sum(Score[c] for c in word.upper())

series #

Given a string of digits, output all the contiguous substrings of length n in - view

def slices(series, length):
    if length <= 0 or len(series) < length:
        raise ValueError("Invalid length")
    return [series[i:i+length] for i in range(len(series)+1-length)]

Given a string of digits, output all the contiguous substrings of length n in - view

pub fn series(digits: &str, len: usize) -> Vec<String> {
  (0..digits.len().checked_sub(len - 1).unwrap_or(0))
    .map(|i| digits[i..i + len].to_owned())
    .collect()
}

sgf-parsing #

Parsing a Smart Game Format string. - view

import re


class SgfTree(object):
    def __init__(self, properties=None, children=None):
        self.properties = properties or {}
        self.children = children or []

    def __eq__(self, other):
        if not isinstance(other, SgfTree):
            return False
        for k, v in self.properties.items():
            if k not in other.properties:
                return False
            if other.properties[k] != v:
                return False
        for k in other.properties.keys():
            if k not in self.properties:
                return False
        if len(self.children) != len(other.children):
            return False
        for a, b in zip(self.children, other.children):
            if a != b:
                return False
        return True

    def __ne__(self, other):
        return not self == other


# TOKENs
VAR_BEGIN, VAR_END, NEXT_LVL, KEY, VALUE, ELSE = (re.compile(s) for s in [
    r'\(',                  # VAR_BEGIN
    r'\)',                  # VAR_END
    r';',                   # NEXT_LVL
    r'(?<=[];])[A-Z]+',     # KEY
    r'\[(.+?)(?<!\\)\]',    # VALUE \1
    r'[^);]'                # ELSE
])


def escape(s): return s.replace('\n', '\\n')


def unescape(s):
    return s.replace(r'\n', '\n').replace('\t', ' ').replace('\\', '')


def match(pattern, s, pos, action=None):
    m_peek = pattern.match(s, pos)
    if m_peek:
        if action:
            action(m_peek)
        return m_peek.end(), True
    return pos, False


def add_node(parent):
    node = SgfTree()
    if parent:
        parent.children.append(node)
    else:
        parent = node


def parse_key_value(s, parent, pos):
    m = KEY.match(s, pos)
    if not m:
        return pos, False
    pos, key, values = m.end(), m.group(0), []
    while True:
        pos, matched = match(VALUE, s, pos,
                             lambda m: values.append(unescape(m.group(1))))
        if not matched:
            break
    if values:
        parent.properties[key] = values
    else:
        raise ValueError("Error: No delimiter!")
    return pos, True


def parse_variation(s, parent=None, pos=0):
    m = VAR_BEGIN.match(s, pos)
    if not m:
        return m.end(), False, parent
    pos, node = m.end(), parent
    while True:
        pos, matched = match(VAR_END, s, pos)
        if not matched:
            break
        pos, matched = match(NEXT_LVL, s, pos)
        pos, matched = parse_key_value(s, node, pos)
        if matched:
            node = SgfTree()
            if parent:
                parent.children.append(node)
            else:
                parent = node
            continue
        pos, matched, _ = parse_variation(s, node, pos)
        if matched:
            continue
        _, matched = match(ELSE, s, pos)
        if matched:
            raise ValueError("Error!")
    return pos, True, parent


def parse(input_string):
    _, _, root = parse_variation(escape(input_string))
    if not root:
        raise ValueError("No nodes!")
    return root


parse('(;A[\\]b\nc\nd\t\te \n\\]])')

sieve #

Use the Sieve of Eratosthenes to find all the primes from 2 up to a given - view

def primes(limit):
    numbers = list(range(2, limit + 1))
    prime_gen = (n for n in numbers if n)

    while True:
        prime = next(prime_gen, None)
        if not prime:
            break
        for i in range(prime * 2, len(numbers) + 2, prime):
            numbers[i - 2] = 0    # mark multiples of prime

    return [n for n in numbers if n]    # primes

simple-cipher #

Implement a simple shift cipher like Caesar and a more secure substitution cipher. - view

from itertools import cycle
from string import ascii_lowercase
from random import choice

A, Z = ord('a'), ord('z')


def wrap_chr(val):
    return chr((val - A) % (Z - A + 1) + A)


class Cipher(object):
    def __init__(self, key=None):
        self.key = key or ''.join(choice(ascii_lowercase) for _ in range(100))

    def encode(self, text, reverse=False):
        return ''.join(wrap_chr(A - ord(k) + ord(c) if reverse else
                                ord(k) - A + ord(c))
                       for c, k in zip(text, cycle(self.key)))

    def decode(self, text):
        return self.encode(text, reverse=True)


class Caesar(Cipher):
    def __init__(self):
        super().__init__('d')

space-age #

Given an age in seconds, calculate how old someone would be on: - view

const EARTH_YEAR_IN_SECONDS = 31557600
const YEAR_IN_EARTH_YEARS = {
  mercury: 0.2408467,
  venus: 0.61519726,
  earth: 1.0,
  mars: 1.8808158,
  jupiter: 11.862615,
  saturn: 29.447498,
  uranus: 84.016846,
  neptune: 164.79132,
}


export const age = (planet, age_in_seconds) => {
  const year_in_seconds = YEAR_IN_EARTH_YEARS[planet] * EARTH_YEAR_IN_SECONDS
  return Number((age_in_seconds / year_in_seconds).toFixed(2))
}

Given an age in seconds, calculate how old someone would be on: - view

class SpaceAge(object):
    PLANET_ORBITS = [(p, o * 31557600) for p, o in (
        ('earth', 1.0),
        ('mercury', 0.2408467),
        ('venus', 0.61519726),
        ('mars', 1.8808158),
        ('jupiter', 11.862615),
        ('saturn', 29.447498),
        ('uranus', 84.016846),
        ('neptune', 164.79132)
    )]

    def __init__(self, seconds):
        self.seconds = seconds
        for planet, orbit in self.PLANET_ORBITS:
            setattr(self, 'on_' + planet,
                    lambda orbit=orbit: round(self.seconds / orbit, 2))

sum-of-multiples #

Given a number, find the sum of all the unique multiples of particular numbers up to - view

def sum_of_multiples(limit, multiples):
    return sum({i for m in multiples if m > 0
                for i in range(m, limit, m)})

Given a number, find the sum of all the unique multiples of particular numbers up to - view

pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 {
  (1..limit)
    .filter(|num| factors.iter().any(|factor| num % factor == 0))
    .fold(0, |sum, multiple| sum + multiple)
}

twelve-days #

Output the lyrics to ‘The Twelve Days of Christmas’. - view

thing = ["a Partridge", "two Turtle Doves", "three French Hens", "four Calling Birds",
         "five Gold Rings", "six Geese-a-Laying", "seven Swans-a-Swimming", "eight Maids-a-Milking",
         "nine Ladies Dancing", "ten Lords-a-Leaping", "eleven Pipers Piping", "twelve Drummers Drumming"]
ordinal = ["first", "second", "third", "fourth", "fifth", "sixth",
           "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"]


def things(n):
    if n == 0:
        return thing[n]
    return ", ".join(thing[i] for i in range(n, 0, -1)) + ", and " + thing[0]


def recite(start_verse, end_verse):
    return [f"On the {ordinal[i]} day of Christmas my true love gave to me: {things(i)} in a Pear Tree."
            for i in range(start_verse-1, end_verse)]

two-fer #

Two-fer or 2-fer is short for two for one. One for you and one for me. - view

export function twoFer(name = 'you') {
  return `One for ${name}, one for me.`
}

Two-fer or 2-fer is short for two for one. One for you and one for me. - view

def two_fer(name="you"):
    return f"One for {name}, one for me."

word-count #

Given a phrase, count the occurrences of each word in that phrase. - view

from collections import Counter
from re import sub


def count_words(sentence):
    words = sub(r"[^'0-9A-Za-z]|(?<!\w)'|'(?!\w)",
                ' ', sentence).lower().split()
    return Counter(words)

yacht #

Score a single throw of dice in Yacht - view

# Score categories
# Change the values as you see fit
YACHT = 0
ONES = 1
TWOS = 2
THREES = 3
FOURS = 4
FIVES = 5
SIXES = 6
FULL_HOUSE = 7
FOUR_OF_A_KIND = 8
LITTLE_STRAIGHT = 9
BIG_STRAIGHT = 10
CHOICE = 11


def score(dice, category):
    def count_all():
        count = [0]*6
        for d in dice:
            count[d-1] += 1
        return count

    if category is YACHT:
        return 50 if count_all().count(0) == 5 else 0   # there is not any of other five
    elif category is LITTLE_STRAIGHT:
        return 30 if all(count_all()[:5]) else 0
    elif category == BIG_STRAIGHT:
        return 30 if all(count_all()[1:]) else 0
    elif category is FULL_HOUSE:
        counts = count_all()
        return sum(dice) if all(count in counts for count in [2, 3]) else 0
    elif category is FOUR_OF_A_KIND:
        try:
            # there is more than 4 of any
            return 4 * next(i+1 for i, c in enumerate(count_all()) if c >= 4)
        except StopIteration:
            return 0
    elif category is CHOICE:
        return sum(dice)
    else:   # ONES, TWOS, THREES, FOURS, FIVES, SIXES
        return category * dice.count(category)