A bunch of interview stuff

This commit is contained in:
Ivan Malison 2019-02-25 21:12:33 -08:00
parent 9109a90e4b
commit 2bb3f9eada
No known key found for this signature in database
GPG Key ID: 62530EFBE99DC2F8
8 changed files with 591 additions and 0 deletions

View File

@ -0,0 +1,123 @@
import random
import enum
import itertools
class Suit(enum.Enum):
CLUBS = 0
DIAMONDS = 1
HEARTS = 2
SPADES = 3
class Deck(object):
@classmethod
def random_deck(cls):
return cls(generate_cards())
def __init__(self, cards):
self._cards = cards
self.top = 0
def pop_top(self):
if self.top >= 52:
raise Exception()
card = get_card(self._cards[self.top])
self.top += 1
return card
def get_card(card_number):
return (Suit(card_number // 13), card_number % 13)
def random_permutation_of_size(n):
remaining = list(range(n))
for i in range(n-1, -1, -1):
yield remaining.pop(random.randint(0, i))
def random_permutation(the_list):
for index in random_permutation_of_size(len(the_list)):
yield the_list[index]
def generate_cards(num_cards=52):
return list(random_permutation(range(num_cards)))
def card_value(card_number):
if card_number >= 10:
return 10
return card_number + 1
def card_string(card_number):
if card_number == 12:
return 'K'
elif card_number == 11:
return 'Q'
elif card_number == 10:
return 'J'
return str(card_number + 1)
def get_hand_value(hand):
number_of_aces = 0
total_value = 0
for _, card_number in hand:
if card_number == 0:
number_of_aces += 1
else:
total_value += card_value(card_number)
while total_value < 10 - (number_of_aces - 1):
total_value += 11
number_of_aces -= 1
total_value += number_aces
return total_value
class Blackjack(object):
def __init__(self, deck=None):
self._deck = deck or Deck.random_deck()
self.initialize_game()
def initialize_game(self):
self.dealer_hand = [self._deck.pop_top() for _ in range(2)]
self.player_hand = [self._deck.pop_top() for _ in range(2)]
def hit(self):
self.player_hand.append(self._deck.pop_top())
def run_dealer(self):
while get_hand_value(self.dealer_hand) < 17:
self.dealer_hand.append(self._deck.pop_top())
class UserHandler(object):
def __init__(self, game=None):
self._game = game or Blackjack()
def print_game_state(self):
print(self.game_string())
def game_string(self):
return "\n".join([
self.dealer_string(), self.hand_string(self._game.player_hand),
])
def dealer_string(self):
return "X {0}".format(self.hand_string(self._game.dealer_hand[1:]))
def hand_string(self, cards):
return " ".join(card_string(card[1]) for card in cards)
if __name__ == '__main__':
UserHandler().print_game_state()
the_cards = UserHandler()._game._deck._cards
print (the_cards)
print(set(the_cards) == set(range(52)))

View File

@ -0,0 +1,42 @@
class CountCrimes(object):
def __init__(self, profits, groups, profit_needed, group_count):
self.profits = profits
self.groups = groups
self.crime_count = len(profits)
self.profit_needed = profit_needed
self.group_count = count
self.reset_cache()
def process_crime(self, profit, num_required):
for gangster_count in range(self.group_count, -1, -1):
for profit_amount in range(self.profit_needed, -1, -1):
new_gangster_count = gangster_count + num_required
new_profit = profit_amount + profit
if new_profit > self.profit_needed:
new_profit = self.profit_needed
new_count = self.cache[gangster_count][profit_amount]
if new_count > 0 and new_gangster_count <= self.group_count:
self.cache[new_gangster_count][new_profit] += new_count
def reset_cache(self):
self.cache = [[0 for _ in range(profit_needed + 1)]
for _ in range(group_count + 1)]
self.cache[0][0] = 1
def process_crimes(self):
for profit, num_required in zip(self.profits, self.groups):
self.process_crime(profit, num_required)
def get_count(self):
self.reset_cache()
self.process_crimes()
return self.count_ways()
def count_ways(self):
return sum(self.cache[i][self.profit_needed]
for i in range(self.group_count + 1))
if __name__ == '__main__':
print(CountCrimes().get_count())

View File

@ -0,0 +1,58 @@
#! /usr/bin/env python
import itertools
def textJustify(input_string, justification_length):
partitioning = partition_paragraph(input_string, justification_length)
return "\n".join(itertools.chain(
(justify_line(line_partition, justification_length)
for line_partition in partitioning[:-1]),
[" ".join(partitioning[-1])]
))
def justify_line(line_words, justification_length):
if len(line_words) == 1:
return line_words[0]
total_length = sum(len(word) for word in line_words)
word_count = len(line_words)
number_of_word_boundaries = word_count - 1
spaces_to_add = justification_length - total_length
base_spaces = spaces_to_add // number_of_word_boundaries
extra_spaces = spaces_to_add % number_of_word_boundaries
output_string = ""
for i, word in enumerate(line_words):
output_string += word
if i >= len(line_words) - 1:
break
space_count = base_spaces
if i < extra_spaces:
space_count += 1
spaces = " " * space_count
output_string += spaces
return output_string
def partition_paragraph(input_string, justification_length):
current_line_lenth = 0
partitioning = []
current = []
for word in input_string.split():
word_length = len(word)
length_with_word = current_line_lenth + word_length
if justification_length < length_with_word:
partitioning.append(current)
current = []
current_line_lenth = 0
length_with_word = word_length
current.append(word)
current_line_lenth = length_with_word + 1
if current:
partitioning.append(current)
return partitioning
if __name__ == '__main__':
sample = "Coursera provides universal access to the world's best education, partnering with to universities and organizations to offer courses online."
print(textJustify(sample, 10))

View File

@ -0,0 +1,107 @@
# neighbors = {
# 1: [6, 8],
# 2: [7, 9],
# 3: [8, 4],
# 4: [9, 3, 0],
# 5: [],
# 6: [0, 7, 1],
# 7: [2, 6],
# 8: [1, 3],
# 9: [4, 2],
# 0: [4, 6]
# }
# cache = {}
# def count_numbers(current_number, number_of_hops):
# cache_value = (current_number, number_of_hops)
# if cache_value in cache:
# return cache[cache_value]
# if number_of_hops == 1:
# return 1
# number_count = 0
# for neighbor in neighbors[current_number]:
# number_count += count_numbers(neighbor, number_of_hops - 1)
# cache[cache_value] = number_count
# return number_count
class DialpadCounter(object):
knight_deltas = [
(2, 1),
(-2, -1),
(-2, 1),
(2, -1),
(1, 2),
(-1, -2),
(-1, 2),
(1, -2)
]
def __init__(self, dialpad_matrix):
self._matrix = dialpad_matrix
self._row_size = len(dialpad_matrix[0])
self._row_count = len(dialpad_matrix)
self._cache = {}
def neighbors(self, y, x):
result = []
for delta_y, delta_x in self.knight_deltas:
neighbor_y = delta_y + y
neighbor_x = delta_x + x
neighbor = (neighbor_y, neighbor_x)
if (self.inbounds(neighbor_y, neighbor_x) and
self._matrix[neighbor_y][neighbor_x]):
result.append(neighbor)
return result
def inbounds(self, y, x):
return 0 <= x < self._row_size and 0 <= y < self._row_count
def count_numbers(self, coordinate, number_of_hops):
y, x = coordinate
if not self._matrix[y][x]:
raise Exception()
cache_value = (coordinate, number_of_hops)
if cache_value in self._cache:
return self._cache[cache_value]
if number_of_hops == 1:
return 1
number_count = 0
for neighbor in self.neighbors(y, x):
number_count += self.count_numbers(neighbor, number_of_hops - 1)
self._cache[cache_value] = number_count
return number_count
def count_numbers(number, number_of_hops):
matrix = [
[True, True, True],
[True, True, True],
[True, True, True],
[False, True, False]
]
if number == 0:
coordinate = 3, 1
else:
row = (number - 1) // 3
column = (number - 1) % 3
coordinate = (row, column)
counter = DialpadCounter(matrix)
return counter.count_numbers(coordinate, number_of_hops)
if __name__ == '__main__':
print(count_numbers(1, 1))
print(count_numbers(1, 2))
print(count_numbers(1, 3))
print(count_numbers(1, 4))
print(count_numbers(1, 10))
print(count_numbers(1, 30))

View File

@ -0,0 +1,56 @@
class MazeSolver(object):
def __init__(self, maze):
self.maze = maze
self.row_length = len(maze[0])
self.column_length = len(maze)
self.visited = set()
@property
def finish(self):
return (self.column_length - 1, self.row_length - 1)
deltas = [(1, 0), (0, 1), (-1, 0), (0, -1)]
def is_in_bounds(self, location):
column_index, row_index = location
return (
0 <= column_index < self.column_length and
0 <= row_index < self.row_length
)
def find_adjacency(self, location):
for delta in self.deltas:
column_delta, row_delta = delta
column_location, row_location = location
new_column_location = column_location + column_delta
new_row_location = row_location + row_delta
adjacent_location = (new_column_location, new_row_location)
if (
self.is_in_bounds(adjacent_location) and
self.maze[new_column_location][new_row_location]
):
yield adjacent_location
def solve(self, current_location=(0, 0)):
if current_location == self.finish:
return [current_location]
self.visited.add(current_location)
for new_location in self.find_adjacency(current_location):
if new_location in self.visited:
continue
result = self.solve(new_location)
if result is not None:
return [current_location] + result
return None
if __name__ == '__main__':
maze = [
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[1, 0, 1, 1, 1],
[1, 0, 0, 0, 1],
[1, 1, 1, 1, 1]
]
print(MazeSolver(maze).solve())

View File

@ -0,0 +1,85 @@
#! /usr/bin/env python
class GameOfLife(object):
neighbor_deltas = [
(1, 0), (1, 1), (1, -1),
(0, 1), (0, -1),
(-1, 0), (-1, 1), (-1, -1)
]
@classmethod
def empty_with_size(cls, rows, columns=None):
columns = columns or rows
return cls([])
@staticmethod
def build_empty_grid(rows, columns):
return [[False for _ in range(columns)] for _ in range(rows)]
def __init__(self, initial_state):
self.current_state = initial_state
self.row_count = len(initial_state)
self.column_count = len(initial_state[0])
def _neighbors(self, row, column):
for (row_delta, column_delta) in self.neighbor_deltas:
candidate_row = row + row_delta
candidate_column = column + column_delta
if self._in_bounds(candidate_row, candidate_column):
yield candidate_row, candidate_column
def _in_bounds(self, row, column):
return 0 <= row < self.row_count and 0 <= column < self.column_count
def _next_state_for_cell(self, row, column):
live_count = 0
cell_was_live = self.current_state[row][column]
for neighbor_row, neighbor_column in self._neighbors(row, column):
if self.current_state[neighbor_row][neighbor_column]:
live_count += 1
if cell_was_live:
return 1 < live_count < 4
else:
return live_count == 3
def compute_next_game_state(self, new_state=None):
new_state = new_state or self.build_empty_grid(
self.row_count, self.column_count,
)
for row in range(self.row_count):
for column in range(self.column_count):
new_state[row][column] = self._next_state_for_cell(row, column)
return new_state
def tick(self, new_state=None):
self.current_state = self.compute_next_game_state(new_state)
def _build_row_string(self, row):
return " ".join(["o" if state else "." for state in row])
@property
def state_string(self):
return "\n".join(
self._build_row_string(row) for row in self.current_state
)
@classmethod
def run(cls, initial_state, generations=30):
game = cls(initial_state)
for _ in range(generations):
game.tick()
print(game.state_string)
return game.current_state
sample_size = 50
sample_state = [
[False, True, False] + ([False] * (sample_size - 3)),
[False, False, True] + ([False] * (sample_size - 3)),
[True, True, True] + ([False] * (sample_size - 3)),
] + [[False] * sample_size for _ in range(sample_size - 3)]
if __name__ == '__main__':
GameOfLife.run(sample_state)

View File

@ -0,0 +1,58 @@
#! /usr/bin/env python
import itertools
def textJustify(input_string, justification_length):
partitioning = partition_paragraph(input_string, justification_length)
return "\n".join(itertools.chain(
(justify_line(line_partition, justification_length)
for line_partition in partitioning[:-1]),
[" ".join(partitioning[-1])]
))
def justify_line(line_words, justification_length):
if len(line_words) == 1:
return line_words[0]
total_length = sum(len(word) for word in line_words)
word_count = len(line_words)
number_of_word_boundaries = word_count - 1
spaces_to_add = justification_length - total_length
base_spaces = spaces_to_add // number_of_word_boundaries
extra_spaces = spaces_to_add % number_of_word_boundaries
output_string = ""
for i, word in enumerate(line_words):
output_string += word
if i >= len(line_words) - 1:
break
space_count = base_spaces
if i < extra_spaces:
space_count += 1
spaces = " " * space_count
output_string += spaces
return output_string
def partition_paragraph(input_string, justification_length):
min_line_length = 0
partitioning = []
current = []
for word in input_string.split():
word_length = len(word)
length_with_word = min_line_length + word_length
if justification_length < length_with_word:
partitioning.append(current)
current = []
min_line_length = 0
length_with_word = word_length
current.append(word)
min_line_length = length_with_word + 1
if current:
partitioning.append(current)
return partitioning
if __name__ == '__main__':
sample = "Coursera provides universal access to the world's best education, partnering with to universities and organizations to offer courses online."
print(textJustify(sample, 10))

View File

@ -0,0 +1,62 @@
import asyncio
import random
import queue
import requests
import threading
class WebhookHandler(object):
def __init__(self, callback_uri='http://whatever'):
self.queue = queue.Queue()
self.callback_uri = callback_uri
def enqueue(self, webhook_request):
self.queue.put(webhook_request)
def webhook_worker(self):
while True:
callback_request = self.queue.get()
self.run_request(callback_request)
self.queue.task_done()
def flaky_request(self, callback_request):
random_value = random.random()
print(random_value)
if random_value > .9:
return 500
r = requests.get(self.callback_uri, params=callback_request)
return r.status_code
def run_request(self, request):
status_code = self.flaky_request(request)
if status_code != 200:
asyncio.run(self.do_retry(callback_request))
else:
print("made request")
async def do_retry(self, request, delay=1):
await asyncio.sleep(delay)
print("Retried request")
self.run_request(request)
if __name__ == '__main__':
handler = WebhookHandler(callback_uri="https://www.google.com/")
thread_count = 10
for _ in range(1000):
handler.enqueue({})
threads = []
for _ in range(thread_count):
thread = threading.Thread(target=handler.webhook_worker, daemon=False)
thread.start()
threads.append(thread)
for _ in range(1000):
handler.enqueue({})
loop = asyncio.get_event_loop()
try:
loop.run_forever()
finally:
loop.close()