-
-
Save ara-ta3/58bec44c58720a8228b6ae67d796f687 to your computer and use it in GitHub Desktop.
CTO Challenge 2016 2nd LV3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import List, Dict | |
from functools import reduce | |
from collections import Counter | |
from menu import Menu | |
Coupon = int | |
class CouponSelector(): | |
def __init__(self, | |
limitation_of_coupons: Dict[Coupon, int], | |
coupons_available_for_pizza: List[Coupon], | |
lowest_amount_for_using_coupon: int | |
) -> None: | |
self.limitation_of_coupons = limitation_of_coupons | |
self.coupons_available_for_pizza = coupons_available_for_pizza | |
self.lowest_amount_for_using_coupon = lowest_amount_for_using_coupon | |
def select_optimum_combination_by_menus( | |
self, | |
menus: List[Menu], | |
coupons: List[Coupon]): | |
amount = reduce(lambda amount, m: amount + m.price, menus, 0) | |
available_coupons = _filter_limited_coupons( | |
coupons, | |
self.limitation_of_coupons | |
) | |
if not _pizza_exists(menus): | |
available_coupons = [c for c in available_coupons | |
if c not in self.coupons_available_for_pizza] | |
return self.select_optimum_combination(amount, available_coupons) | |
def select_optimum_combination(self, amount: int, coupons: List[Coupon]): | |
if amount <= self.lowest_amount_for_using_coupon: | |
return [] | |
sorted_coupons = sorted(coupons, reverse=True) | |
rest = amount | |
used_coupons = [] | |
for c in sorted_coupons: | |
if rest < c: | |
break | |
rest -= c | |
used_coupons.append(c) | |
return used_coupons | |
def _pizza_exists(menus: List[Menu]): | |
return any(m.is_pizza() for m in menus) | |
def _filter_limited_coupons( | |
coupons: List[Coupon], | |
coupon2limit: Dict[Coupon, int]): | |
counter = Counter(coupons) | |
for c, n in counter.items(): | |
counter[c] = min(coupon2limit[c], n) | |
return list(counter.elements()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from coupon_selector import CouponSelector | |
coupon_selector = CouponSelector({}, [], 1000) | |
def test_select_optimum_combination_case1(): | |
selected = coupon_selector.select_optimum_combination( | |
1000, | |
[500, 500, 200, 100, 100, 100] | |
) | |
assert selected == [] | |
def test_select_optimum_combination_case2(): | |
selected = coupon_selector.select_optimum_combination(1210, []) | |
assert selected == [] | |
def test_select_optimum_combination_case3(): | |
selected = coupon_selector.select_optimum_combination( | |
1210, | |
[500, 500, 200, 100, 100, 100] | |
) | |
assert selected == [500, 500, 200] | |
def test_select_optimum_combination_case4(): | |
selected = coupon_selector.select_optimum_combination( | |
1530, | |
[500, 500, 200, 100, 100, 100] | |
) | |
assert selected == [500, 500, 200, 100, 100, 100] | |
def test_discounted_in_order_when_coupons_are_not_sorted(): | |
selected = coupon_selector.select_optimum_combination( | |
1530, | |
[500, 200, 100, 500, 100, 100] | |
) | |
assert selected == [500, 500, 200, 100, 100, 100] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from coupon_selector import CouponSelector | |
from menu import PizzaMenu, SideMenu | |
coupon_selector = CouponSelector( | |
{500: 2, 200: 2, 100: 3, 400: 1}, | |
[400], | |
1000 | |
) | |
def test_select_optimum_combination_by_menu_case1_on_lv2(): | |
menus = [PizzaMenu("ジェノベーゼ", "M", 1000)] | |
selected = coupon_selector.select_optimum_combination_by_menus( | |
menus, | |
[500, 200, 100, 400] | |
) | |
assert selected == [] | |
def test_select_optimum_combination_by_menu_case2_on_lv2(): | |
menus = [PizzaMenu("マルゲリータ", "M", 1200)] | |
selected = coupon_selector.select_optimum_combination_by_menus( | |
menus, | |
[] | |
) | |
assert selected == [] | |
def test_select_optimum_combination_by_menu_case3_on_lv2(): | |
menus = [ | |
SideMenu("ポテトフライ", 400), | |
SideMenu("ポテトフライ", 400), | |
SideMenu("シーザーサラダ", 600) | |
] | |
selected = coupon_selector.select_optimum_combination_by_menus( | |
menus, | |
[500, 500, 200, 100, 100, 400] | |
) | |
assert selected == [500, 500, 200, 100, 100] | |
def test_select_optimum_combination_by_menu_case4_on_lv2(): | |
menus = [PizzaMenu("ジェノベーゼ", "L", 1400)] | |
selected = coupon_selector.select_optimum_combination_by_menus( | |
menus, | |
[500, 500, 200, 100, 100, 400] | |
) | |
assert selected == [500, 500, 400] | |
def test_select_optimum_combination_by_menu_case5_on_lv2(): | |
menus = [PizzaMenu("ジェノベーゼ", "M", 1000), PizzaMenu("マルゲリータ", "M", 1200)] | |
selected = coupon_selector.select_optimum_combination_by_menus( | |
menus, | |
[500, 500, 500, 200, 200, 200, 100, 100, 100, 100, 400, 400] | |
) | |
assert selected == [500, 500, 400, 200, 200, 100, 100, 100] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import combinations, product | |
from datetime import datetime | |
from setmenu_discounter import SetMenuDiscount, SetMenuDiscounter | |
from menu import PizzaMenu, SideMenu | |
all_pizza = [ | |
PizzaMenu("ジェノベーゼ", "M", 1000), | |
PizzaMenu("マルゲリータ", "M", 1200), | |
PizzaMenu("ジェノベーゼ", "L", 1400), | |
PizzaMenu("マルゲリータ", "L", 1800), | |
] | |
l_pizza = [ | |
PizzaMenu("ジェノベーゼ", "L", 1400), | |
PizzaMenu("マルゲリータ", "L", 1800), | |
] | |
side_menus = [ | |
SideMenu("ポテトフライ", 400), | |
SideMenu("グリーンサラダ", 500), | |
SideMenu("シーザーサラダ", 600) | |
] | |
def is_weekday_and_from_11_to_14(d): | |
return 0 <= d.weekday() and \ | |
d.weekday() < 5 and \ | |
11 <= d.hour and \ | |
d.hour <= 14 | |
service = SetMenuDiscounter([ | |
SetMenuDiscount( | |
"ピザ2セット", | |
list(map(lambda x: list(x), combinations(all_pizza, 2))), | |
None, | |
[SideMenu("ポテトフライ", 400)], | |
None | |
), | |
SetMenuDiscount( | |
"ピザL2セット", | |
list(map(lambda x: list(x), combinations(l_pizza, 2))), | |
None, | |
[ | |
SideMenu("ポテトフライ", 400), | |
SideMenu("グリーンサラダ", 500), | |
SideMenu("シーザーサラダ", 600) | |
], | |
None | |
), | |
SetMenuDiscount( | |
"平日ランチセット", | |
list(map(lambda x: list(x), product(all_pizza, side_menus))), | |
[is_weekday_and_from_11_to_14], | |
[], | |
400 | |
) | |
]) | |
def test_pizza2_set(): | |
orders = [ | |
PizzaMenu("ジェノベーゼ", "M", 1000), | |
PizzaMenu("マルゲリータ", "M", 1200), | |
SideMenu("ポテトフライ", 400), | |
] | |
(actual, discount) = service.decide_discount(orders, datetime.now()) | |
assert type(actual) == SetMenuDiscount | |
assert actual.name == "ピザ2セット" | |
assert discount == 400 | |
def test_pizzaL2_set(): | |
orders = [ | |
PizzaMenu("ジェノベーゼ", "L", 1400), | |
PizzaMenu("マルゲリータ", "L", 1800), | |
SideMenu("グリーンサラダ", 500), | |
] | |
(actual, discount) = service.decide_discount(orders, datetime.now()) | |
assert type(actual) == SetMenuDiscount | |
assert actual.name == "ピザL2セット" | |
assert discount == 500 | |
def test_weekday_lunch_set(): | |
orders = [ | |
PizzaMenu("ジェノベーゼ", "L", 1400), | |
SideMenu("グリーンサラダ", 500), | |
] | |
(actual, discount) = service.decide_discount( | |
orders, | |
datetime(2016, 10, 26, 11, 30, 0) | |
) | |
assert type(actual) == SetMenuDiscount | |
assert actual.name == "平日ランチセット" | |
assert discount == 400 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pip=bin/pip | |
python=bin/python | |
pyflakes=bin/pyflakes | |
pytest=bin/pytest | |
run: $(python) | |
$< main.py -c $(cs) -m $(ms) | |
test: $(pytest) | |
$< -v ./lv1_test.py ./lv2_test.py ./lv3_test.py | |
install: $(pip) | |
$< install -r requirements.txt | |
$(pytest): $(pip) | |
$(MAKE) install | |
$(pyflakes): $(pip) | |
$(MAKE) install | |
$(python): | |
virtualenv . -p python3 | |
$(pip): | |
virtualenv . -p python3 | |
clean: | |
rm -rf ./bin | |
rm -rf ./lib | |
rm -rf ./include |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pytest | |
flake8 | |
mypy-lang |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment