mega-commit, some from now, some from months ago. added a lot of logging tonight so we can watch a game in real-time. also included slowdown for the same purpose
This commit is contained in:
5
.coveragerc
Normal file
5
.coveragerc
Normal file
@@ -0,0 +1,5 @@
|
||||
[run]
|
||||
omit =
|
||||
*/site-packages/*
|
||||
*/distutils/*
|
||||
tests/*
|
||||
BIN
__pycache__/buy_decision_algos.cpython-37.pyc
Normal file
BIN
__pycache__/buy_decision_algos.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/buy_decision_algos.cpython-39.pyc
Normal file
BIN
__pycache__/buy_decision_algos.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/exceptions.cpython-37.pyc
Normal file
BIN
__pycache__/exceptions.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/exceptions.cpython-39.pyc
Normal file
BIN
__pycache__/exceptions.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/monopoly.cpython-37.pyc
Normal file
BIN
__pycache__/monopoly.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/monopoly.cpython-39.pyc
Normal file
BIN
__pycache__/monopoly.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/simulate.cpython-37.pyc
Normal file
BIN
__pycache__/simulate.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/simulate.cpython-39.pyc
Normal file
BIN
__pycache__/simulate.cpython-39.pyc
Normal file
Binary file not shown.
88
buy_decision_algos.py
Normal file
88
buy_decision_algos.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
from
|
||||
[here](https://blog.ed.ted.com/2017/12/01/heres-how-to-win-at-monopoly-according-to-math-experts/):
|
||||
'For every property (apart from the brown set — which, let’s be honest, is basically pointless),
|
||||
it’s the third house that is really worth investing in quickly. After that, build more if you have
|
||||
the money, but it’s probably worth waiting a few turns if cash is a bit tight. Since there are a
|
||||
limited number of houses in the game, building three houses on properties early and then waiting
|
||||
to upgrade further has the added advantage of potentially blocking the building projects of other
|
||||
players. Sneaky, huh?'
|
||||
'utilities are completely pointless.'
|
||||
"""
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from monopoly import Property, Player
|
||||
|
||||
|
||||
class BuyDecision(ABC):
|
||||
@abstractmethod
|
||||
def __call__(self, property_: "Property", player: "Player"):
|
||||
pass
|
||||
|
||||
|
||||
class BuyEverything(BuyDecision):
|
||||
def __call__(self, _, __):
|
||||
return True
|
||||
|
||||
|
||||
class BuyIfHaveThreeTimesPrice(BuyDecision):
|
||||
def __call__(self, property_: "Property", player: "Player"):
|
||||
return player.money >= property_.cost * 3
|
||||
|
||||
|
||||
class BuyIfDontHaveTwoPartialMonopoliesOfOtherColors(BuyDecision):
|
||||
def __call__(self, property_: "Property", player: "Player"):
|
||||
num_partial_monopolies = 0
|
||||
for property_type, properties in player.properties_by_type.items():
|
||||
if property_type in ("railroad", "utility"):
|
||||
continue
|
||||
if len(properties) == 3:
|
||||
num_partial_monopolies += 1
|
||||
if num_partial_monopolies == 3:
|
||||
print(
|
||||
f"{player.name} isn't buying {property_} because "
|
||||
f"they have {num_partial_monopolies} monopolies"
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class BuyIfOwnFewerThanFivePropertiesOrHaveOneOfThisColor(BuyDecision):
|
||||
def __call__(self, property_, player):
|
||||
num_properties = len(player.properties)
|
||||
if num_properties < 5:
|
||||
print(f"{player} wants to buy {property_}")
|
||||
return True
|
||||
for property_type, properties in player.properties_by_type.items():
|
||||
if property_type == property_.type:
|
||||
print(f"{player} wants to buy {property_}")
|
||||
return True
|
||||
print(f"{player} doesn't want to buy {property_}")
|
||||
return False
|
||||
|
||||
|
||||
class BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned(BuyDecision):
|
||||
"""
|
||||
ALGORITHM
|
||||
---------
|
||||
If nobody owns this type of property, buy it.
|
||||
If only one player owns all owned property of this type, buy it.
|
||||
If this player owns any of this type fo property, buy it.
|
||||
"""
|
||||
|
||||
def __call__(self, property_, player):
|
||||
properties_of_this_type = Property.instances_by_type()[property_.type]
|
||||
if not any(p.owner for p in properties_of_this_type):
|
||||
return True
|
||||
# prevent others from getting monopolies
|
||||
if (
|
||||
len(set([p.owner for p in Property.instances_by_type()[property_.type]]))
|
||||
== 1
|
||||
):
|
||||
return True
|
||||
|
||||
players_property_types = player.properties_by_type.keys()
|
||||
if player.properties and property_.type in players_property_types:
|
||||
return True
|
||||
return False
|
||||
@@ -10,6 +10,10 @@ class NotEnough(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NotEnoughPlayers(NotEnough):
|
||||
pass
|
||||
|
||||
|
||||
class MustBeEqualAmounts(Exception):
|
||||
pass
|
||||
|
||||
|
||||
589
htmlcov/coverage_html.js
generated
Normal file
589
htmlcov/coverage_html.js
generated
Normal file
@@ -0,0 +1,589 @@
|
||||
// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
|
||||
// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
|
||||
|
||||
// Coverage.py HTML report browser code.
|
||||
/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
|
||||
/*global coverage: true, document, window, $ */
|
||||
|
||||
coverage = {};
|
||||
|
||||
// Find all the elements with shortkey_* class, and use them to assign a shortcut key.
|
||||
coverage.assign_shortkeys = function () {
|
||||
$("*[class*='shortkey_']").each(function (i, e) {
|
||||
$.each($(e).attr("class").split(" "), function (i, c) {
|
||||
if (/^shortkey_/.test(c)) {
|
||||
$(document).bind('keydown', c.substr(9), function () {
|
||||
$(e).click();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Create the events for the help panel.
|
||||
coverage.wire_up_help_panel = function () {
|
||||
$("#keyboard_icon").click(function () {
|
||||
// Show the help panel, and position it so the keyboard icon in the
|
||||
// panel is in the same place as the keyboard icon in the header.
|
||||
$(".help_panel").show();
|
||||
var koff = $("#keyboard_icon").offset();
|
||||
var poff = $("#panel_icon").position();
|
||||
$(".help_panel").offset({
|
||||
top: koff.top-poff.top,
|
||||
left: koff.left-poff.left
|
||||
});
|
||||
});
|
||||
$("#panel_icon").click(function () {
|
||||
$(".help_panel").hide();
|
||||
});
|
||||
};
|
||||
|
||||
// Create the events for the filter box.
|
||||
coverage.wire_up_filter = function () {
|
||||
// Cache elements.
|
||||
var table = $("table.index");
|
||||
var table_rows = table.find("tbody tr");
|
||||
var table_row_names = table_rows.find("td.name a");
|
||||
var no_rows = $("#no_rows");
|
||||
|
||||
// Create a duplicate table footer that we can modify with dynamic summed values.
|
||||
var table_footer = $("table.index tfoot tr");
|
||||
var table_dynamic_footer = table_footer.clone();
|
||||
table_dynamic_footer.attr('class', 'total_dynamic hidden');
|
||||
table_footer.after(table_dynamic_footer);
|
||||
|
||||
// Observe filter keyevents.
|
||||
$("#filter").on("keyup change", $.debounce(150, function (event) {
|
||||
var filter_value = $(this).val();
|
||||
|
||||
if (filter_value === "") {
|
||||
// Filter box is empty, remove all filtering.
|
||||
table_rows.removeClass("hidden");
|
||||
|
||||
// Show standard footer, hide dynamic footer.
|
||||
table_footer.removeClass("hidden");
|
||||
table_dynamic_footer.addClass("hidden");
|
||||
|
||||
// Hide placeholder, show table.
|
||||
if (no_rows.length > 0) {
|
||||
no_rows.hide();
|
||||
}
|
||||
table.show();
|
||||
|
||||
}
|
||||
else {
|
||||
// Filter table items by value.
|
||||
var hidden = 0;
|
||||
var shown = 0;
|
||||
|
||||
// Hide / show elements.
|
||||
$.each(table_row_names, function () {
|
||||
var element = $(this).parents("tr");
|
||||
|
||||
if ($(this).text().indexOf(filter_value) === -1) {
|
||||
// hide
|
||||
element.addClass("hidden");
|
||||
hidden++;
|
||||
}
|
||||
else {
|
||||
// show
|
||||
element.removeClass("hidden");
|
||||
shown++;
|
||||
}
|
||||
});
|
||||
|
||||
// Show placeholder if no rows will be displayed.
|
||||
if (no_rows.length > 0) {
|
||||
if (shown === 0) {
|
||||
// Show placeholder, hide table.
|
||||
no_rows.show();
|
||||
table.hide();
|
||||
}
|
||||
else {
|
||||
// Hide placeholder, show table.
|
||||
no_rows.hide();
|
||||
table.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Manage dynamic header:
|
||||
if (hidden > 0) {
|
||||
// Calculate new dynamic sum values based on visible rows.
|
||||
for (var column = 2; column < 20; column++) {
|
||||
// Calculate summed value.
|
||||
var cells = table_rows.find('td:nth-child(' + column + ')');
|
||||
if (!cells.length) {
|
||||
// No more columns...!
|
||||
break;
|
||||
}
|
||||
|
||||
var sum = 0, numer = 0, denom = 0;
|
||||
$.each(cells.filter(':visible'), function () {
|
||||
var ratio = $(this).data("ratio");
|
||||
if (ratio) {
|
||||
var splitted = ratio.split(" ");
|
||||
numer += parseInt(splitted[0], 10);
|
||||
denom += parseInt(splitted[1], 10);
|
||||
}
|
||||
else {
|
||||
sum += parseInt(this.innerHTML, 10);
|
||||
}
|
||||
});
|
||||
|
||||
// Get footer cell element.
|
||||
var footer_cell = table_dynamic_footer.find('td:nth-child(' + column + ')');
|
||||
|
||||
// Set value into dynamic footer cell element.
|
||||
if (cells[0].innerHTML.indexOf('%') > -1) {
|
||||
// Percentage columns use the numerator and denominator,
|
||||
// and adapt to the number of decimal places.
|
||||
var match = /\.([0-9]+)/.exec(cells[0].innerHTML);
|
||||
var places = 0;
|
||||
if (match) {
|
||||
places = match[1].length;
|
||||
}
|
||||
var pct = numer * 100 / denom;
|
||||
footer_cell.text(pct.toFixed(places) + '%');
|
||||
}
|
||||
else {
|
||||
footer_cell.text(sum);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide standard footer, show dynamic footer.
|
||||
table_footer.addClass("hidden");
|
||||
table_dynamic_footer.removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
// Show standard footer, hide dynamic footer.
|
||||
table_footer.removeClass("hidden");
|
||||
table_dynamic_footer.addClass("hidden");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// Trigger change event on setup, to force filter on page refresh
|
||||
// (filter value may still be present).
|
||||
$("#filter").trigger("change");
|
||||
};
|
||||
|
||||
// Loaded on index.html
|
||||
coverage.index_ready = function ($) {
|
||||
// Look for a localStorage item containing previous sort settings:
|
||||
var sort_list = [];
|
||||
var storage_name = "COVERAGE_INDEX_SORT";
|
||||
var stored_list = undefined;
|
||||
try {
|
||||
stored_list = localStorage.getItem(storage_name);
|
||||
} catch(err) {}
|
||||
|
||||
if (stored_list) {
|
||||
sort_list = JSON.parse('[[' + stored_list + ']]');
|
||||
}
|
||||
|
||||
// Create a new widget which exists only to save and restore
|
||||
// the sort order:
|
||||
$.tablesorter.addWidget({
|
||||
id: "persistentSort",
|
||||
|
||||
// Format is called by the widget before displaying:
|
||||
format: function (table) {
|
||||
if (table.config.sortList.length === 0 && sort_list.length > 0) {
|
||||
// This table hasn't been sorted before - we'll use
|
||||
// our stored settings:
|
||||
$(table).trigger('sorton', [sort_list]);
|
||||
}
|
||||
else {
|
||||
// This is not the first load - something has
|
||||
// already defined sorting so we'll just update
|
||||
// our stored value to match:
|
||||
sort_list = table.config.sortList;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Configure our tablesorter to handle the variable number of
|
||||
// columns produced depending on report options:
|
||||
var headers = [];
|
||||
var col_count = $("table.index > thead > tr > th").length;
|
||||
|
||||
headers[0] = { sorter: 'text' };
|
||||
for (i = 1; i < col_count-1; i++) {
|
||||
headers[i] = { sorter: 'digit' };
|
||||
}
|
||||
headers[col_count-1] = { sorter: 'percent' };
|
||||
|
||||
// Enable the table sorter:
|
||||
$("table.index").tablesorter({
|
||||
widgets: ['persistentSort'],
|
||||
headers: headers
|
||||
});
|
||||
|
||||
coverage.assign_shortkeys();
|
||||
coverage.wire_up_help_panel();
|
||||
coverage.wire_up_filter();
|
||||
|
||||
// Watch for page unload events so we can save the final sort settings:
|
||||
$(window).unload(function () {
|
||||
try {
|
||||
localStorage.setItem(storage_name, sort_list.toString())
|
||||
} catch(err) {}
|
||||
});
|
||||
};
|
||||
|
||||
// -- pyfile stuff --
|
||||
|
||||
coverage.pyfile_ready = function ($) {
|
||||
// If we're directed to a particular line number, highlight the line.
|
||||
var frag = location.hash;
|
||||
if (frag.length > 2 && frag[1] === 't') {
|
||||
$(frag).addClass('highlight');
|
||||
coverage.set_sel(parseInt(frag.substr(2), 10));
|
||||
}
|
||||
else {
|
||||
coverage.set_sel(0);
|
||||
}
|
||||
|
||||
$(document)
|
||||
.bind('keydown', 'j', coverage.to_next_chunk_nicely)
|
||||
.bind('keydown', 'k', coverage.to_prev_chunk_nicely)
|
||||
.bind('keydown', '0', coverage.to_top)
|
||||
.bind('keydown', '1', coverage.to_first_chunk)
|
||||
;
|
||||
|
||||
$(".button_toggle_run").click(function (evt) {coverage.toggle_lines(evt.target, "run");});
|
||||
$(".button_toggle_exc").click(function (evt) {coverage.toggle_lines(evt.target, "exc");});
|
||||
$(".button_toggle_mis").click(function (evt) {coverage.toggle_lines(evt.target, "mis");});
|
||||
$(".button_toggle_par").click(function (evt) {coverage.toggle_lines(evt.target, "par");});
|
||||
|
||||
coverage.assign_shortkeys();
|
||||
coverage.wire_up_help_panel();
|
||||
|
||||
coverage.init_scroll_markers();
|
||||
|
||||
// Rebuild scroll markers when the window height changes.
|
||||
$(window).resize(coverage.build_scroll_markers);
|
||||
};
|
||||
|
||||
coverage.toggle_lines = function (btn, cls) {
|
||||
btn = $(btn);
|
||||
var show = "show_"+cls;
|
||||
if (btn.hasClass(show)) {
|
||||
$("#source ." + cls).removeClass(show);
|
||||
btn.removeClass(show);
|
||||
}
|
||||
else {
|
||||
$("#source ." + cls).addClass(show);
|
||||
btn.addClass(show);
|
||||
}
|
||||
coverage.build_scroll_markers();
|
||||
};
|
||||
|
||||
// Return the nth line div.
|
||||
coverage.line_elt = function (n) {
|
||||
return $("#t" + n);
|
||||
};
|
||||
|
||||
// Return the nth line number div.
|
||||
coverage.num_elt = function (n) {
|
||||
return $("#n" + n);
|
||||
};
|
||||
|
||||
// Set the selection. b and e are line numbers.
|
||||
coverage.set_sel = function (b, e) {
|
||||
// The first line selected.
|
||||
coverage.sel_begin = b;
|
||||
// The next line not selected.
|
||||
coverage.sel_end = (e === undefined) ? b+1 : e;
|
||||
};
|
||||
|
||||
coverage.to_top = function () {
|
||||
coverage.set_sel(0, 1);
|
||||
coverage.scroll_window(0);
|
||||
};
|
||||
|
||||
coverage.to_first_chunk = function () {
|
||||
coverage.set_sel(0, 1);
|
||||
coverage.to_next_chunk();
|
||||
};
|
||||
|
||||
// Return a string indicating what kind of chunk this line belongs to,
|
||||
// or null if not a chunk.
|
||||
coverage.chunk_indicator = function (line_elt) {
|
||||
var klass = line_elt.attr('class');
|
||||
if (klass) {
|
||||
var m = klass.match(/\bshow_\w+\b/);
|
||||
if (m) {
|
||||
return m[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
coverage.to_next_chunk = function () {
|
||||
var c = coverage;
|
||||
|
||||
// Find the start of the next colored chunk.
|
||||
var probe = c.sel_end;
|
||||
var chunk_indicator, probe_line;
|
||||
while (true) {
|
||||
probe_line = c.line_elt(probe);
|
||||
if (probe_line.length === 0) {
|
||||
return;
|
||||
}
|
||||
chunk_indicator = c.chunk_indicator(probe_line);
|
||||
if (chunk_indicator) {
|
||||
break;
|
||||
}
|
||||
probe++;
|
||||
}
|
||||
|
||||
// There's a next chunk, `probe` points to it.
|
||||
var begin = probe;
|
||||
|
||||
// Find the end of this chunk.
|
||||
var next_indicator = chunk_indicator;
|
||||
while (next_indicator === chunk_indicator) {
|
||||
probe++;
|
||||
probe_line = c.line_elt(probe);
|
||||
next_indicator = c.chunk_indicator(probe_line);
|
||||
}
|
||||
c.set_sel(begin, probe);
|
||||
c.show_selection();
|
||||
};
|
||||
|
||||
coverage.to_prev_chunk = function () {
|
||||
var c = coverage;
|
||||
|
||||
// Find the end of the prev colored chunk.
|
||||
var probe = c.sel_begin-1;
|
||||
var probe_line = c.line_elt(probe);
|
||||
if (probe_line.length === 0) {
|
||||
return;
|
||||
}
|
||||
var chunk_indicator = c.chunk_indicator(probe_line);
|
||||
while (probe > 0 && !chunk_indicator) {
|
||||
probe--;
|
||||
probe_line = c.line_elt(probe);
|
||||
if (probe_line.length === 0) {
|
||||
return;
|
||||
}
|
||||
chunk_indicator = c.chunk_indicator(probe_line);
|
||||
}
|
||||
|
||||
// There's a prev chunk, `probe` points to its last line.
|
||||
var end = probe+1;
|
||||
|
||||
// Find the beginning of this chunk.
|
||||
var prev_indicator = chunk_indicator;
|
||||
while (prev_indicator === chunk_indicator) {
|
||||
probe--;
|
||||
probe_line = c.line_elt(probe);
|
||||
prev_indicator = c.chunk_indicator(probe_line);
|
||||
}
|
||||
c.set_sel(probe+1, end);
|
||||
c.show_selection();
|
||||
};
|
||||
|
||||
// Return the line number of the line nearest pixel position pos
|
||||
coverage.line_at_pos = function (pos) {
|
||||
var l1 = coverage.line_elt(1),
|
||||
l2 = coverage.line_elt(2),
|
||||
result;
|
||||
if (l1.length && l2.length) {
|
||||
var l1_top = l1.offset().top,
|
||||
line_height = l2.offset().top - l1_top,
|
||||
nlines = (pos - l1_top) / line_height;
|
||||
if (nlines < 1) {
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
result = Math.ceil(nlines);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Returns 0, 1, or 2: how many of the two ends of the selection are on
|
||||
// the screen right now?
|
||||
coverage.selection_ends_on_screen = function () {
|
||||
if (coverage.sel_begin === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var top = coverage.line_elt(coverage.sel_begin);
|
||||
var next = coverage.line_elt(coverage.sel_end-1);
|
||||
|
||||
return (
|
||||
(top.isOnScreen() ? 1 : 0) +
|
||||
(next.isOnScreen() ? 1 : 0)
|
||||
);
|
||||
};
|
||||
|
||||
coverage.to_next_chunk_nicely = function () {
|
||||
coverage.finish_scrolling();
|
||||
if (coverage.selection_ends_on_screen() === 0) {
|
||||
// The selection is entirely off the screen: select the top line on
|
||||
// the screen.
|
||||
var win = $(window);
|
||||
coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop()));
|
||||
}
|
||||
coverage.to_next_chunk();
|
||||
};
|
||||
|
||||
coverage.to_prev_chunk_nicely = function () {
|
||||
coverage.finish_scrolling();
|
||||
if (coverage.selection_ends_on_screen() === 0) {
|
||||
var win = $(window);
|
||||
coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop() + win.height()));
|
||||
}
|
||||
coverage.to_prev_chunk();
|
||||
};
|
||||
|
||||
// Select line number lineno, or if it is in a colored chunk, select the
|
||||
// entire chunk
|
||||
coverage.select_line_or_chunk = function (lineno) {
|
||||
var c = coverage;
|
||||
var probe_line = c.line_elt(lineno);
|
||||
if (probe_line.length === 0) {
|
||||
return;
|
||||
}
|
||||
var the_indicator = c.chunk_indicator(probe_line);
|
||||
if (the_indicator) {
|
||||
// The line is in a highlighted chunk.
|
||||
// Search backward for the first line.
|
||||
var probe = lineno;
|
||||
var indicator = the_indicator;
|
||||
while (probe > 0 && indicator === the_indicator) {
|
||||
probe--;
|
||||
probe_line = c.line_elt(probe);
|
||||
if (probe_line.length === 0) {
|
||||
break;
|
||||
}
|
||||
indicator = c.chunk_indicator(probe_line);
|
||||
}
|
||||
var begin = probe + 1;
|
||||
|
||||
// Search forward for the last line.
|
||||
probe = lineno;
|
||||
indicator = the_indicator;
|
||||
while (indicator === the_indicator) {
|
||||
probe++;
|
||||
probe_line = c.line_elt(probe);
|
||||
indicator = c.chunk_indicator(probe_line);
|
||||
}
|
||||
|
||||
coverage.set_sel(begin, probe);
|
||||
}
|
||||
else {
|
||||
coverage.set_sel(lineno);
|
||||
}
|
||||
};
|
||||
|
||||
coverage.show_selection = function () {
|
||||
var c = coverage;
|
||||
|
||||
// Highlight the lines in the chunk
|
||||
$(".linenos .highlight").removeClass("highlight");
|
||||
for (var probe = c.sel_begin; probe > 0 && probe < c.sel_end; probe++) {
|
||||
c.num_elt(probe).addClass("highlight");
|
||||
}
|
||||
|
||||
c.scroll_to_selection();
|
||||
};
|
||||
|
||||
coverage.scroll_to_selection = function () {
|
||||
// Scroll the page if the chunk isn't fully visible.
|
||||
if (coverage.selection_ends_on_screen() < 2) {
|
||||
// Need to move the page. The html,body trick makes it scroll in all
|
||||
// browsers, got it from http://stackoverflow.com/questions/3042651
|
||||
var top = coverage.line_elt(coverage.sel_begin);
|
||||
var top_pos = parseInt(top.offset().top, 10);
|
||||
coverage.scroll_window(top_pos - 30);
|
||||
}
|
||||
};
|
||||
|
||||
coverage.scroll_window = function (to_pos) {
|
||||
$("html,body").animate({scrollTop: to_pos}, 200);
|
||||
};
|
||||
|
||||
coverage.finish_scrolling = function () {
|
||||
$("html,body").stop(true, true);
|
||||
};
|
||||
|
||||
coverage.init_scroll_markers = function () {
|
||||
var c = coverage;
|
||||
// Init some variables
|
||||
c.lines_len = $('#source p').length;
|
||||
c.body_h = $('body').height();
|
||||
c.header_h = $('div#header').height();
|
||||
|
||||
// Build html
|
||||
c.build_scroll_markers();
|
||||
};
|
||||
|
||||
coverage.build_scroll_markers = function () {
|
||||
var c = coverage,
|
||||
min_line_height = 3,
|
||||
max_line_height = 10,
|
||||
visible_window_h = $(window).height();
|
||||
|
||||
c.lines_to_mark = $('#source').find('p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par');
|
||||
$('#scroll_marker').remove();
|
||||
// Don't build markers if the window has no scroll bar.
|
||||
if (c.body_h <= visible_window_h) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("body").append("<div id='scroll_marker'> </div>");
|
||||
var scroll_marker = $('#scroll_marker'),
|
||||
marker_scale = scroll_marker.height() / c.body_h,
|
||||
line_height = scroll_marker.height() / c.lines_len;
|
||||
|
||||
// Line height must be between the extremes.
|
||||
if (line_height > min_line_height) {
|
||||
if (line_height > max_line_height) {
|
||||
line_height = max_line_height;
|
||||
}
|
||||
}
|
||||
else {
|
||||
line_height = min_line_height;
|
||||
}
|
||||
|
||||
var previous_line = -99,
|
||||
last_mark,
|
||||
last_top,
|
||||
offsets = {};
|
||||
|
||||
// Calculate line offsets outside loop to prevent relayouts
|
||||
c.lines_to_mark.each(function() {
|
||||
offsets[this.id] = $(this).offset().top;
|
||||
});
|
||||
c.lines_to_mark.each(function () {
|
||||
var id_name = $(this).attr('id'),
|
||||
line_top = Math.round(offsets[id_name] * marker_scale),
|
||||
line_number = parseInt(id_name.substring(1, id_name.length));
|
||||
|
||||
if (line_number === previous_line + 1) {
|
||||
// If this solid missed block just make previous mark higher.
|
||||
last_mark.css({
|
||||
'height': line_top + line_height - last_top
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Add colored line in scroll_marker block.
|
||||
scroll_marker.append('<div id="m' + line_number + '" class="marker"></div>');
|
||||
last_mark = $('#m' + line_number);
|
||||
last_mark.css({
|
||||
'height': line_height,
|
||||
'top': line_top
|
||||
});
|
||||
last_top = line_top;
|
||||
}
|
||||
|
||||
previous_line = line_number;
|
||||
});
|
||||
};
|
||||
102
htmlcov/exceptions_py.html
generated
Normal file
102
htmlcov/exceptions_py.html
generated
Normal file
@@ -0,0 +1,102 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
|
||||
<title>Coverage for exceptions.py: 100%</title>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script type="text/javascript" src="jquery.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.hotkeys.js"></script>
|
||||
<script type="text/javascript" src="jquery.isonscreen.js"></script>
|
||||
<script type="text/javascript" src="coverage_html.js"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(coverage.pyfile_ready);
|
||||
</script>
|
||||
</head>
|
||||
<body class="pyfile">
|
||||
<div id="header">
|
||||
<div class="content">
|
||||
<h1>Coverage for <b>exceptions.py</b> :
|
||||
<span class="pc_cov">100%</span>
|
||||
</h1>
|
||||
<img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
|
||||
<h2 class="stats">
|
||||
20 statements
|
||||
<span class="run shortkey_r button_toggle_run">20 run</span>
|
||||
<span class="mis show_mis shortkey_m button_toggle_mis">0 missing</span>
|
||||
<span class="exc show_exc shortkey_x button_toggle_exc">0 excluded</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="help_panel">
|
||||
<img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
|
||||
<p class="legend">Hot-keys on this page</p>
|
||||
<div>
|
||||
<p class="keyhelp">
|
||||
<span class="key">r</span>
|
||||
<span class="key">m</span>
|
||||
<span class="key">x</span>
|
||||
<span class="key">p</span> toggle line displays
|
||||
</p>
|
||||
<p class="keyhelp">
|
||||
<span class="key">j</span>
|
||||
<span class="key">k</span> next/prev highlighted chunk
|
||||
</p>
|
||||
<p class="keyhelp">
|
||||
<span class="key">0</span> (zero) top of page
|
||||
</p>
|
||||
<p class="keyhelp">
|
||||
<span class="key">1</span> (one) first highlighted chunk
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="source">
|
||||
<p id="t1" class="run"><span class="n"><a href="#t1">1</a></span><span class="t"><span class="key">class</span> <span class="nam">TooMany</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t2" class="run"><span class="n"><a href="#t2">2</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t3" class="pln"><span class="n"><a href="#t3">3</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t4" class="pln"><span class="n"><a href="#t4">4</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t5" class="run"><span class="n"><a href="#t5">5</a></span><span class="t"><span class="key">class</span> <span class="nam">TooManyPlayers</span><span class="op">(</span><span class="nam">TooMany</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t6" class="run"><span class="n"><a href="#t6">6</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t7" class="pln"><span class="n"><a href="#t7">7</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t8" class="pln"><span class="n"><a href="#t8">8</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t9" class="run"><span class="n"><a href="#t9">9</a></span><span class="t"><span class="key">class</span> <span class="nam">NotEnough</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t10" class="run"><span class="n"><a href="#t10">10</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t11" class="pln"><span class="n"><a href="#t11">11</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t12" class="pln"><span class="n"><a href="#t12">12</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t13" class="run"><span class="n"><a href="#t13">13</a></span><span class="t"><span class="key">class</span> <span class="nam">NotEnoughPlayers</span><span class="op">(</span><span class="nam">NotEnough</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t14" class="run"><span class="n"><a href="#t14">14</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t15" class="pln"><span class="n"><a href="#t15">15</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t16" class="pln"><span class="n"><a href="#t16">16</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t17" class="run"><span class="n"><a href="#t17">17</a></span><span class="t"><span class="key">class</span> <span class="nam">MustBeEqualAmounts</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t18" class="run"><span class="n"><a href="#t18">18</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t19" class="pln"><span class="n"><a href="#t19">19</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t20" class="pln"><span class="n"><a href="#t20">20</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t21" class="run"><span class="n"><a href="#t21">21</a></span><span class="t"><span class="key">class</span> <span class="nam">Argument</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t22" class="run"><span class="n"><a href="#t22">22</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t23" class="pln"><span class="n"><a href="#t23">23</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t24" class="pln"><span class="n"><a href="#t24">24</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t25" class="run"><span class="n"><a href="#t25">25</a></span><span class="t"><span class="key">class</span> <span class="nam">DidntFind</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t26" class="run"><span class="n"><a href="#t26">26</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t27" class="pln"><span class="n"><a href="#t27">27</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t28" class="pln"><span class="n"><a href="#t28">28</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t29" class="run"><span class="n"><a href="#t29">29</a></span><span class="t"><span class="key">class</span> <span class="nam">NoOwner</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t30" class="run"><span class="n"><a href="#t30">30</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t31" class="pln"><span class="n"><a href="#t31">31</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t32" class="pln"><span class="n"><a href="#t32">32</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t33" class="run"><span class="n"><a href="#t33">33</a></span><span class="t"><span class="key">class</span> <span class="nam">CantMortgage</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t34" class="run"><span class="n"><a href="#t34">34</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
<p id="t35" class="pln"><span class="n"><a href="#t35">35</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t36" class="pln"><span class="n"><a href="#t36">36</a></span><span class="t"> </span><span class="r"></span></p>
|
||||
<p id="t37" class="run"><span class="n"><a href="#t37">37</a></span><span class="t"><span class="key">class</span> <span class="nam">CantBuyBuildings</span><span class="op">(</span><span class="nam">Exception</span><span class="op">)</span><span class="op">:</span> </span><span class="r"></span></p>
|
||||
<p id="t38" class="run"><span class="n"><a href="#t38">38</a></span><span class="t"> <span class="key">pass</span> </span><span class="r"></span></p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="content">
|
||||
<p>
|
||||
<a class="nav" href="index.html">« index</a> <a class="nav" href="https://coverage.readthedocs.io">coverage.py v5.1</a>,
|
||||
created at 2020-06-01 17:09
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
91
htmlcov/index.html
generated
Normal file
91
htmlcov/index.html
generated
Normal file
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Coverage report</title>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script type="text/javascript" src="jquery.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.ba-throttle-debounce.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.tablesorter.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.hotkeys.js"></script>
|
||||
<script type="text/javascript" src="coverage_html.js"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(coverage.index_ready);
|
||||
</script>
|
||||
</head>
|
||||
<body class="indexfile">
|
||||
<div id="header">
|
||||
<div class="content">
|
||||
<h1>Coverage report:
|
||||
<span class="pc_cov">50%</span>
|
||||
</h1>
|
||||
<img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />
|
||||
<form id="filter_container">
|
||||
<input id="filter" type="text" value="" placeholder="filter..." />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="help_panel">
|
||||
<img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />
|
||||
<p class="legend">Hot-keys on this page</p>
|
||||
<div>
|
||||
<p class="keyhelp">
|
||||
<span class="key">n</span>
|
||||
<span class="key">s</span>
|
||||
<span class="key">m</span>
|
||||
<span class="key">x</span>
|
||||
<span class="key">c</span> change column sorting
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="index">
|
||||
<table class="index">
|
||||
<thead>
|
||||
<tr class="tablehead" title="Click to sort">
|
||||
<th class="name left headerSortDown shortkey_n">Module</th>
|
||||
<th class="shortkey_s">statements</th>
|
||||
<th class="shortkey_m">missing</th>
|
||||
<th class="shortkey_x">excluded</th>
|
||||
<th class="right shortkey_c">coverage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr class="total">
|
||||
<td class="name left">Total</td>
|
||||
<td>505</td>
|
||||
<td>250</td>
|
||||
<td>0</td>
|
||||
<td class="right" data-ratio="255 505">50%</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr class="file">
|
||||
<td class="name left"><a href="exceptions_py.html">exceptions.py</a></td>
|
||||
<td>20</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td class="right" data-ratio="20 20">100%</td>
|
||||
</tr>
|
||||
<tr class="file">
|
||||
<td class="name left"><a href="monopoly_py.html">monopoly.py</a></td>
|
||||
<td>485</td>
|
||||
<td>250</td>
|
||||
<td>0</td>
|
||||
<td class="right" data-ratio="235 485">48%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p id="no_rows">
|
||||
No items found using the specified filter.
|
||||
</p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="content">
|
||||
<p>
|
||||
<a class="nav" href="https://coverage.readthedocs.io">coverage.py v5.1</a>,
|
||||
created at 2020-06-01 17:10
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
9
htmlcov/jquery.ba-throttle-debounce.min.js
generated
vendored
Normal file
9
htmlcov/jquery.ba-throttle-debounce.min.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* jQuery throttle / debounce - v1.1 - 3/7/2010
|
||||
* http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
|
||||
99
htmlcov/jquery.hotkeys.js
generated
Normal file
99
htmlcov/jquery.hotkeys.js
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* jQuery Hotkeys Plugin
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Based upon the plugin by Tzury Bar Yochay:
|
||||
* http://github.com/tzuryby/hotkeys
|
||||
*
|
||||
* Original idea by:
|
||||
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
||||
*/
|
||||
|
||||
(function(jQuery){
|
||||
|
||||
jQuery.hotkeys = {
|
||||
version: "0.8",
|
||||
|
||||
specialKeys: {
|
||||
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
|
||||
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
|
||||
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
|
||||
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
|
||||
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
|
||||
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
|
||||
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
|
||||
},
|
||||
|
||||
shiftNums: {
|
||||
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
|
||||
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
|
||||
".": ">", "/": "?", "\\": "|"
|
||||
}
|
||||
};
|
||||
|
||||
function keyHandler( handleObj ) {
|
||||
// Only care when a possible input has been specified
|
||||
if ( typeof handleObj.data !== "string" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var origHandler = handleObj.handler,
|
||||
keys = handleObj.data.toLowerCase().split(" ");
|
||||
|
||||
handleObj.handler = function( event ) {
|
||||
// Don't fire in text-accepting inputs that we didn't directly bind to
|
||||
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
|
||||
event.target.type === "text") ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keypress represents characters, not special keys
|
||||
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
|
||||
character = String.fromCharCode( event.which ).toLowerCase(),
|
||||
key, modif = "", possible = {};
|
||||
|
||||
// check combinations (alt|ctrl|shift+anything)
|
||||
if ( event.altKey && special !== "alt" ) {
|
||||
modif += "alt+";
|
||||
}
|
||||
|
||||
if ( event.ctrlKey && special !== "ctrl" ) {
|
||||
modif += "ctrl+";
|
||||
}
|
||||
|
||||
// TODO: Need to make sure this works consistently across platforms
|
||||
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
|
||||
modif += "meta+";
|
||||
}
|
||||
|
||||
if ( event.shiftKey && special !== "shift" ) {
|
||||
modif += "shift+";
|
||||
}
|
||||
|
||||
if ( special ) {
|
||||
possible[ modif + special ] = true;
|
||||
|
||||
} else {
|
||||
possible[ modif + character ] = true;
|
||||
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
|
||||
|
||||
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
||||
if ( modif === "shift+" ) {
|
||||
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
if ( possible[ keys[i] ] ) {
|
||||
return origHandler.apply( this, arguments );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
jQuery.each([ "keydown", "keyup", "keypress" ], function() {
|
||||
jQuery.event.special[ this ] = { add: keyHandler };
|
||||
});
|
||||
|
||||
})( jQuery );
|
||||
53
htmlcov/jquery.isonscreen.js
generated
Normal file
53
htmlcov/jquery.isonscreen.js
generated
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Copyright (c) 2010
|
||||
* @author Laurence Wheway
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
*
|
||||
* @version 1.2.0
|
||||
*/
|
||||
(function($) {
|
||||
jQuery.extend({
|
||||
isOnScreen: function(box, container) {
|
||||
//ensure numbers come in as intgers (not strings) and remove 'px' is it's there
|
||||
for(var i in box){box[i] = parseFloat(box[i])};
|
||||
for(var i in container){container[i] = parseFloat(container[i])};
|
||||
|
||||
if(!container){
|
||||
container = {
|
||||
left: $(window).scrollLeft(),
|
||||
top: $(window).scrollTop(),
|
||||
width: $(window).width(),
|
||||
height: $(window).height()
|
||||
}
|
||||
}
|
||||
|
||||
if( box.left+box.width-container.left > 0 &&
|
||||
box.left < container.width+container.left &&
|
||||
box.top+box.height-container.top > 0 &&
|
||||
box.top < container.height+container.top
|
||||
) return true;
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
jQuery.fn.isOnScreen = function (container) {
|
||||
for(var i in container){container[i] = parseFloat(container[i])};
|
||||
|
||||
if(!container){
|
||||
container = {
|
||||
left: $(window).scrollLeft(),
|
||||
top: $(window).scrollTop(),
|
||||
width: $(window).width(),
|
||||
height: $(window).height()
|
||||
}
|
||||
}
|
||||
|
||||
if( $(this).offset().left+$(this).width()-container.left > 0 &&
|
||||
$(this).offset().left < container.width+container.left &&
|
||||
$(this).offset().top+$(this).height()-container.top > 0 &&
|
||||
$(this).offset().top < container.height+container.top
|
||||
) return true;
|
||||
return false;
|
||||
}
|
||||
})(jQuery);
|
||||
4
htmlcov/jquery.min.js
generated
vendored
Normal file
4
htmlcov/jquery.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
htmlcov/jquery.tablesorter.min.js
generated
vendored
Normal file
2
htmlcov/jquery.tablesorter.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
htmlcov/keybd_closed.png
generated
Normal file
BIN
htmlcov/keybd_closed.png
generated
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 B |
BIN
htmlcov/keybd_open.png
generated
Normal file
BIN
htmlcov/keybd_open.png
generated
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 B |
1166
htmlcov/monopoly_py.html
generated
Normal file
1166
htmlcov/monopoly_py.html
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
htmlcov/status.json
generated
Normal file
1
htmlcov/status.json
generated
Normal file
@@ -0,0 +1 @@
|
||||
{"format":2,"version":"5.1","globals":"36313e81643a3db58cf1124f7f45ff7f","files":{"exceptions_py":{"hash":"24aac4ad890cd9eca3b48e798198f5aa","index":{"nums":[1,20,0,0,0,0,0],"html_filename":"exceptions_py.html","relative_filename":"exceptions.py"}},"monopoly_py":{"hash":"045e6cfe9ae9a903be5f67f8a34baa4d","index":{"nums":[1,485,0,250,0,0,0],"html_filename":"monopoly_py.html","relative_filename":"monopoly.py"}}}}
|
||||
124
htmlcov/style.css
generated
Normal file
124
htmlcov/style.css
generated
Normal file
@@ -0,0 +1,124 @@
|
||||
@charset "UTF-8";
|
||||
/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */
|
||||
/* Don't edit this .css file. Edit the .scss file instead! */
|
||||
html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
|
||||
|
||||
body { font-family: georgia, serif; font-size: 1em; }
|
||||
|
||||
html > body { font-size: 16px; }
|
||||
|
||||
p { font-size: .75em; line-height: 1.33333333em; }
|
||||
|
||||
table { border-collapse: collapse; }
|
||||
|
||||
td { vertical-align: top; }
|
||||
|
||||
table tr.hidden { display: none !important; }
|
||||
|
||||
p#no_rows { display: none; font-size: 1.2em; }
|
||||
|
||||
a.nav { text-decoration: none; color: inherit; }
|
||||
a.nav:hover { text-decoration: underline; color: inherit; }
|
||||
|
||||
#header { background: #f8f8f8; width: 100%; border-bottom: 1px solid #eee; }
|
||||
|
||||
.indexfile #footer { margin: 1em 3em; }
|
||||
|
||||
.pyfile #footer { margin: 1em 1em; }
|
||||
|
||||
#footer .content { padding: 0; font-size: 85%; font-family: verdana, sans-serif; color: #666666; font-style: italic; }
|
||||
|
||||
#index { margin: 1em 0 0 3em; }
|
||||
|
||||
#header .content { padding: 1em 3rem; }
|
||||
|
||||
h1 { font-size: 1.25em; display: inline-block; }
|
||||
|
||||
#filter_container { display: inline-block; float: right; margin: 0 2em 0 0; }
|
||||
#filter_container input { width: 10em; }
|
||||
|
||||
h2.stats { margin-top: .5em; font-size: 1em; }
|
||||
|
||||
.stats span { border: 1px solid; border-radius: .1em; padding: .1em .5em; margin: 0 .1em; cursor: pointer; border-color: #ccc #999 #999 #ccc; }
|
||||
.stats span.run { background: #eeffee; }
|
||||
.stats span.run.show_run { border-color: #999 #ccc #ccc #999; background: #ddffdd; }
|
||||
.stats span.mis { background: #ffeeee; }
|
||||
.stats span.mis.show_mis { border-color: #999 #ccc #ccc #999; background: #ffdddd; }
|
||||
.stats span.exc { background: #f7f7f7; }
|
||||
.stats span.exc.show_exc { border-color: #999 #ccc #ccc #999; background: #eeeeee; }
|
||||
.stats span.par { background: #ffffd5; }
|
||||
.stats span.par.show_par { border-color: #999 #ccc #ccc #999; background: #ffffaa; }
|
||||
|
||||
#source p .annotate.long, .help_panel { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; box-shadow: #cccccc .2em .2em .2em; color: #333; padding: .25em .5em; }
|
||||
|
||||
#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; }
|
||||
|
||||
#keyboard_icon { float: right; margin: 5px; cursor: pointer; }
|
||||
|
||||
.help_panel { padding: .5em; border: 1px solid #883; }
|
||||
.help_panel .legend { font-style: italic; margin-bottom: 1em; }
|
||||
.indexfile .help_panel { width: 20em; height: 4em; }
|
||||
.pyfile .help_panel { width: 16em; height: 8em; }
|
||||
|
||||
#panel_icon { float: right; cursor: pointer; }
|
||||
|
||||
.keyhelp { margin: .75em; }
|
||||
.keyhelp .key { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: monospace; font-weight: bold; background: #eee; }
|
||||
|
||||
#source { padding: 1em 0 1em 3rem; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
|
||||
#source p { position: relative; white-space: pre; }
|
||||
#source p * { box-sizing: border-box; }
|
||||
#source p .n { float: left; text-align: right; width: 3rem; box-sizing: border-box; margin-left: -3rem; padding-right: 1em; color: #999999; font-family: verdana, sans-serif; }
|
||||
#source p .n a { text-decoration: none; color: #999999; font-size: .8333em; line-height: 1em; }
|
||||
#source p .n a:hover { text-decoration: underline; color: #999999; }
|
||||
#source p.highlight .n { background: #ffdd00; }
|
||||
#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid white; }
|
||||
#source p .t:hover { background: #f2f2f2; }
|
||||
#source p .t:hover ~ .r .annotate.long { display: block; }
|
||||
#source p .t .com { color: green; font-style: italic; line-height: 1px; }
|
||||
#source p .t .key { font-weight: bold; line-height: 1px; }
|
||||
#source p .t .str { color: #000080; }
|
||||
#source p.mis .t { border-left: 0.2em solid #ff0000; }
|
||||
#source p.mis.show_mis .t { background: #ffdddd; }
|
||||
#source p.mis.show_mis .t:hover { background: #f2d2d2; }
|
||||
#source p.run .t { border-left: 0.2em solid #00ff00; }
|
||||
#source p.run.show_run .t { background: #ddffdd; }
|
||||
#source p.run.show_run .t:hover { background: #d2f2d2; }
|
||||
#source p.exc .t { border-left: 0.2em solid #808080; }
|
||||
#source p.exc.show_exc .t { background: #eeeeee; }
|
||||
#source p.exc.show_exc .t:hover { background: #e2e2e2; }
|
||||
#source p.par .t { border-left: 0.2em solid #eeee99; }
|
||||
#source p.par.show_par .t { background: #ffffaa; }
|
||||
#source p.par.show_par .t:hover { background: #f2f2a2; }
|
||||
#source p .r { position: absolute; top: 0; right: 2.5em; font-family: verdana, sans-serif; }
|
||||
#source p .annotate { font-family: georgia; color: #666; padding-right: .5em; }
|
||||
#source p .annotate.short:hover ~ .long { display: block; }
|
||||
#source p .annotate.long { width: 30em; right: 2.5em; }
|
||||
#source p input { display: none; }
|
||||
#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; }
|
||||
#source p input ~ .r label.ctx::before { content: "▶ "; }
|
||||
#source p input ~ .r label.ctx:hover { background: #d5f7ff; color: #666; }
|
||||
#source p input:checked ~ .r label.ctx { background: #aaeeff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; }
|
||||
#source p input:checked ~ .r label.ctx::before { content: "▼ "; }
|
||||
#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; }
|
||||
#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; }
|
||||
#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: verdana, sans-serif; white-space: nowrap; background: #aaeeff; border-radius: .25em; margin-right: 1.75em; }
|
||||
#source p .ctxs span { display: block; text-align: right; }
|
||||
|
||||
#index td, #index th { text-align: right; width: 5em; padding: .25em .5em; border-bottom: 1px solid #eee; }
|
||||
#index td.left, #index th.left { padding-left: 0; }
|
||||
#index td.right, #index th.right { padding-right: 0; }
|
||||
#index td.name, #index th.name { text-align: left; width: auto; }
|
||||
#index th { font-style: italic; color: #333; border-bottom: 1px solid #ccc; cursor: pointer; }
|
||||
#index th:hover { background: #eee; border-bottom: 1px solid #999; }
|
||||
#index th.headerSortDown, #index th.headerSortUp { border-bottom: 1px solid #000; white-space: nowrap; background: #eee; }
|
||||
#index th.headerSortDown:after { content: " ↓"; }
|
||||
#index th.headerSortUp:after { content: " ↑"; }
|
||||
#index td.name a { text-decoration: none; color: #000; }
|
||||
#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; }
|
||||
#index tr.file:hover { background: #eeeeee; }
|
||||
#index tr.file:hover td.name { text-decoration: underline; color: #000; }
|
||||
|
||||
#scroll_marker { position: fixed; right: 0; top: 0; width: 16px; height: 100%; background: white; border-left: 1px solid #eee; will-change: transform; }
|
||||
#scroll_marker .marker { background: #ddd; position: absolute; min-height: 3px; width: 100%; }
|
||||
331
monopoly.py
331
monopoly.py
@@ -4,31 +4,63 @@ Purpose:
|
||||
1) To simulate games of Monopoly in order to determine the best strategy
|
||||
2) To play Monopoly on a computer
|
||||
|
||||
|
||||
Along those lines, here's some prior art:
|
||||
|
||||
http://www.tkcs-collins.com/truman/monopoly/monopoly.shtml
|
||||
https://blog.ed.ted.com/2017/12/01/heres-how-to-win-at-monopoly-according-to-math-experts/
|
||||
|
||||
|
||||
# TODO: maybe instead of all these classmethods, instances?
|
||||
# TODO: something more graceful than Game.games[0]
|
||||
# TODO: store LAST_ROLL in a global constant instead of passing it around to all the `action` methods
|
||||
TODO: maybe instead of all these classmethods, instances?
|
||||
TODO: something more graceful than Game.games[0]
|
||||
TODO: store LAST_ROLL in a global constant instead of passing it around to all the `action` methods
|
||||
TODO: write some tests
|
||||
TODO: break up into modules
|
||||
TODO: add auctions
|
||||
TODO: print the reason someone decided to/not to buy a property
|
||||
TODO: print whether someone is in jail or just visiting
|
||||
TODO: don't allow buying of multiple houses/a hotel on a property if the other properties in the same color don't have any
|
||||
"""
|
||||
from abc import abstractmethod, ABC
|
||||
from abc import ABC
|
||||
from collections import defaultdict
|
||||
from itertools import cycle
|
||||
from random import shuffle, choice
|
||||
from random import choice, shuffle
|
||||
from time import sleep
|
||||
from typing import Type, NewType, Tuple, cast, List
|
||||
from typing import cast, List, NewType, Optional, Tuple, Type
|
||||
|
||||
from exceptions import TooManyPlayers, NotEnough, DidntFind, Argument, NoOwner, CantMortgage, \
|
||||
CantBuyBuildings, TooMany, MustBeEqualAmounts
|
||||
from exceptions import (
|
||||
Argument,
|
||||
CantBuyBuildings,
|
||||
CantMortgage,
|
||||
DidntFind,
|
||||
MustBeEqualAmounts,
|
||||
NoOwner,
|
||||
NotEnough,
|
||||
TooMany,
|
||||
TooManyPlayers,
|
||||
NotEnoughPlayers,
|
||||
)
|
||||
|
||||
ALL_MONEY = 20_580
|
||||
NUM_HOUSES = 32
|
||||
NUM_HOTELS = 12
|
||||
|
||||
Doubles = NewType("Doubles", bool)
|
||||
|
||||
LANGUAGE = "français"
|
||||
BACKUP_LANGUAGE = "English"
|
||||
BUILDING_TYPES = "house", "hotel"
|
||||
MAX_ROUNDS = 5000
|
||||
|
||||
BUILDABLE_PROPERTY_COLORS = (
|
||||
"yellow",
|
||||
"red",
|
||||
"light blue",
|
||||
"brown",
|
||||
"pink",
|
||||
"orange",
|
||||
"green",
|
||||
"dark blue",
|
||||
)
|
||||
|
||||
|
||||
class Space:
|
||||
@@ -45,6 +77,10 @@ class NothingHappensWhenYouLandOnItSpace(Space):
|
||||
|
||||
|
||||
class Go(NothingHappensWhenYouLandOnItSpace):
|
||||
"""
|
||||
should this really be a NothingHappensWhenYouLandOnItSpace?
|
||||
since you get to collect $200
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -61,6 +97,7 @@ class TaxSpace(Space):
|
||||
|
||||
@classmethod
|
||||
def action(cls, player, _):
|
||||
print(f"{player} pays bank {cls.amount} ({cls.__name__})")
|
||||
player.pay("Bank", cls.amount)
|
||||
|
||||
|
||||
@@ -123,8 +160,10 @@ class ElectedPresidentCard(Card):
|
||||
|
||||
@classmethod
|
||||
def action(cls, player, _):
|
||||
print("{cls.__name__}")
|
||||
for other_player in Game.games[0].active_players:
|
||||
if other_player != player:
|
||||
print(f"{player} is paying {other_player} 50")
|
||||
player.pay(other_player, 50)
|
||||
|
||||
|
||||
@@ -136,6 +175,7 @@ class GetOutOfJailFreeCard(Card):
|
||||
|
||||
@classmethod
|
||||
def action(cls, player: "Player", _):
|
||||
print(f"{player} got a get out of jail free card")
|
||||
player.get_out_of_jail_free_card = True
|
||||
|
||||
|
||||
@@ -145,6 +185,7 @@ class AdvanceCard(Card):
|
||||
|
||||
@classmethod
|
||||
def action(cls, player, _):
|
||||
print(f"the card is {cls.__name__}")
|
||||
player.advance(**cls.kwarg)
|
||||
|
||||
|
||||
@@ -186,6 +227,7 @@ class BuildingAndLoanMaturesCard(Card):
|
||||
|
||||
@classmethod
|
||||
def action(self, player, _):
|
||||
print(f"{self.__class__}: the bank pays {player} 150")
|
||||
Bank.pay(player, 150)
|
||||
|
||||
|
||||
@@ -195,18 +237,25 @@ class SpeedingCard(Card):
|
||||
|
||||
@classmethod
|
||||
def action(cls, player, _):
|
||||
print(f"{cls.__name__}: {player} pays 15 to Bank")
|
||||
player.pay(Bank, 15)
|
||||
|
||||
|
||||
class RepairPropertyCard(Card):
|
||||
text = {
|
||||
"français": "Vous faites des réparations sur toutes vos propriétés: Versez M25"
|
||||
" pour chaque maison M100 pour Chque hôtel que vous possédez"
|
||||
" pour chaque maison M100 pour Chaque hôtel que vous possédez"
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def action(cls, player, _):
|
||||
|
||||
num_houses, num_hotels = 0, 0
|
||||
for property in player.buildable_properties:
|
||||
num_houses += property.buildings["house"]
|
||||
num_hotels += property.buildings["hotel"]
|
||||
total_owed = sum([num_houses * 25, num_hotels * 100])
|
||||
print(f"{player} pays the bank {total_owed} for {cls.__name__}")
|
||||
player.pay(Bank, total_owed)
|
||||
|
||||
|
||||
class Deck:
|
||||
@@ -247,8 +296,6 @@ def shuffle_decks():
|
||||
|
||||
|
||||
def buy_decision(property: "Property", player: "Player"):
|
||||
if property.cost > player.assets:
|
||||
print(f"{player} doesn't have enough to buy {property}.")
|
||||
return Game.games[0].buy_decision_algorithm(property, player)
|
||||
|
||||
|
||||
@@ -269,9 +316,14 @@ class Property(Space):
|
||||
|
||||
def __repr__(self):
|
||||
if hasattr(self, "_name"):
|
||||
return self._name
|
||||
return self._name[LANGUAGE]
|
||||
return str(self.__class__)
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
for property in cls.instances:
|
||||
property.owner = None
|
||||
|
||||
@classmethod
|
||||
def get_num_of_type(cls, type):
|
||||
return len(cls.instances_by_type()[type])
|
||||
@@ -295,10 +347,16 @@ class Property(Space):
|
||||
if not self.owner:
|
||||
buy = buy_decision(self, player)
|
||||
if buy:
|
||||
print(f"{player} will buy {self}")
|
||||
return player.buy(self)
|
||||
if self.mortgaged:
|
||||
print(f"{player} decided not to buy {self}")
|
||||
return
|
||||
return player.pay(self.owner, self.calculate_rent(last_roll))
|
||||
if self.owner == player or self.mortgaged:
|
||||
print(f"{player} landed on his own property, {self}")
|
||||
return
|
||||
rent = self.calculate_rent(last_roll)
|
||||
print(f"{player} pays {self.owner} ${rent} after landing on it.")
|
||||
player.pay(self.owner, rent)
|
||||
|
||||
def calculate_rent(self, _):
|
||||
if not self.owner:
|
||||
@@ -320,7 +378,7 @@ class Utility(Property):
|
||||
super().calculate_rent(last_roll)
|
||||
if not last_roll:
|
||||
return 10 * Player.roll_the_dice()[0]
|
||||
return self.rent[self.owner.owns_x_of_type(self)](last_roll)
|
||||
return self.rent[self.owner.owns_x_of_type(self.type)](last_roll)
|
||||
|
||||
|
||||
class Railroad(Property):
|
||||
@@ -332,7 +390,7 @@ class Railroad(Property):
|
||||
|
||||
def calculate_rent(self, _):
|
||||
super().calculate_rent(_)
|
||||
owns_x_of_type = self.owner.owns_x_of_type(self)
|
||||
owns_x_of_type = self.owner.owns_x_of_type(self.type)
|
||||
if not owns_x_of_type:
|
||||
return 0
|
||||
return self.rent[owns_x_of_type]
|
||||
@@ -359,7 +417,7 @@ class BuildableProperty(Property):
|
||||
self.unmortgage_cost = unmortgage_cost
|
||||
self.buildings = {"house": 0, "hotel": 0}
|
||||
|
||||
def buy_buildings(self, building_type, quantity=None):
|
||||
def buy_building(self, building_type):
|
||||
"""
|
||||
TODO: Each property within a group must be no more than one house level away from all other
|
||||
properties in that group. For example, if you own the Orange group, you can’t put a
|
||||
@@ -369,17 +427,15 @@ class BuildableProperty(Property):
|
||||
"""
|
||||
if not self.owner.owns_all_type(self.type):
|
||||
raise CantBuyBuildings
|
||||
quantity = quantity or 1
|
||||
|
||||
if building_type == "hotel" and self.buildings["house"] != 4:
|
||||
raise NotEnough
|
||||
elif building_type == "house" and (self.buildings["house"] + quantity) > 4:
|
||||
elif building_type == "house" and self.buildings["house"] == 4:
|
||||
raise TooMany
|
||||
|
||||
total_buildings = quantity * self.num_of_type
|
||||
cost = self.house_and_hotel_cost * total_buildings
|
||||
cost = self.house_and_hotel_cost
|
||||
self.owner.check_funds(cost)
|
||||
Bank.get_buildings(building_type, total_buildings)
|
||||
Bank.get_building(building_type)
|
||||
self.owner.pay(Bank, cost)
|
||||
|
||||
for property_ in self.properties_of_type:
|
||||
@@ -387,12 +443,14 @@ class BuildableProperty(Property):
|
||||
property_.buildings["house"] = 0
|
||||
property_.buildings["hotel"] = 1
|
||||
else:
|
||||
property_.buildings["house"] += quantity
|
||||
property_.buildings["house"] += 1
|
||||
|
||||
def sell_buildings(self, building_type, quantity):
|
||||
if not self.buildings[building_type]:
|
||||
raise NotEnough
|
||||
if quantity % self.num_of_type:
|
||||
# TODO: this isn't right
|
||||
# https://www.quora.com/When-can-a-player-place-a-house-in-monopoly
|
||||
raise MustBeEqualAmounts
|
||||
|
||||
def mortgage(self, player: "Player"):
|
||||
@@ -407,8 +465,12 @@ class BuildableProperty(Property):
|
||||
|
||||
def calculate_rent(self, _):
|
||||
super().calculate_rent(_)
|
||||
if self.buildings:
|
||||
key = self.buildings
|
||||
if self.buildings["house"] or self.buildings["hotel"]:
|
||||
buildings = self.buildings
|
||||
if buildings["house"]:
|
||||
key = buildings["house"]
|
||||
else:
|
||||
key = "hotel"
|
||||
elif self.owner.owns_all_type(self.type):
|
||||
key = "monopoly"
|
||||
else:
|
||||
@@ -441,7 +503,7 @@ class Board:
|
||||
IncomeTax,
|
||||
Railroad(_name={"français": "Union des Chemins de Fer Privés"}),
|
||||
BuildableProperty(
|
||||
_name={"deutsche": "Aarau Rathausplatz"},
|
||||
_name={"français": "Aarau Rathausplatz"},
|
||||
cost=100,
|
||||
color="light blue",
|
||||
rent={0: 6, "monopoly": 12, 1: 30, 2: 90, 3: 270, 4: 400, "hotel": 550},
|
||||
@@ -478,7 +540,7 @@ class Board:
|
||||
mortgage_cost=70,
|
||||
unmortgage_cost=77,
|
||||
),
|
||||
Utility(_name="Usines Électriques"),
|
||||
Utility(_name={"français": "Usines Électriques"}),
|
||||
BuildableProperty(
|
||||
_name={"français": "Soleure Hauptgasse"},
|
||||
cost=140,
|
||||
@@ -489,7 +551,7 @@ class Board:
|
||||
unmortgage_cost=77,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"italian": "Lugano Via Nassa"},
|
||||
_name={"français": "Lugano Via Nassa"},
|
||||
cost=160,
|
||||
color="pink",
|
||||
rent={0: 12, "monopoly": 24, 1: 60, 2: 180, 3: 500, 4: 700, "hotel": 900},
|
||||
@@ -562,7 +624,7 @@ class Board:
|
||||
mortgage_cost=120,
|
||||
unmortgage_cost=132,
|
||||
),
|
||||
Railroad(_name="Tramways Interurbains"),
|
||||
Railroad(_name={"français": "Tramways Interurbains"}),
|
||||
BuildableProperty(
|
||||
_name={"français": "Lucerne Weggisgasse"},
|
||||
cost=260,
|
||||
@@ -597,7 +659,7 @@ class Board:
|
||||
mortgage_cost=130,
|
||||
unmortgage_cost=143,
|
||||
),
|
||||
Utility(_name="Usines Hydrauliques"),
|
||||
Utility(_name={"français": "Usines Hydrauliques"}),
|
||||
BuildableProperty(
|
||||
_name={"français": "Lausanne Rue de Bourg"},
|
||||
cost=280,
|
||||
@@ -668,7 +730,7 @@ class Board:
|
||||
mortgage_cost=160,
|
||||
unmortgage_cost=176,
|
||||
),
|
||||
Railroad(_name="Association des Télépheriques"),
|
||||
Railroad(_name={"français": "Association des Télépheriques"}),
|
||||
Chance,
|
||||
BuildableProperty(
|
||||
_name={"français": "Lausanne Place St. François"},
|
||||
@@ -726,36 +788,35 @@ def get_space_index(name):
|
||||
|
||||
|
||||
class EconomicActor:
|
||||
def __repr__(self):
|
||||
return f"<{self.name} money=${self.money}>"
|
||||
pass
|
||||
|
||||
|
||||
class Bank(EconomicActor):
|
||||
name = "Bank"
|
||||
money = 20_580
|
||||
NUM_HOUSES = 32
|
||||
NUM_HOTELS = 12
|
||||
money = ALL_MONEY
|
||||
NUM_HOUSES = NUM_HOUSES
|
||||
NUM_HOTELS = NUM_HOTELS
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
cls.money = ALL_MONEY
|
||||
cls.NUM_HOUSES = NUM_HOUSES
|
||||
cls.NUM_HOTELS = NUM_HOTELS
|
||||
|
||||
@classmethod
|
||||
def pay(cls, actor: "EconomicActor", amount: int):
|
||||
if isinstance(actor, str):
|
||||
actor = eval(actor)
|
||||
if amount > cls.money:
|
||||
raise NotEnough
|
||||
cls.money -= amount
|
||||
actor.money += amount
|
||||
|
||||
@classmethod
|
||||
def get_buildings(cls, type_, quantity=None):
|
||||
def get_building(cls, type_):
|
||||
cls.check_building_type(type_)
|
||||
to_check = cls.get_building_store(type_)
|
||||
if type_ == "hotel":
|
||||
quantity = 1
|
||||
|
||||
if to_check < quantity:
|
||||
store = cls.get_building_store(type_)
|
||||
if not store:
|
||||
raise NotEnough(f"Not enough {type_}s!")
|
||||
else:
|
||||
to_check -= quantity
|
||||
store -= 1
|
||||
|
||||
@classmethod
|
||||
def put_building(cls, type_, quantity):
|
||||
@@ -800,6 +861,60 @@ class GetOutOfJailDecision(Decision):
|
||||
pass
|
||||
|
||||
|
||||
def get_property_with_least_number_of_houses(properties):
|
||||
return sorted(properties, key=lambda prop: prop.buildings["house"], reverse=True)[0]
|
||||
|
||||
|
||||
def get_property_with_no_hotels(properties):
|
||||
return sorted(properties, key=lambda prop: prop.buildings["hotel"])[0]
|
||||
|
||||
|
||||
class Monopoly:
|
||||
def __init__(self, property_: "BuildableProperty"):
|
||||
self.properties = Property.instances_by_type()[property_.type]
|
||||
self.num_properties = len(self.properties)
|
||||
self.max_num_houses = 4 * self.num_properties
|
||||
self.max_num_hotels = self.num_properties
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Monopoly type={self.properties[0].type}"
|
||||
|
||||
@property
|
||||
def num_houses(self):
|
||||
return sum(property.buildings["house"] for property in self.properties)
|
||||
|
||||
@property
|
||||
def num_hotels(self):
|
||||
return sum(property.buildings["hotel"] for property in self.properties)
|
||||
|
||||
@property
|
||||
def next_building(self) -> Tuple[Optional[str], Optional["BuildableProperty"]]:
|
||||
num_houses, num_hotels, max_num_houses, max_num_hotels = (
|
||||
self.num_houses,
|
||||
self.num_hotels,
|
||||
self.max_num_houses,
|
||||
self.max_num_hotels,
|
||||
)
|
||||
first_prop = self.properties[0]
|
||||
|
||||
if not num_houses and not num_hotels:
|
||||
return "house", first_prop
|
||||
|
||||
elif num_hotels == max_num_hotels:
|
||||
return None, None
|
||||
|
||||
elif num_houses < max_num_houses:
|
||||
if not num_hotels:
|
||||
return (
|
||||
"house",
|
||||
get_property_with_least_number_of_houses(self.properties),
|
||||
)
|
||||
else:
|
||||
return "hotel", get_property_with_no_hotels(self.properties)
|
||||
elif num_houses == max_num_houses:
|
||||
return "hotel", first_prop
|
||||
|
||||
|
||||
class Player(EconomicActor):
|
||||
in_jail = False
|
||||
bankrupt = False
|
||||
@@ -807,17 +922,20 @@ class Player(EconomicActor):
|
||||
go_again = False
|
||||
current_space_index = get_space_index("Go")
|
||||
money = 0
|
||||
passed_go_times = 0
|
||||
monopolies = []
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __init__(self):
|
||||
self.name = choice([str(i) for i in range(10_000)])
|
||||
Bank.pay(self, 1_500)
|
||||
|
||||
def pay(self, actor: Type["EconomicActor"], amount: int):
|
||||
if isinstance(actor, str):
|
||||
actor = eval(actor)
|
||||
print(actor, amount, self.money)
|
||||
self.check_funds(amount)
|
||||
print(f"{self} is paying {actor} ${amount}")
|
||||
self.money -= amount
|
||||
actor.money += amount
|
||||
|
||||
@@ -829,16 +947,46 @@ class Player(EconomicActor):
|
||||
try:
|
||||
self.pay(from_, cost or property_.cost)
|
||||
except NotEnough:
|
||||
print(f"{self.name} does not have enough to buy {property_._name}")
|
||||
return
|
||||
property_.owner = self
|
||||
print(f"{self.name} bought {property_._name}")
|
||||
sleep(0.2)
|
||||
|
||||
if property_.__class__.__name__ == "BuildableProperty" and self.owns_all_type(
|
||||
property_.type
|
||||
):
|
||||
monopoly = Monopoly(property_)
|
||||
self.monopolies.append(monopoly)
|
||||
|
||||
def buy_buildings_if_possible(self):
|
||||
if self.monopolies:
|
||||
print(f"{self} has {self.monopolies}")
|
||||
else:
|
||||
print(f"{self} has no monopolies.")
|
||||
for monopoly in self.monopolies:
|
||||
while True:
|
||||
next_building_type, property_ = monopoly.next_building
|
||||
if not next_building_type:
|
||||
break
|
||||
print("next_building_type:", next_building_type, "property_:", property_)
|
||||
if not self.can_afford(property_.house_and_hotel_cost):
|
||||
print("can't afford")
|
||||
break
|
||||
try:
|
||||
property_.buy_building(next_building_type)
|
||||
except NotEnough:
|
||||
print("can't afford")
|
||||
break
|
||||
print("bought a building")
|
||||
|
||||
def take_a_turn(self):
|
||||
if self.in_jail:
|
||||
return GetOutOfJailDecision(self)
|
||||
print(f"{self} is in jail")
|
||||
decision = GetOutOfJailDecision(self)
|
||||
print(decision)
|
||||
return decision
|
||||
# TODO: you can buy buildings from jail! Fix this
|
||||
self.buy_buildings_if_possible()
|
||||
num_spaces, doubles = self.roll_the_dice()
|
||||
print(f'{self} rolled', str(num_spaces))
|
||||
if doubles:
|
||||
self.go_again = True
|
||||
else:
|
||||
@@ -848,12 +996,14 @@ class Player(EconomicActor):
|
||||
|
||||
def owns_x_of_type(self, type_):
|
||||
properties_of_this_type = self.properties_by_type.get(type_)
|
||||
if properties_of_this_type is None:
|
||||
return 0
|
||||
if properties_of_this_type is None:
|
||||
return 0
|
||||
return len(properties_of_this_type)
|
||||
|
||||
def owns_all_type(self, type_):
|
||||
return self.owns_x_of_type(type_) == Property.get_num_of_type(type)
|
||||
return self.owns_x_of_type(type_) == Property.get_num_of_type(type_)
|
||||
|
||||
@property
|
||||
def properties_by_type(self):
|
||||
@@ -884,6 +1034,12 @@ class Player(EconomicActor):
|
||||
# then iterate through those instances to see which ones have an owner equal to `self`
|
||||
return [p for p in Property.instances if p.owner == self]
|
||||
|
||||
@property
|
||||
def buildable_properties(self) -> List[BuildableProperty]:
|
||||
return [
|
||||
p for p in self.properties if p.__class__.__name__ == "BuildableProperty"
|
||||
]
|
||||
|
||||
def advance(
|
||||
self,
|
||||
num_spaces=None,
|
||||
@@ -907,10 +1063,15 @@ class Player(EconomicActor):
|
||||
|
||||
if pass_go and new_space_index >= Board.NUM_SPACES - 1:
|
||||
self.money += 200
|
||||
print(f"{self} passed go and collected 200")
|
||||
self.passed_go_times += 1
|
||||
new_space_index = new_space_index - Board.NUM_SPACES
|
||||
elif pass_go and self.current_space_index > new_space_index:
|
||||
self.money += 200
|
||||
print(f"{self} passed go and collected 200")
|
||||
self.passed_go_times += 1
|
||||
|
||||
print("new_space_index", str(new_space_index))
|
||||
self.current_space_index = new_space_index
|
||||
|
||||
if just_rolled:
|
||||
@@ -923,55 +1084,69 @@ class Player(EconomicActor):
|
||||
except NotEnough:
|
||||
# TODO: is this always right?
|
||||
# TODO: eventually make deals and mortgage prtoperties to avoid bankruptcy
|
||||
print(f"{self.name} went bankrupt!")
|
||||
self.bankrupt = True
|
||||
print(f"{self} just went bankrupt!")
|
||||
|
||||
def do_action_of_current_space(self, last_roll=None):
|
||||
space = Board.spaces[self.current_space_index]
|
||||
print(f"space is {space}")
|
||||
space.action(self, last_roll)
|
||||
|
||||
def go_to_jail(self):
|
||||
self.in_jail = True
|
||||
self.current_space_index = get_space_index("Jail")
|
||||
|
||||
def can_afford(self, cost):
|
||||
return self.money >= cost
|
||||
|
||||
|
||||
class Game:
|
||||
games = []
|
||||
rounds = 0
|
||||
|
||||
def __init__(self, *player_names, buy_decision_algorithm=None):
|
||||
def return_true(_, __):
|
||||
return True
|
||||
|
||||
self.buy_decision_algorithm = buy_decision_algorithm or return_true
|
||||
def __init__(self, num_players, buy_decision_algorithm, slow_down=False):
|
||||
self.slow_down = slow_down
|
||||
Bank.reset()
|
||||
shuffle_decks()
|
||||
Property.reset()
|
||||
self.buy_decision_algorithm = buy_decision_algorithm()
|
||||
# TODO: make this nicer
|
||||
if self.games:
|
||||
del self.games[0]
|
||||
self.games.append(self)
|
||||
if len(player_names) > 8:
|
||||
if num_players < 2:
|
||||
raise NotEnoughPlayers
|
||||
if num_players > 8:
|
||||
raise TooManyPlayers
|
||||
self._players = [Player(player_name) for player_name in player_names]
|
||||
self._players = [Player() for _ in range(num_players)]
|
||||
self.players = cycle(self._players)
|
||||
# TODO: roll to see who goes first, then order the players accordingly
|
||||
shuffle_decks()
|
||||
self.next()
|
||||
self.start()
|
||||
|
||||
@property
|
||||
def active_players(self):
|
||||
return [player for player in self._players if not player.bankrupt]
|
||||
|
||||
def next(self):
|
||||
while len(self.active_players) > 1:
|
||||
def start(self):
|
||||
while len(self.active_players) > 1 and self.rounds < MAX_ROUNDS:
|
||||
current_player = next(self.players)
|
||||
if not current_player.bankrupt:
|
||||
if self.slow_down:
|
||||
sleep(3)
|
||||
print()
|
||||
print()
|
||||
current_player.take_a_turn()
|
||||
while current_player.go_again:
|
||||
while current_player.go_again and not current_player.bankrupt:
|
||||
if self.slow_down:
|
||||
sleep(3)
|
||||
print()
|
||||
print()
|
||||
current_player.take_a_turn()
|
||||
self.rounds += 1
|
||||
if self.rounds > 500:
|
||||
break
|
||||
self.end()
|
||||
|
||||
def get_rounds_played_per_player(self):
|
||||
return self.rounds / len(self._players)
|
||||
|
||||
def end(self):
|
||||
print(self.active_players[0], "is the winner!")
|
||||
print(f"It took {self.rounds} rounds.")
|
||||
|
||||
|
||||
game = Game("Bot", "Ro", "Francis", buy_decision_algorithm=None)
|
||||
for player in self._players:
|
||||
del player
|
||||
|
||||
49
simulate.py
Normal file
49
simulate.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import random
|
||||
import statistics
|
||||
from collections import defaultdict
|
||||
|
||||
from monopoly import Game
|
||||
from buy_decision_algos import BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned
|
||||
|
||||
|
||||
def get_results(results, game, attrs_to_get):
|
||||
for attr in attrs_to_get:
|
||||
attr_obj = getattr(game, attr)
|
||||
if callable(attr_obj):
|
||||
val = attr_obj()
|
||||
else:
|
||||
val = attr_obj
|
||||
results[attr].append(val)
|
||||
|
||||
|
||||
def print_results(results, num_players):
|
||||
for attr, results_list in results.items():
|
||||
mean = statistics.mean(results_list)
|
||||
std_dev = statistics.stdev(results_list)
|
||||
print(
|
||||
f"num_players -> {num_players}, mean -> {int(mean)}, stdev -> {int(std_dev)}"
|
||||
)
|
||||
|
||||
|
||||
def play_x_games(
|
||||
num_games=200,
|
||||
num_players=range(2, 9),
|
||||
buy_decision_algorithms=(BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned,),
|
||||
attrs_to_get=("get_rounds_played_per_player",),
|
||||
slow_down=False,
|
||||
):
|
||||
for buy_decision_algorithm in buy_decision_algorithms:
|
||||
results = defaultdict(list)
|
||||
|
||||
print(buy_decision_algorithm.__name__)
|
||||
print(buy_decision_algorithm.__doc__)
|
||||
print("num games per simulation:", str(num_games))
|
||||
print("attrs to get:", attrs_to_get)
|
||||
|
||||
for num_players_ in num_players:
|
||||
for i in range(num_games):
|
||||
game = Game(num_players_, buy_decision_algorithm=buy_decision_algorithm, slow_down=slow_down)
|
||||
get_results(results, game, attrs_to_get)
|
||||
game.end()
|
||||
|
||||
print_results(results, num_players_)
|
||||
316
tags
Normal file
316
tags
Normal file
@@ -0,0 +1,316 @@
|
||||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||
ALL_MONEY monopoly.py /^ALL_MONEY = 20_580$/;" v
|
||||
AdvanceCard monopoly.py /^class AdvanceCard(Card):$/;" c
|
||||
AdvanceThreeSpacesCard monopoly.py /^class AdvanceThreeSpacesCard(AdvanceCard):$/;" c
|
||||
Argument exceptions.py /^class Argument(Exception):$/;" c
|
||||
BACKUP_LANGUAGE monopoly.py /^BACKUP_LANGUAGE = "English"$/;" v
|
||||
BUILDABLE_PROPERTY_COLORS monopoly.py /^BUILDABLE_PROPERTY_COLORS = ($/;" v
|
||||
BUILDING_TYPES monopoly.py /^BUILDING_TYPES = "house", "hotel"$/;" v
|
||||
Bank monopoly.py /^class Bank(EconomicActor):$/;" c
|
||||
Board monopoly.py /^class Board:$/;" c
|
||||
BuildableProperty monopoly.py /^class BuildableProperty(Property):$/;" c
|
||||
BuildingAndLoanMaturesCard monopoly.py /^class BuildingAndLoanMaturesCard(Card):$/;" c
|
||||
BuyDecision buy_decision_algos.py /^class BuyDecision(ABC):$/;" c
|
||||
BuyEverything buy_decision_algos.py /^class BuyEverything(BuyDecision):$/;" c
|
||||
BuyIfDontHaveTwoPartialMonopoliesOfOtherColors buy_decision_algos.py /^class BuyIfDontHaveTwoPartialMonopoliesOfOtherColors(BuyDecision):$/;" c
|
||||
BuyIfHaveThreeTimesPrice buy_decision_algos.py /^class BuyIfHaveThreeTimesPrice(BuyDecision):$/;" c
|
||||
BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned buy_decision_algos.py /^class BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned(BuyDecision):$/;" c
|
||||
BuyIfOwnFewerThanFivePropertiesOrHaveOneOfThisColor buy_decision_algos.py /^class BuyIfOwnFewerThanFivePropertiesOrHaveOneOfThisColor(BuyDecision):$/;" c
|
||||
CantBuyBuildings exceptions.py /^class CantBuyBuildings(Exception):$/;" c
|
||||
CantMortgage exceptions.py /^class CantMortgage(Exception):$/;" c
|
||||
Card monopoly.py /^class Card(ABC):$/;" c
|
||||
CardSpace monopoly.py /^class CardSpace(Space):$/;" c
|
||||
Chance monopoly.py /^class Chance(CardSpace):$/;" c
|
||||
ChanceDeck monopoly.py /^class ChanceDeck(Deck):$/;" c
|
||||
CommunityChest monopoly.py /^class CommunityChest(CardSpace):$/;" c
|
||||
CommunityChestDeck monopoly.py /^class CommunityChestDeck(Deck):$/;" c
|
||||
Decision monopoly.py /^class Decision:$/;" c
|
||||
Deck monopoly.py /^class Deck:$/;" c
|
||||
DidntFind exceptions.py /^class DidntFind(Exception):$/;" c
|
||||
Doubles monopoly.py /^Doubles = NewType("Doubles", bool)$/;" v
|
||||
EconomicActor monopoly.py /^class EconomicActor:$/;" c
|
||||
ElectedPresidentCard monopoly.py /^class ElectedPresidentCard(Card):$/;" c
|
||||
FreeParking monopoly.py /^class FreeParking(NothingHappensWhenYouLandOnItSpace):$/;" c
|
||||
Game monopoly.py /^class Game:$/;" c
|
||||
GetOutOfJailDecision monopoly.py /^class GetOutOfJailDecision(Decision):$/;" c
|
||||
GetOutOfJailFreeCard monopoly.py /^class GetOutOfJailFreeCard(Card):$/;" c
|
||||
Go monopoly.py /^class Go(NothingHappensWhenYouLandOnItSpace):$/;" c
|
||||
GoToBernPlaceFederaleCard monopoly.py /^class GoToBernPlaceFederaleCard(AdvanceCard):$/;" c
|
||||
GoToClosestRailroadCard monopoly.py /^class GoToClosestRailroadCard(AdvanceCard):$/;" c
|
||||
GoToJail monopoly.py /^class GoToJail(Space):$/;" c
|
||||
GoToJailCard monopoly.py /^class GoToJailCard(AdvanceCard):$/;" c
|
||||
IncomeTax monopoly.py /^class IncomeTax(TaxSpace):$/;" c
|
||||
Jail monopoly.py /^class Jail(NothingHappensWhenYouLandOnItSpace):$/;" c
|
||||
LANGUAGE monopoly.py /^LANGUAGE = "français"$/;" v
|
||||
LuxuryTax monopoly.py /^class LuxuryTax(TaxSpace):$/;" c
|
||||
MAX_ROUNDS monopoly.py /^MAX_ROUNDS = 5000$/;" v
|
||||
Monopoly monopoly.py /^class Monopoly:$/;" c
|
||||
MustBeEqualAmounts exceptions.py /^class MustBeEqualAmounts(Exception):$/;" c
|
||||
NUM_HOTELS monopoly.py /^ NUM_HOTELS = NUM_HOTELS$/;" v class:Bank
|
||||
NUM_HOTELS monopoly.py /^NUM_HOTELS = 12$/;" v
|
||||
NUM_HOUSES monopoly.py /^ NUM_HOUSES = NUM_HOUSES$/;" v class:Bank
|
||||
NUM_HOUSES monopoly.py /^NUM_HOUSES = 32$/;" v
|
||||
NUM_SPACES monopoly.py /^ NUM_SPACES = len(spaces)$/;" v class:Board
|
||||
NoOwner exceptions.py /^class NoOwner(Exception):$/;" c
|
||||
NotEnough exceptions.py /^class NotEnough(Exception):$/;" c
|
||||
NotEnoughPlayers exceptions.py /^class NotEnoughPlayers(NotEnough):$/;" c
|
||||
NothingHappensWhenYouLandOnItSpace monopoly.py /^class NothingHappensWhenYouLandOnItSpace(Space):$/;" c
|
||||
Player monopoly.py /^class Player(EconomicActor):$/;" c
|
||||
Property monopoly.py /^class Property(Space):$/;" c
|
||||
Railroad monopoly.py /^class Railroad(Property):$/;" c
|
||||
RepairPropertyCard monopoly.py /^class RepairPropertyCard(Card):$/;" c
|
||||
SPACES_DICT monopoly.py /^ SPACES_DICT = {}$/;" v class:Board
|
||||
Space monopoly.py /^class Space:$/;" c
|
||||
SpeedingCard monopoly.py /^class SpeedingCard(Card):$/;" c
|
||||
TaxSpace monopoly.py /^class TaxSpace(Space):$/;" c
|
||||
TooMany exceptions.py /^class TooMany(Exception):$/;" c
|
||||
TooManyPlayers exceptions.py /^class TooManyPlayers(TooMany):$/;" c
|
||||
Utility monopoly.py /^class Utility(Property):$/;" c
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, _, __):$/;" m class:BuyEverything file:
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, property_, player):$/;" m class:BuyIfNoOneOwnsTypeAndIsOfTheOneTypeOwned file:
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, property_, player):$/;" m class:BuyIfOwnFewerThanFivePropertiesOrHaveOneOfThisColor file:
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, property_: "Property", player: "Player"):$/;" m class:BuyDecision file:
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, property_: "Property", player: "Player"):$/;" m class:BuyIfDontHaveTwoPartialMonopoliesOfOtherColors file:
|
||||
__call__ buy_decision_algos.py /^ def __call__(self, property_: "Property", player: "Player"):$/;" m class:BuyIfHaveThreeTimesPrice file:
|
||||
__init__ monopoly.py /^ def __init__($/;" m class:BuildableProperty
|
||||
__init__ monopoly.py /^ def __init__(self):$/;" m class:Player
|
||||
__init__ monopoly.py /^ def __init__(self, _name):$/;" m class:Property
|
||||
__init__ monopoly.py /^ def __init__(self, num_players, buy_decision_algorithm, slow_down=False):$/;" m class:Game
|
||||
__init__ monopoly.py /^ def __init__(self, player: "Player"):$/;" m class:GetOutOfJailDecision
|
||||
__init__ monopoly.py /^ def __init__(self, property_: "BuildableProperty"):$/;" m class:Monopoly
|
||||
__repr__ monopoly.py /^ def __repr__(self):$/;" m class:Card file:
|
||||
__repr__ monopoly.py /^ def __repr__(self):$/;" m class:Monopoly file:
|
||||
__repr__ monopoly.py /^ def __repr__(self):$/;" m class:Property file:
|
||||
__repr__ monopoly.py /^ def __repr__(self):$/;" m class:Space file:
|
||||
__str__ monopoly.py /^ def __str__(self):$/;" m class:Player file:
|
||||
_name monopoly.py /^ _name={"français": "Aarau Rathausplatz"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Berne Place Fédérale"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Berne Spitalgasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Bienne Rue De Nidau"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Bâle Freie Strasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Bâle Steinen-Vorstadt"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Coire Kornplatz"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Fribourg Avenue de la Gare"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Genève Rue de la Croix-D'Or"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "La Chaux-de-Fonds Avenue Louis-Robert"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Lausanne Place St. François"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Lausanne Rue de Bourg"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Lucerne Weggisgasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Lugano Via Nassa"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Neuchâtel Place Pury"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Schaffhouse Vordergasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Soleure Hauptgasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "St-Gall Markplatz"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Thoune Hauptgasse"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Winterthour Bahnhofplatz"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Zurich Paradeplatz"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name={"français": "Zurich Rennweg"},$/;" v class:Board
|
||||
_name monopoly.py /^ _name = {"français": "Chance", "deutsch": "Chance", "English": "Chance"}$/;" v class:Chance
|
||||
_name monopoly.py /^ _name = {"français": "Chancellerie", "deutsch": "Kanzlei"}$/;" v class:CommunityChest
|
||||
_name monopoly.py /^ _name = {"français": "Impôt Supplémentaire", "deutsch": "Nachsteuer"}$/;" v class:LuxuryTax
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:AdvanceCard
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:CardSpace
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:ElectedPresidentCard
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:GoToJail
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:RepairPropertyCard
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:SpeedingCard
|
||||
action monopoly.py /^ def action(cls, player, _):$/;" m class:TaxSpace
|
||||
action monopoly.py /^ def action(cls, player: "Player", _):$/;" m class:GetOutOfJailFreeCard
|
||||
action monopoly.py /^ def action(self, player, _):$/;" m class:BuildingAndLoanMaturesCard
|
||||
action monopoly.py /^ def action(self, player: "Player", _):$/;" m class:Card
|
||||
action monopoly.py /^ def action(self, player: "Player", _):$/;" m class:NothingHappensWhenYouLandOnItSpace
|
||||
action monopoly.py /^ def action(self, player: "Player", last_roll=None):$/;" m class:Property
|
||||
active_players monopoly.py /^ def active_players(self):$/;" m class:Game
|
||||
advance monopoly.py /^ def advance($/;" m class:Player
|
||||
amount monopoly.py /^ amount = 100$/;" v class:IncomeTax
|
||||
amount monopoly.py /^ amount = 75$/;" v class:LuxuryTax
|
||||
amount monopoly.py /^ amount = None$/;" v class:TaxSpace
|
||||
assets monopoly.py /^ def assets(self):$/;" m class:Player
|
||||
bankrupt monopoly.py /^ bankrupt = False$/;" v class:Player
|
||||
buildable_properties monopoly.py /^ def buildable_properties(self) -> List[BuildableProperty]:$/;" m class:Player
|
||||
buy monopoly.py /^ def buy(self, property_: "Property", from_=Bank, cost=None):$/;" m class:Player
|
||||
buy_building monopoly.py /^ def buy_building(self, building_type):$/;" m class:BuildableProperty
|
||||
buy_buildings_if_possible monopoly.py /^ def buy_buildings_if_possible(self):$/;" m class:Player
|
||||
buy_decision monopoly.py /^def buy_decision(property: "Property", player: "Player"):$/;" f
|
||||
calculate_rent monopoly.py /^ def calculate_rent(self, _):$/;" m class:BuildableProperty
|
||||
calculate_rent monopoly.py /^ def calculate_rent(self, _):$/;" m class:Property
|
||||
calculate_rent monopoly.py /^ def calculate_rent(self, _):$/;" m class:Railroad
|
||||
calculate_rent monopoly.py /^ def calculate_rent(self, last_roll: int):$/;" m class:Utility
|
||||
can_afford monopoly.py /^ def can_afford(self, cost):$/;" m class:Player
|
||||
check_args monopoly.py /^def check_args(num_spaces, space_index, until_space_type):$/;" f
|
||||
check_building_type monopoly.py /^ def check_building_type(type_):$/;" m class:Bank
|
||||
check_funds monopoly.py /^ def check_funds(self, amount):$/;" m class:Player
|
||||
color monopoly.py /^ color="brown",$/;" v class:Board
|
||||
color monopoly.py /^ color="dark blue",$/;" v class:Board
|
||||
color monopoly.py /^ color="green",$/;" v class:Board
|
||||
color monopoly.py /^ color="light blue",$/;" v class:Board
|
||||
color monopoly.py /^ color="orange",$/;" v class:Board
|
||||
color monopoly.py /^ color="pink",$/;" v class:Board
|
||||
color monopoly.py /^ color="red",$/;" v class:Board
|
||||
color monopoly.py /^ color="yellow",$/;" v class:Board
|
||||
cost monopoly.py /^ cost=100,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=120,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=140,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=160,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=180,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=200,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=220,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=240,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=260,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=280,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=300,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=320,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=350,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=400,$/;" v class:Board
|
||||
cost monopoly.py /^ cost=60,$/;" v class:Board
|
||||
cost monopoly.py /^ cost = 0$/;" v class:Property
|
||||
cost monopoly.py /^ cost = 200$/;" v class:Railroad
|
||||
cost monopoly.py /^ cost = 200$/;" v class:Utility
|
||||
cost monopoly.py /^ cost = None$/;" v class:Card
|
||||
current_space_index monopoly.py /^ current_space_index = get_space_index("Go")$/;" v class:Player
|
||||
deck monopoly.py /^ deck = "ChanceDeck"$/;" v class:Chance
|
||||
deck monopoly.py /^ deck = "CommunityChestDeck"$/;" v class:CommunityChest
|
||||
deck monopoly.py /^ deck = None$/;" v class:CardSpace
|
||||
deck monopoly.py /^ deck = None$/;" v class:Deck
|
||||
deck monopoly.py /^ deck = [$/;" v class:ChanceDeck
|
||||
deck monopoly.py /^ deck = [GoToJailCard, SpeedingCard]$/;" v class:CommunityChestDeck
|
||||
do_action_of_current_space monopoly.py /^ def do_action_of_current_space(self, last_roll=None):$/;" m class:Player
|
||||
end monopoly.py /^ def end(self):$/;" m class:Game
|
||||
game simulate.py /^ game = Game(num_players_, buy_decision_algorithm=buy_decision_algorithm, slow_down=slow_down)$/;" v
|
||||
games monopoly.py /^ games = []$/;" v class:Game
|
||||
get_building monopoly.py /^ def get_building(cls, type_):$/;" m class:Bank
|
||||
get_building_store monopoly.py /^ def get_building_store(cls, type_):$/;" m class:Bank
|
||||
get_card monopoly.py /^ def get_card(cls):$/;" m class:Deck
|
||||
get_index_of_next_space_of_type monopoly.py /^def get_index_of_next_space_of_type(current_space_index, until_space_type):$/;" f
|
||||
get_num_of_type monopoly.py /^ def get_num_of_type(cls, type):$/;" m class:Property
|
||||
get_out_of_jail_free_card monopoly.py /^ get_out_of_jail_free_card = False$/;" v class:Player
|
||||
get_property_with_least_number_of_houses monopoly.py /^def get_property_with_least_number_of_houses(properties):$/;" f
|
||||
get_property_with_no_hotels monopoly.py /^def get_property_with_no_hotels(properties):$/;" f
|
||||
get_results simulate.py /^def get_results(results, game, attrs_to_get):$/;" f
|
||||
get_rounds_played_per_player monopoly.py /^ def get_rounds_played_per_player(self):$/;" m class:Game
|
||||
get_space_index monopoly.py /^def get_space_index(name):$/;" f
|
||||
go_again monopoly.py /^ go_again = False$/;" v class:Player
|
||||
go_to_jail monopoly.py /^ def go_to_jail(self):$/;" m class:Player
|
||||
house_and_hotel_cost monopoly.py /^ house_and_hotel_cost=100,$/;" v class:Board
|
||||
house_and_hotel_cost monopoly.py /^ house_and_hotel_cost=150,$/;" v class:Board
|
||||
house_and_hotel_cost monopoly.py /^ house_and_hotel_cost=200,$/;" v class:Board
|
||||
house_and_hotel_cost monopoly.py /^ house_and_hotel_cost=50,$/;" v class:Board
|
||||
in_jail monopoly.py /^ in_jail = False$/;" v class:Player
|
||||
instances monopoly.py /^ instances = []$/;" v class:Property
|
||||
instances_by_type monopoly.py /^ def instances_by_type(cls):$/;" m class:Property
|
||||
keep monopoly.py /^ keep = False$/;" v class:Card
|
||||
kwarg monopoly.py /^ kwarg = {"num_spaces": 3}$/;" v class:AdvanceThreeSpacesCard
|
||||
kwarg monopoly.py /^ kwarg = {"space_index": "Berne Place Fédérale"}$/;" v class:GoToBernPlaceFederaleCard
|
||||
kwarg monopoly.py /^ kwarg = {"until_space_type": "Jail", "pass_go": False}$/;" v class:GoToJailCard
|
||||
kwarg monopoly.py /^ kwarg = {"until_space_type": "Railroad"}$/;" v class:GoToClosestRailroadCard
|
||||
kwarg monopoly.py /^ kwarg = {}$/;" v class:AdvanceCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = False$/;" v class:Card
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:AdvanceCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:AdvanceThreeSpacesCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:BuildingAndLoanMaturesCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:ElectedPresidentCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:GoToBernPlaceFederaleCard
|
||||
mandatory_action monopoly.py /^ mandatory_action = True$/;" v class:SpeedingCard
|
||||
money monopoly.py /^ money = 0$/;" v class:Player
|
||||
money monopoly.py /^ money = ALL_MONEY$/;" v class:Bank
|
||||
monopolies monopoly.py /^ monopolies = []$/;" v class:Player
|
||||
mortgage monopoly.py /^ def mortgage(self, player: "Player"):$/;" m class:BuildableProperty
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=100,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=110,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=120,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=130,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=140,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=150,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=160,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=175,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=200,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=30,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=50,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=60,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=70,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=80,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost=90,$/;" v class:Board
|
||||
mortgage_cost monopoly.py /^ mortgage_cost = 100$/;" v class:Railroad
|
||||
mortgage_cost monopoly.py /^ mortgage_cost = 75$/;" v class:Utility
|
||||
mortgaged monopoly.py /^ mortgaged = False$/;" v class:Property
|
||||
next_building monopoly.py /^ def next_building(self) -> Tuple[Optional[str], Optional["BuildableProperty"]]:$/;" m class:Monopoly
|
||||
num_hotels monopoly.py /^ def num_hotels(self):$/;" m class:Monopoly
|
||||
num_houses monopoly.py /^ def num_houses(self):$/;" m class:Monopoly
|
||||
num_of_type monopoly.py /^ def num_of_type(self):$/;" m class:Property
|
||||
owner monopoly.py /^ owner = None$/;" v class:Property
|
||||
owns_all_type monopoly.py /^ def owns_all_type(self, type_):$/;" m class:Player
|
||||
owns_x_of_type monopoly.py /^ def owns_x_of_type(self, type_):$/;" m class:Player
|
||||
passed_go_times monopoly.py /^ passed_go_times = 0$/;" v class:Player
|
||||
pay monopoly.py /^ def pay(cls, actor: "EconomicActor", amount: int):$/;" m class:Bank
|
||||
pay monopoly.py /^ def pay(self, actor: Type["EconomicActor"], amount: int):$/;" m class:Player
|
||||
play_x_games simulate.py /^def play_x_games($/;" f
|
||||
print_results simulate.py /^def print_results(results, num_players):$/;" f
|
||||
properties monopoly.py /^ def properties(self) -> List["Property"]:$/;" m class:Player
|
||||
properties_by_type monopoly.py /^ def properties_by_type(self):$/;" m class:Player
|
||||
properties_of_type monopoly.py /^ def properties_of_type(self):$/;" m class:Property
|
||||
put_building monopoly.py /^ def put_building(cls, type_, quantity):$/;" m class:Bank
|
||||
rent monopoly.py /^ rent={$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 10, "monopoly": 20, 1: 50, 2: 150, 3: 450, 4: 625, "hotel": 750},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 12, "monopoly": 24, 1: 60, 2: 180, 3: 500, 4: 700, "hotel": 900},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 14, "monopoly": 28, 1: 70, 2: 200, 3: 550, 4: 750, "hotel": 950},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 16, "monopoly": 32, 1: 80, 2: 220, 3: 600, 4: 800, "hotel": 1_000},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 18, "monopoly": 39, 1: 90, 2: 250, 3: 700, 4: 875, "hotel": 1_050},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 2, "monopoly": 4, 1: 10, 2: 30, 3: 90, 4: 160, "hotel": 250},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 4, "monopoly": 8, 1: 20, 2: 60, 3: 180, 4: 320, "hotel": 450},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 6, "monopoly": 12, 1: 30, 2: 90, 3: 270, 4: 400, "hotel": 550},$/;" v class:Board
|
||||
rent monopoly.py /^ rent={0: 8, "monopoly": 16, 1: 30, 2: 100, 3: 300, 4: 400, "hotel": 600},$/;" v class:Board
|
||||
rent monopoly.py /^ rent = {$/;" v class:Utility
|
||||
rent monopoly.py /^ rent = {1: 25, 2: 50, 3: 100, 4: 200}$/;" v class:Railroad
|
||||
reset monopoly.py /^ def reset(cls):$/;" m class:Bank
|
||||
reset monopoly.py /^ def reset(cls):$/;" m class:Property
|
||||
results simulate.py /^ results = defaultdict(list)$/;" v
|
||||
roll_the_dice monopoly.py /^ def roll_the_dice() -> Tuple[int, Doubles]:$/;" m class:Player
|
||||
rounds monopoly.py /^ rounds = 0$/;" v class:Game
|
||||
sell_buildings monopoly.py /^ def sell_buildings(self, building_type, quantity):$/;" m class:BuildableProperty
|
||||
shuffle monopoly.py /^ def shuffle(cls):$/;" m class:Deck
|
||||
shuffle_decks monopoly.py /^def shuffle_decks():$/;" f
|
||||
space_name monopoly.py /^ space_name = space.__name__$/;" v class:Board
|
||||
space_name monopoly.py /^ space_name = space._name$/;" v class:Board
|
||||
space_name monopoly.py /^ space_name = space._name.get(LANGUAGE) or space._name.get(BACKUP_LANGUAGE)$/;" v class:Board
|
||||
spaces monopoly.py /^ spaces = [$/;" v class:Board
|
||||
start monopoly.py /^ def start(self):$/;" m class:Game
|
||||
take_a_turn monopoly.py /^ def take_a_turn(self):$/;" m class:Player
|
||||
test_bank_reset tests/test_monopoly.py /^def test_bank_reset():$/;" f
|
||||
test_property_reset tests/test_monopoly.py /^def test_property_reset():$/;" f
|
||||
test_roll_the_dice tests/test_monopoly.py /^def test_roll_the_dice():$/;" f
|
||||
text monopoly.py /^ text = {"français": "Amende pour excès de vitesse. Payez M15."}$/;" v class:SpeedingCard
|
||||
text monopoly.py /^ text = {"français": "Avancez jusqu'à le chemin de fer le plus proche."}$/;" v class:GoToClosestRailroadCard
|
||||
text monopoly.py /^ text = {"français": "Reculez de trois cases."}$/;" v class:AdvanceThreeSpacesCard
|
||||
text monopoly.py /^ text = {$/;" v class:BuildingAndLoanMaturesCard
|
||||
text monopoly.py /^ text = {$/;" v class:ElectedPresidentCard
|
||||
text monopoly.py /^ text = {$/;" v class:GetOutOfJailFreeCard
|
||||
text monopoly.py /^ text = {$/;" v class:GoToBernPlaceFederaleCard
|
||||
text monopoly.py /^ text = {$/;" v class:GoToJailCard
|
||||
text monopoly.py /^ text = {$/;" v class:RepairPropertyCard
|
||||
total_property_mortgage_value monopoly.py /^ def total_property_mortgage_value(self):$/;" m class:Player
|
||||
type monopoly.py /^ type = "railroad"$/;" v class:Railroad
|
||||
type monopoly.py /^ type = "utility"$/;" v class:Utility
|
||||
type monopoly.py /^ type = None$/;" v class:Property
|
||||
un_mortgage monopoly.py /^ def un_mortgage(self, player: "Player"):$/;" m class:BuildableProperty
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=110,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=121,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=132,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=143,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=154,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=165,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=176,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=193,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=220,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=33,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=55,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=66,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=77,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=88,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost=99,$/;" v class:Board
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost = 110$/;" v class:Railroad
|
||||
unmortgage_cost monopoly.py /^ unmortgage_cost = 83$/;" v class:Utility
|
||||
Binary file not shown.
BIN
tests/__pycache__/test_monopoly.cpython-37-pytest-5.4.2.pyc
Normal file
BIN
tests/__pycache__/test_monopoly.cpython-37-pytest-5.4.2.pyc
Normal file
Binary file not shown.
0
tests/test_buy_decision_algos.py
Normal file
0
tests/test_buy_decision_algos.py
Normal file
21
tests/test_monopoly.py
Normal file
21
tests/test_monopoly.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from monopoly import Bank, NUM_HOUSES, NUM_HOTELS, ALL_MONEY, Property, Player
|
||||
import pytest
|
||||
|
||||
|
||||
def test_bank_reset():
|
||||
Bank.reset()
|
||||
assert Bank.NUM_HOTELS == NUM_HOTELS
|
||||
assert Bank.NUM_HOUSES == NUM_HOUSES
|
||||
assert Bank.money == ALL_MONEY
|
||||
|
||||
|
||||
def test_property_reset():
|
||||
Property.reset()
|
||||
assert all(p.owner is None for p in Property.instances)
|
||||
|
||||
|
||||
def test_roll_the_dice():
|
||||
for i in range(200):
|
||||
num, doubles = Player.roll_the_dice()
|
||||
assert 2 <= num <= 12
|
||||
assert isinstance(doubles, bool)
|
||||
Reference in New Issue
Block a user