forked from colonelpanic/dotfiles
A bunch of interview stuff
This commit is contained in:
parent
9109a90e4b
commit
2bb3f9eada
123
dotfiles/lib/python/blackjack.py
Normal file
123
dotfiles/lib/python/blackjack.py
Normal 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)))
|
42
dotfiles/lib/python/crime_profit.py
Normal file
42
dotfiles/lib/python/crime_profit.py
Normal 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())
|
58
dotfiles/lib/python/dashed_paragraph.py
Executable file
58
dotfiles/lib/python/dashed_paragraph.py
Executable 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))
|
107
dotfiles/lib/python/dialpad.py
Normal file
107
dotfiles/lib/python/dialpad.py
Normal 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))
|
56
dotfiles/lib/python/freenome.py
Normal file
56
dotfiles/lib/python/freenome.py
Normal 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())
|
85
dotfiles/lib/python/game_of_life.py
Executable file
85
dotfiles/lib/python/game_of_life.py
Executable 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)
|
58
dotfiles/lib/python/justify_paragraph.py
Executable file
58
dotfiles/lib/python/justify_paragraph.py
Executable 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))
|
62
dotfiles/lib/python/webhook.py
Normal file
62
dotfiles/lib/python/webhook.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user