예제 #1
0
class Warehouse(Building):
    max_capacity = kp.NumericProperty()
    time_to_full = kp.DictProperty({"wood": "", "clay": "", "iron": ""})
    time_when_its_full = kp.DictProperty({"wood": "", "clay": "", "iron": ""})

    def __init__(self):
        self.settings = BUILDINGS.get("WAREHOUSE")
        super().__init__()
        self.capacity0 = self.settings.get("CAPACITY_INIT")
        self.capacity_ratio = self.settings.get("CAPACITY_RATIO")
        self.max_capacity = self.calc_capacity(self.level)
        self.bind(level=self.on_level)
        Clock.schedule_interval(self.calc_when_is_full, .1)

    def calc_capacity(self, level):
        return self.capacity0 * self.capacity_ratio**(level - 1)

    def on_level(self, *args):
        self.max_capacity = self.calc_capacity(self.level)

    def calc_when_is_full(self, *args):
        self.app = App.get_running_app()
        for resource in self.app.resources:
            resource_until_full = self.max_capacity - resource.current
            resource_until_full = max(resource_until_full, 0)
            seconds_to_full = resource_until_full / resource.per_s
            self.time_to_full[resource._type] = str(
                datetime.timedelta(seconds=int(seconds_to_full)))
            self.time_when_its_full[resource._type] =\
                datetime.datetime.fromtimestamp(time.time() + seconds_to_full).strftime('%H:%M:%S')
예제 #2
0
class CustomTVLabel(HoverBehavior, TreeViewNode, MDLabel):
    """Custom node object for storing database row"""

    item_data = prop.DictProperty() ## Dict with one row from database

    def __init__(self,**kwargs):
        super().__init__(**kwargs)
예제 #3
0
class PCDTree(MDBoxLayout):
    """Treeview widget + buttons and dialogs
    manipulations refered to data"""

    btn_icon = prop.ListProperty(['unfold-more-horizontal','unfold-less-horizontal'])
    btn_text = prop.ListProperty(['Expandir Árvore', 'Retrair Árvore'])

    app = prop.ObjectProperty() ## Main APP reference
    toggled = prop.BooleanProperty(False) ## State of nodes
    nodes_dict = prop.DictProperty() ## All nodes instances callable via id

    dialog = prop.ObjectProperty() ## Search dialog
    search_widget = prop.ObjectProperty() ## Search dialog content instance
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.app = MDApp.get_running_app()
        self.populate_all_nodes() ## add nodes to the treeview

        self.search_widget = SearchFrame(self) ## creates search widget
        self.create_search_dialog() ## creates search dialog with `self.search_widget`
    """
    Treeview methods
    """
    def regen_tree(self):
        """Regenerates treeview nodes"""
        self.ids.treeview.root.nodes = [] ## clear nodes list
        self.ids.treeview.clear_widgets() ## clear nodes widgets
        self.toggled = False ## reset toggled state
        self.populate_all_nodes() ## populate treeview

    def _fetch_data_into_dict(self):
        """Fetches data from database and converts into dict 
        returns a list with a dict for each row of the database
        :return: list"""
        query = 'SELECT * FROM PCD ORDER BY cls_codigo'
        data = self.app.cursor.execute(query).fetchall()
        description = [ col[0] for col in self.app.cursor.description ]
        return [ dict(zip(description,item)) for item in data ]

    def _create_all_nodes(self):
        """Generates all nodes and sorts them between parents and
        children, returns a tupple of (parents,children) lists
        :return: tupple"""
        self.nodes_dict = {} ## nodes instances for future reference
        parents = [] ## parents list
        children = [] ## children list
        data = self._fetch_data_into_dict() ## database items in dict
        for item in data:
            ## Creates treeview node object for each item in database \/
            label = CustomTVLabel(text=f"{item['cls_codigo']} - {item['cls_nome']}")
            label.item_data = item ## add data dict to object
            label.bind(on_touch_down= lambda node, _: self._node_callback(node)) ## bind function
            ## Adding reference to dict
            self.nodes_dict[item['legacyId']] = label
            ## sorting parents and children
            if str(item['parentId']) == 'zero':
                parents.append(label)
            else:
                children.append(label)
        return parents,children

    def populate_all_nodes(self):
        """Populate treeview with new nodes"""
        parents,children = self._create_all_nodes()

        for parent in parents:
            ## add parents to tree
            self.ids.treeview.add_node(parent)
        
        ## adds children nodes into parents
        for parent in self.ids.treeview.iterate_all_nodes():
            for child in children:
                if parent != self.ids.treeview.root: ## skip root node
                    if child.item_data['parentId'] == parent.item_data['legacyId']:
                        self.ids.treeview.add_node(child,parent=parent)
                        children.remove(child)
    
    def _node_callback(self, node):
        """Callback for treeview nodes, checks if
        Form isn't already the selected node
        :param node: obj"""
        df_c = self.app.root.ids.data_frame.children
        if df_c and isinstance(df_c[0], DataManagement):
            ## Form exists
            if df_c[0].item_data['legacyId'] == node.item_data['legacyId']:
                ## Node is IN the current Form
                return
        ## Form doesn't exist or node != current node
        self.generate_data_frame(node)

    def generate_data_frame(self, node):
        """Creates data management obj from current
        node data. node = instance of selected node
        :param node: obj"""
        self.app.set_data_management_widget(
                view_only = True,
                item_data = node.item_data
                )
    
    def delete_node_from_tree(self):
        """Delete selected node from tree"""
        selected_node = self.ids.treeview.get_selected_node()
        self.ids.treeview.remove_node(selected_node)
        self.nodes_dict.pop(selected_node.item_data['legacyId'])
    """
    Buttons methods
    """
    def toggle_all_nodes(self):
        """Toggles all nodes to toggled state"""
        for node in self.ids.treeview.iterate_all_nodes():
            if node != self.ids.treeview.root:
                if self.toggled and node.is_open:
                    ## close open node
                    self.ids.treeview.toggle_node(node)
                if not self.toggled and not node.is_open:
                    ## open closed nodes
                    self.ids.treeview.toggle_node(node)
        ## switches toggled state \/
        self.toggled = not self.toggled
    
    def switch_button(self,reset=False):
        """Switches tooltip and icon when pressed"""
        if reset:
            self.btn_icon = ['unfold-more-horizontal','unfold-less-horizontal']
            self.btn_text = ['Expandir Árvore', 'Retrair Árvore']
        else:
            self.btn_icon[0], self.btn_icon[1] = self.btn_icon[1], self.btn_icon[0]
            self.btn_text[0], self.btn_text[1] = self.btn_text[1], self.btn_text[0]
    """
    Search dialog methods
    """
    def create_search_dialog(self):
        """Creates search dialog"""
        if not self.dialog:
            self.dialog = MDDialog(
                title = 'Clique na Classe para encontrá-la na árvore',
                size_hint = (.5,.9),
                pos_hint = {'right': .9},
                overlay_color = [0, 0, 0, .3],
                auto_dismiss = False,
                type = "custom",
                radius = [20,],
                content_cls = self.search_widget)
            self.dialog.bind(on_open = self.set_focus)

    def set_focus(self, *_):
        """Sets focus to text field"""
        self.search_widget.ids.to_search.focus = True
예제 #4
0
class DataManagement(MDBoxLayout):
    """Object of text fields and buttons for managing data"""

    ## Place holders \/
    app = None ## Main APP reference
    item_data = prop.DictProperty() ## Dict of one row from database
    new_cls = prop.BooleanProperty() ## Bool for new item without parents
    view_only = prop.BooleanProperty() ## Enables/Disables text fields
    delete_dialog = prop.ObjectProperty() ## Delete Dialog popup object
    editing = prop.BooleanProperty(False) ## Enable/Disable editing mode

    def __init__(self,view_only=True,item_data=None,new_cls=False,**kwargs):
        super().__init__(**kwargs)
        self.app = MDApp.get_running_app() ## App object reference
        self.view_only = view_only
        self.item_data = item_data
        self.new_cls = new_cls
        self.set_fields() ## Set text field contents
        self.add_buttons() ## Add buttons to screen
    
    def set_fields(self):
        """Set rules for text fields content"""
        if self.view_only:
            ## populate fields with current database row
            self.populate_fields()
        else:
            ## if not view_only tests for new item 
            if self.new_cls:
                ## if new item, changes label icon and adds 'None' to parent node
                self.ids.label_icon.icon = 'folder-plus-outline'
                self.ids.cls_sub.text = '[ Fundo ]'
                self.app.pcd_tree.disabled = True ## Locks treeview
            else:
                ## if not new item, adds current item code as item parent
                self.ids.cls_sub.text = self.item_data['cls_codigo']

    def add_buttons(self):
        """Add buttons depending on view_only mode"""
        if self.view_only:
            buttons = ViewButtons(edit_code=str(self.item_data['cls_codigo']))
        else:
            buttons = EditButtons()
        self.ids.btn_frame.clear_widgets()
        self.ids.btn_frame.add_widget(buttons)

    def enable_edit(self):
        """Enables editing of text fields"""
        toast(f'Editando {self.item_data["cls_nome"][:40]}{" [...]" if len(self.item_data["cls_nome"]) > 40 else ""}',1)
        self.ids.add_label.text = f'[b]Editando[/b] {self.item_data["cls_nome"]}'
        self.editing = True ## Enables editing
        self.view_only = False ## Disables view_only mode
        self.app.pcd_tree.disabled = True ## Locks treeview
        self.add_buttons() ## Add new buttons

    def populate_fields(self):
        """Populates text fields with current item_data data"""
        self.ids.add_label.text = f'Visualizando [b]{self.item_data["cls_nome"]}[/b]'
        self.ids.cls_nome.text = str(self.item_data['cls_nome'])
        self.ids.cls_codigo.text = str(self.item_data['cls_codigo'])
        self.ids.cls_sub.text = str(self.item_data['cls_sub']) if self.item_data['cls_sub'] != '' else '[ Fundo ]'
        self.ids.reg_abertura.text = str(self.item_data['reg_abertura'])
        self.ids.reg_desativacao.text = str(self.item_data['reg_desativacao'])
        self.ids.reg_reativacao.text = str(self.item_data['reg_reativacao'])
        self.ids.reg_mudanca_nome.text = str(self.item_data['reg_mudanca_nome'])
        self.ids.reg_deslocamento.text = str(self.item_data['reg_deslocamento'])
        self.ids.reg_extincao.text = str(self.item_data['reg_extincao'])
        self.ids.ativa.state = 'down' if self.item_data['cls_indicador'] == 'Ativa' else 'normal'
        self.ids.inativa.state = 'normal' if self.item_data['cls_indicador'] == 'Ativa' else 'down'
        self.ids.fase_corrente.text = str(self.item_data['fase_corrente'])
        self.ids.evento_fase_corrente.text = str(self.item_data['evento_fase_corrente'])
        self.ids.fase_intermediaria.text = str(self.item_data['fase_intermediaria'])
        self.ids.evento_fase_inter.text = str(self.item_data['evento_fase_inter'])
        self.ids.preservacao.state = 'down' if self.item_data['dest_final'] == 'Preservação' else 'normal'
        self.ids.eliminacao.state = 'normal' if self.item_data['dest_final'] == 'Preservação' else 'down'
        self.ids.reg_alteracao.text = str(self.item_data['reg_alteracao'])
        self.ids.observacoes.text = str(self.item_data['observacoes'])

    def show_delete_dialog(self):
        """Create and open delete dialog popup"""
        btn_cancel = MDFlatButton(
            text = 'Cancelar',
            theme_text_color = 'Custom',
            text_color = self.app.theme_cls.primary_color,
            on_release = lambda x: self.delete_dialog.dismiss())
        btn_confirm = MDRaisedButton(
            text = 'Apagar',
            elevation = 11,
            on_release = lambda *x: (self.delete_item_from_db(), self.delete_dialog.dismiss()))

        self.delete_dialog = MDDialog(
            title = 'Deseja realmente apagar?',
            text = f'{self.item_data["cls_nome"]}',
            buttons = [btn_cancel,btn_confirm],
            auto_dismiss = False)
        self.delete_dialog.open()
    
    def delete_item_from_db(self):
        """Try deleting item from database, if successful, deletes item from treeview"""
        try:
            delete_row(self.item_data)
        except lib.utils.ItemHasChildren:
            toast('Classe possui dependentes! Impossível apagar.')
        else:
            toast(f'{self.item_data["cls_nome"][:40]}{" [...]" if len(self.item_data["cls_nome"]) > 40 else ""} apagado com sucesso!',1)
            self.app.root.ids.data_frame.clear_widgets() ## clear data management frame
            self.app.pcd_tree.delete_node_from_tree() ## delete item from treeview
    
    def text_fields_into_dict(self):
        """Gets data from text fields into dict
        :return: dict"""
        data = {
            'parentId': self.item_data['legacyId'] if not self.new_cls else 'zero',
            'cls_nome': self.ids.cls_nome.text.strip(),
            'cls_codigo': self.ids.cls_codigo.text.strip(),
            'cls_sub': self.ids.cls_sub.text.strip() if not self.new_cls else '',
            'reg_abertura': self.ids.reg_abertura.text.strip(),
            'reg_desativacao': self.ids.reg_desativacao.text.strip(),
            'reg_reativacao': self.ids.reg_reativacao.text.strip(),
            'reg_mudanca_nome': self.ids.reg_mudanca_nome.text.strip(),
            'reg_deslocamento': self.ids.reg_deslocamento.text.strip(),
            'reg_extincao': self.ids.reg_extincao.text.strip(),
            'cls_indicador': 'Ativa' if self.ids.ativa.state == 'down' else 'Inativa',
            'fase_corrente': self.ids.fase_corrente.text.strip(),
            'evento_fase_corrente': self.ids.evento_fase_corrente.text.strip(),
            'fase_intermediaria': self.ids.fase_intermediaria.text.strip(),
            'evento_fase_inter': self.ids.evento_fase_inter.text.strip(),
            'dest_final': 'Preservação' if self.ids.preservacao.state == 'down' else 'Eliminação',
            'reg_alteracao': self.ids.reg_alteracao.text.strip(),
            'observacoes': self.ids.observacoes.text.strip()}
        return data
    
    def insert_data_into_db(self):
        """Try to insert data into database,
        if successful regen treeview with new data"""
        data = self.text_fields_into_dict() ## Current item data dict
        parent = self.item_data if not self.new_cls else 'zero' ## set parent data if not new cls
        if self.ids.cls_nome.text.strip() and self.ids.cls_codigo.text.strip() != '':
            ## if required fields are not empty
            try:
                ## Instantiate data manager object \/
                to_insert = ManageData(item_data=data,parent_data=parent)
                if not self.editing:
                    to_insert.insert_into_db() ## inserts into database
                else:
                    to_insert.update_db() ## updates database
            except:
                toast('Algo deu errado! Impossível salvar a Classe.')
            else:
                toast('Classe salva com sucesso!',1)
                self.app.root.ids.data_frame.clear_widgets() ## clear data management frame 
                self.app.pcd_tree.regen_tree() ## Regenerates pcd treeview
                self.app.pcd_tree.switch_button(reset=True) ## switch toggle nodes button
                self.app.pcd_tree.disabled = False ## Unlocks treeview
        else:
            ## if required fields are empty
            toast('Campos obrigatórios estão em branco!')
            self.ids.cls_codigo.focus = True if self.ids.cls_codigo.text.strip() == '' else False
            self.ids.cls_nome.focus = True if self.ids.cls_nome.text.strip() == '' else False
예제 #5
0
class AppFrame(FloatLayout):
    """
    The core layout of the application, acts as the root widget and
    provides methods universal to all child widgets.
    """
    btn_layout = kp.ObjectProperty(None)
    keybindings = kp.DictProperty({})
    config = kp.DictProperty({})

    def new_keybind_dialogue(self) -> None:
        """
        Opens a NewBindDialogue pop up to get user input.

        :return: None
        """
        nbd = NewBinding()
        self.add_widget(nbd)

    def name_bindset_dialogue(self, mode: str = 'Save') -> None:
        """
        Opens a NameBindSet pop up to get user input.

        :param mode: A string, either 'Save' or 'Load'.
        :return: None
        """
        sbs = NameBindSet(mode=mode)
        self.add_widget(sbs)

    def update_keybind(self, **options) -> None:
        """
        Creates a new Keybind object or updates an existing one.

        :param options: kwargs. Main kwarg that update_keybind requires
            is name, a string specifying the user-supplied name of the
            keybind.
        :return: None
        """
        bind_name = options.get('name')
        if self.keybindings.get(bind_name):
            self.keybindings[bind_name].setup(**options)
        else:
            new_btn = Keybind()
            new_btn.setup(**options)
            self.keybindings[bind_name] = new_btn
            self.btn_layout.add_widget(new_btn)

    @staticmethod
    def to_json(file_path: str, data: dict) -> None:
        """
        Simple method to save a one line dictionary to a json file.

        :param file_path: A string, a valid file path.
        :param data: A dictionary.
        :return: None
        """
        with open(file_path, 'w') as w:
            w.write(json.dumps(data))

    @staticmethod
    def from_json(file_path: str) -> dict:
        """
        Simple method to load a one line json into a python dictionary.

        :param file_path: A string, a file path.
        :return: A dictionary containing the json in file_path, or an
            empty dictionary if the file_path was invalid.
        """
        if os.path.exists(file_path):
            with open(file_path, 'r') as r:
                for line in r:
                    result = json.loads(line)
            return result
        else:
            return dict()

    def save(self, file_name: str) -> None:
        """
        Saves all the Keybinds in keybindings as well as the values
        stored in config.

        :param file_name: A string, the name of the file to save to.
        :return: None
        """
        result = dict()
        for k, v in self.keybindings.items():
            result[k] = {**v.output()}
        self.to_json(f'bindsets/{file_name}.json', result)
        self.config['last_bindset'] = file_name
        self.save_config()

    def save_config(self) -> None:
        """
        Saves the config dictionary to a json file called ref.

        :return: None
        """
        self.to_json('ref.json', self.config)

    def load(self, file_name: str) -> bool:
        """
        Loads a specified bindset from the bindsets directory and
        replaces the existing bindset with Keybinds corresponding to
        the new bindset.

        :param file_name: A valid file path.
        :return: A boolean indicating whether data was successfully
            retrieved from the passed file.
        """
        p = f'bindsets/{file_name}.json'
        result = self.from_json(p)
        if len(result) > 0:
            self.btn_layout.clear_widgets()
            for k, v in result.items():
                b = Keybind()
                b.setup(k, **v)
                self.keybindings[k] = b
                self.btn_layout.add_widget(b)
            return True
        else:
            return False
예제 #6
0
class RallyPoint(Building):
    attacker = kp.DictProperty(defaultdict(int))
    defender = kp.DictProperty(defaultdict(int))
    units_kills_atk = kp.DictProperty(defaultdict(int))
    units_kills_def = kp.DictProperty(defaultdict(int))

    def __init__(self):
        self.settings = BUILDINGS.get("RALLY_POINT")
        super().__init__()
        self.scavenging = self.settings.get("SCAVENGING")

    def calc_simulator(self, *args):
        print("simulator", args)
        attacker_inputs = args[0]
        attacker_inputs = list(reversed(attacker_inputs.children[:-1]))
        defender_inputs = args[1]
        defender_inputs = list(reversed(defender_inputs.children[:-1]))
        app = args[2]

        # attacker = defaultdict(int)
        attacker_power_per_type = defaultdict(int)
        total_defender_power_per_type = defaultdict(
            lambda: app.wall.basic_defense)
        defender_power_per_type = defaultdict(int)
        total_population_per_type = defaultdict(int)
        total_population_per_type_def = defaultdict(int)
        perc_population_per_type = defaultdict(int)
        _types = ["general", "cavalry", "archer"]

        # get input units:
        for i, unit in enumerate(app.units):
            try:
                self.attacker[unit] = int(attacker_inputs[i].text)
            except ValueError:
                self.attacker[unit] = 0
            try:
                self.defender[unit] = int(defender_inputs[i].text)
            except ValueError:
                self.defender[unit] = 0

        print("attacker", self.attacker)
        print("defender", self.defender)

        # calc total power done for all units per type:
        for i, unit in enumerate(app.units):
            attacker_power_per_type[
                unit._type] += self.attacker[unit] * unit.atk
            for _type in _types:
                total_defender_power_per_type[_type] += self.defender[
                    unit] * unit.defence.get(_type.upper())
        print("attacker_power_per_type", attacker_power_per_type)
        print("total_defender_power_per_type", total_defender_power_per_type)

        # calc total_population_per_type:
        for i, unit in enumerate(app.units):
            total_population_per_type[
                unit._type] += self.attacker[unit] * unit.population
            total_population_per_type_def[
                unit._type] += self.defender[unit] * unit.population
        print("total_population_per_type", total_population_per_type)
        print("total_population_per_type_def", total_population_per_type_def)

        # calc perc_population_per_type:
        total_all_types_population = sum(total_population_per_type.values())
        try:
            for _type in _types:
                perc_population_per_type[_type] += total_population_per_type[
                    _type] / total_all_types_population
        except ZeroDivisionError:
            return
        print("perc_population_per_type", perc_population_per_type)

        # calc defender power after aply perc_population_per_type:
        for _type in _types:
            defender_power_per_type[_type] = total_defender_power_per_type[
                _type] * perc_population_per_type[_type]
        print("defender_power_per_type", defender_power_per_type)

        # calc total_killed_units_per_type by type:
        total_killed_units_per_type = defaultdict(int)
        total_killed_units_per_type_def = defaultdict(int)
        for _type in _types:
            print(_type)
            if attacker_power_per_type[_type] == 0:
                continue
            if total_population_per_type[_type] == 0:
                continue
            x = attacker_power_per_type[_type] / defender_power_per_type[_type]
            x_defender = defender_power_per_type[
                _type] / attacker_power_per_type[_type]
            print("x", x)
            print("x_defender", x_defender)
            ratio = 1 / x**0.5
            ratio_defender = 1 / x_defender**0.5
            print("ratio", ratio)
            print("ratio_defender", ratio_defender)
            damage_done_by_def = ratio * defender_power_per_type[_type]
            damage_done_by_atk = ratio_defender * attacker_power_per_type[_type]
            print("damage_done_by_def", damage_done_by_def)
            print("damage_done_by_atk", damage_done_by_atk)
            total_killed_units_per_type[_type] =\
                damage_done_by_def / attacker_power_per_type[_type] * total_population_per_type[_type]
            total_killed_units_per_type_def[_type] =\
                damage_done_by_atk / defender_power_per_type[_type] * total_population_per_type[_type]
        print("total_killed_units_per_type", total_killed_units_per_type)
        print("total_killed_units_per_type_def",
              total_killed_units_per_type_def)

        # calc units_kills: split the type % for all units
        for i, unit in enumerate(app.units):
            # attacker:
            try:
                ratio_units = (self.attacker[unit] * unit.population
                               ) / total_population_per_type[unit._type]
                print("ratio_units", ratio_units)
                self.units_kills_atk[unit] = total_killed_units_per_type[
                    unit._type] * ratio_units / unit.population
                self.units_kills_atk[unit] = min(
                    round(self.units_kills_atk[unit]), self.attacker[unit])
            except ZeroDivisionError:
                continue
            # defender:
            try:
                ratio_units_def = (
                    self.defender[unit] * unit.population
                ) / total_population_per_type_def[unit._type]
                print("ratio_units_def", ratio_units_def)
                self.units_kills_def[unit] = total_killed_units_per_type_def[
                    unit._type] * ratio_units_def / unit.population
                self.units_kills_def[unit] = min(
                    round(self.units_kills_def[unit]), self.defender[unit])
            except ZeroDivisionError:
                continue
        print("self.units_kills_atk", self.units_kills_atk)
        print("self.units_kills_def", self.units_kills_def)
예제 #7
0
class GameApp(App):
    width = kp.NumericProperty(Window.width)
    height = kp.NumericProperty(Window.height)
    # offset = kp.NumericProperty()
    # resources:
    wood = kp.ObjectProperty(Resource("WOOD"))
    clay = kp.ObjectProperty(Resource("CLAY"))
    iron = kp.ObjectProperty(Resource("IRON"))
    population_icon = kp.StringProperty(
        RESOURCES.get("ICON").get("POPULATION"))
    resources_ratio = kp.NumericProperty(RESOURCES.get("RATIO"))
    population = kp.DictProperty({
        "max":
        BUILDINGS.get("FARM").get("POPULATION_INIT"),
        "buildings":
        0,
        "units":
        0,
        "total":
        0,
    })
    # buildings:
    headquarters = kp.ObjectProperty(Headquarters())
    rally_point = kp.ObjectProperty(RallyPoint())
    statue = kp.ObjectProperty(Statue())
    timber_camp = kp.ObjectProperty(TimberCamp())
    clay_pit = kp.ObjectProperty(ClayPit())
    iron_mine = kp.ObjectProperty(IronMine())
    farm = kp.ObjectProperty(Farm())
    warehouse = kp.ObjectProperty(Warehouse())
    hiding_place = kp.ObjectProperty(HidingPlace())
    barracks = kp.ObjectProperty(Barracks())
    stable = kp.ObjectProperty(Stable())
    workshop = kp.ObjectProperty(Workshop())
    academy = kp.ObjectProperty(Academy())
    smithy = kp.ObjectProperty(Smithy())
    market = kp.ObjectProperty(Market())
    wall = kp.ObjectProperty(Wall())
    # to upgrade buildings:
    current_upgrading = kp.ObjectProperty("")
    time_left = kp.NumericProperty()
    time_eta = kp.ObjectProperty("")
    cancel = kp.BooleanProperty(False)
    is_upgrading = kp.BooleanProperty(False)
    # Units:
    spear_fighter = kp.ObjectProperty(Unit(name="SPEAR_FIGHTER"))
    swordsman = kp.ObjectProperty(Unit(name="SWORDSMAN"))
    axeman = kp.ObjectProperty(Unit(name="AXEMAN"))
    archer = kp.ObjectProperty(Unit(name="ARCHER"))
    scout = kp.ObjectProperty(Unit(name="SCOUT"))
    light_cavalry = kp.ObjectProperty(Unit(name="LIGHT_CAVALRY"))
    mounted_archer = kp.ObjectProperty(Unit(name="MOUNTED_ARCHER"))
    heavy_cavalry = kp.ObjectProperty(Unit(name="HEAVY_CAVALRY"))
    ram = kp.ObjectProperty(Unit(name="RAM"))
    catapult = kp.ObjectProperty(Unit(name="CATAPULT"))
    paladin = kp.ObjectProperty(Paladin())
    noble = kp.ObjectProperty(Unit(name="NOBLE"))
    militia = kp.ObjectProperty(Unit(name="MILITIA"))

    def build_config(self, *args):
        self.units = [
            self.spear_fighter, self.swordsman, self.axeman, self.archer,
            self.scout, self.light_cavalry, self.mounted_archer,
            self.heavy_cavalry, self.ram, self.catapult, self.paladin,
            self.noble, self.militia
        ]
        self.buildings = [
            self.headquarters, self.rally_point, self.statue, self.timber_camp,
            self.clay_pit, self.iron_mine, self.farm, self.warehouse,
            self.hiding_place, self.barracks, self.stable, self.workshop,
            self.academy, self.smithy, self.market, self.wall
        ]

    def build(self):
        self.game = Game(transition=NoTransition())
        self.resources = [self.wood, self.clay, self.iron]
        self.calc_current_population()
        Clock.schedule_interval(self.update_resources, .1)
        return self.game

    def calc_current_population(self):
        for building in self.buildings:
            self.population["buildings"] += building.population
        for unit in self.units:
            self.population["units"] += unit.n * unit.population

        self.population[
            "total"] = self.population["buildings"] + self.population["units"]

    def upgrade_building(self, building):
        if self.is_upgrading:
            return
        # check if can upgrade:
        check_resources =\
            self.wood.current > building.wood and \
            self.clay.current > building.clay and self.iron.current > building.iron
        check_max_level = building.level < building.max_level
        if not (check_resources and check_max_level):
            return
        self.current_upgrading = building
        self.time_left = building.time
        self.time_eta = datetime.datetime.fromtimestamp(
            time.time() + self.time_left).strftime('%H:%M:%S')
        # update resources:
        self.wood.current -= self.current_upgrading.wood
        self.clay.current -= self.current_upgrading.clay
        self.iron.current -= self.current_upgrading.iron
        self.is_upgrading = True
        Clock.schedule_interval(self.update_building, .1)

    def update_building(self, dt):
        if self.cancel:
            # undo update resources:
            self.wood.current += self.current_upgrading.wood
            self.clay.current += self.current_upgrading.clay
            self.iron.current += self.current_upgrading.iron
            self.current_upgrading = ""
            self.time_left = 0
            self.cancel = False
            self.is_upgrading = False
            return False
        self.time_left -= dt
        if self.time_left <= 0:
            self.update_building_finish()
            return False

    def update_building_finish(self):
        # update requirements:
        self.current_upgrading.level += 1
        self.current_upgrading.update_cost_for_current_level()
        self.current_upgrading.update_population_for_current_level()
        self.calc_current_population()
        self.current_upgrading.time *= self.current_upgrading.ratio
        # update buildings:
        if self.current_upgrading.name == "headquarters":
            for build in self.buildings:
                build.time *= self.current_upgrading.time_reduce
        if self.current_upgrading.name == "timber_camp":
            self.wood.per_s *= self.resources_ratio
        if self.current_upgrading.name == "clay_pit":
            self.clay.per_s *= self.resources_ratio
        if self.current_upgrading.name == "iron_mine":
            self.iron.per_s *= self.resources_ratio
        if self.current_upgrading.name == "farm":
            self.population["max"] *= self.farm.population_ratio

        self.current_upgrading = ""
        self.is_upgrading = False

    def cancel_upgrading(self, *args):
        if self.is_upgrading:
            self.cancel = True

    def update_resources(self, dt):
        for resource in self.resources:
            resource.current += resource.per_s * dt
            resource.current = min(resource.current,
                                   self.warehouse.max_capacity)
예제 #8
0
class GameWidget(Screen):

    app = prop.ObjectProperty()
    game = prop.ObjectProperty()

    player_name = prop.StringProperty()
    current_turn_author = prop.StringProperty()
    player_widgets = prop.DictProperty()
    deck_widget = prop.ObjectProperty()

    pending_actions = []
    player_tab_title = '* You *'

    def __init__(self, game, **kwargs):
        super(GameWidget, self).__init__(**kwargs)
        self.game = game
        self.player_name = self.app.player_name

        self.player_widgets = {player.name: player.make_widget(game_widget=self) \
            for player in self.game.get_category(game_component_types.PLAYER).itervalues()}

        self.add_player_widget(self.player_widgets[self.player_name])
        for widget in self.player_widgets.itervalues():
            if widget.player.name != self.player_name:
                self.add_player_widget(widget)

        deck_zone = self.ids.deck_zone
        self.deck_widget = self.game.get_category(
            game_component_types.DECK).values()[0].make_widget(
                game_widget=self)
        deck_zone.add_widget(self.deck_widget)

        self.update_current_turn_author()

    def update_current_turn_author(self):
        self.current_turn_author = self.game.current_flow._author

    def is_our_turn(self):
        #print("Current player: {0}".format(self.game.current_flow._author))
        return self.player_name == self.current_turn_author

    def is_our_tab_active(self):
        #print("Active tab: {0}".format(self.ids.player_zone.current_tab.text))
        return self.ids.player_zone.current_tab.text == self.player_tab_title

    def add_player_widget(self, widget):
        caption = self.player_tab_title if widget.player.name == self.player_name else widget.player.name
        tab = tabbedpanel.TabbedPanelItem(text=caption)
        tab.add_widget(widget=widget)
        self.ids.player_zone.add_widget(tab)

    def queue_action(self, action):
        self.pending_actions.append(action)
        print(self.pending_actions)

    def send_actions(self, *actions):
        for action in actions:
            msg = action.make_message()
            self.app.send_action(msg)

    def push_game_forward(self, action):
        self.game.receive_message(action)
        self.update_current_turn_author()

    def notify(self, text):
        self.app.notify(text)
예제 #9
0
class mainwidget(FloatLayout):
                                                    #flags=-1 represents game not started and only black can press since white starts
    pause_flag=1
    white_time=kv.DictProperty({'hour':'0','minute':'5','second':'0'})  # dictionary to hold time of white and black
    black_time=kv.DictProperty({'hour':'0','minute':'5','second':'0'})
    white_string=kv.StringProperty('0:5:0')
    black_string=kv.StringProperty("0:5:0")                  #strings which contain display of white and black time

    def __init__(self):
        super(mainwidget, self).__init__() 
        self.flags=-1
    def refresher(self):                     
        Clock.unschedule(self.decrease_time_default_white)
        Clock.unschedule(self.decrease_time_default_black)
        self.flags=-1
        self.white_time={'hour':'0','minute':'5','second':'0'}
        self.black_time={'hour':'0','minute':'5','second':'0'}
        self.white_string='0:5:0'                                     #used to set times to initial state
        self.black_string="0:5:0"
    
    def pauser(self):                                               # used to pause the clock
        if(self.pause_flag==1):                                      # if flag 1 then clock is ticking
            if(self.flags==1):
                Clock.unschedule(self.decrease_time_default_white)            # unschedule white  flags=1 represents white time is going 
            elif(self.flags==0):                                                # unschedule black  flags=1 represents black time is going 
                Clock.unschedule(self.decrease_time_default_black)
            labels=self.ids['pause_button']                            
            labels.text="resume"                                          #interchange between resume and pause
            self.pause_flag=0
        elif(self.pause_flag==0):                                            # if flag=0 clock is paused either side it remains constant
            if(self.flags==1):                                             
                Clock.schedule_interval(self.decrease_time_default_white,1)        # resume time if move belongs to white
            elif(self.flags==0):                                                   
                Clock.schedule_interval(self.decrease_time_default_black,1)
            labels=self.ids['pause_button']
            labels.text="pause"                                         #interchange the name 
            self.pause_flag=1

    def decrease_time_default_black(self,dt):
              
        self.black_time['second']=str(int(self.black_time['second'])-1)
        if(int(self.black_time['second'])<0):
            self.black_time['minute']=str(int(self.black_time['minute'])-1)
            self.black_time['second']=str(int(self.black_time['second'])+60)                   #decrease the time in black by 1 sec
            
        if(int(self.black_time['minute'])<0):
            self.black_time['hour']=str(int(self.black_time['hour'])-1)
            self.black_time['minute']=str(int(self.black_time['minute'])+60)
        self.black_string=self.black_time['hour']+':'+self.black_time['minute']+':'+self.black_time['second'] # update in the string

    def decrease_time_default_white(self,dt):
        self.white_time['second']=str(int(self.white_time['second'])-1)
        if(int(self.white_time['second'])<0):
            self.white_time['minute']=str(int(self.white_time['minute'])-1)
            self.white_time['second']=str(int(self.white_time['second'])+60)                #decrease the time in black by 1 sec
            
        if(int(self.white_time['minute'])<0):
            self.white_time['hour']=str(int(self.white_time['hour'])-1)
            self.white_time['hour']=str(int(self.white_time['hour'])+60)
        self.white_string=self.white_time['hour']+':'+self.white_time['minute']+':'+self.white_time['second']
            
    def click_setter_black(self):
        white=self.ids['white']                #if clicked on black
        black=self.ids['black']           
        if(self.flags ==-1):          # beginning of the game
            white.background_color=[1,1,1,1]  #running color
            black.background_color=[0,1,0,1]  #dormant color        
            self.flags=1                                                     
            Clock.schedule_interval(self.decrease_time_default_white,1)
            print(self.white_string)
        elif(self.flags==0):               # if black presses and its his turn
            white.background_color=[1,1,1,1]
            black.background_color=[0,1,0,1]  
            self.flags=1  
            Clock.unschedule(self.decrease_time_default_black)               
            Clock.schedule_interval(self.decrease_time_default_white,1)
    
    def click_setter_white(self):        # similar to black
        white=self.ids['white']
        black=self.ids['black']     
        if(self.flags==1):
            white.background_color=[0,1,0,1]
            black.background_color=[1,1,1,1]  
            self.flags=0
            Clock.unschedule(self.decrease_time_default_white)
            Clock.schedule_interval(self.decrease_time_default_black,1)
예제 #10
0
class SecondScreen(Screen):
                                                   #flags=-1 represents game not started and only black can press since white starts
    pause_flag=1
    white_time_init=kv.DictProperty({'hour':'0','minute':'5','second':'00'})  # dictionary to hold time of white and black
    black_time_init=kv.DictProperty({'hour':'0','minute':'5','second':'00'})
    increment_white_time=kv.DictProperty({'hour':'0','minute':'0','second':'02'})
    increment_black_time=kv.DictProperty({'hour':'0','minute':'0','second':'02'})
    white_time=kv.DictProperty({'hour':'0','minute':'5','second':'00'})  # dictionary to hold time of white and black
    black_time=kv.DictProperty({'hour':'0','minute':'5','second':'00'})
    white_string=kv.StringProperty('5:00')
    black_string=kv.StringProperty("5:00")                  #strings which contain display of white and black time
    flags=-1
    def __init__(self, **kw):
        super().__init__(**kw)
        df=pd.read_csv("helo.csv")
        #elf.pause_flag=int(df.loc[0]['pause_flag'])    # fields=['flags','pause_flag','white_string','black_string','increment_white','increment_black']
        self.white_time=string_to_dict(df.loc[0]['white_string'])
        self.black_time=string_to_dict(df.loc[0]['black_string'])
        self.white_string=df.loc[0]['white_string']
        self.black_string=df.loc[0]['black_string']
        self.white_time_init=string_to_dict(df.loc[0]['init_white'])
        self.black_time_init=string_to_dict(df.loc[0]['init_black'])
        self.increment_white_time=string_to_dict(df.loc[0]['increment_white'])
        self.increment_black_time_=string_to_dict(df.loc[0]['increment_black'])
        self.flags=df.loc[0]['flags']
        
    def value_time(self,dict):
       return int(dict['second'])+int(dict['minute'])*60+int(dict['hour'])*3600
    def increment_setter(self,dict1,dict2):
        self.increment_white_time=dict1
        self.increment_black_time=dict2
        
   

    def new_value_setter(self,dict1,dict2):
        self.flags=-1
        self.pause_flag=0
        self.white_time_init=dict1
        self.black_time_init=dict2
        self.white_time=dict1
        self.black_time=dict2
        self.white_string=format_time(self.white_time)
        self.black_string=format_time(self.black_time)
        white=self.ids['white']
        black=self.ids['black']
        white.background_color=[0,1,1,1]
        black.background_color=[0,1,1,1]

    def refresher(self):  
        self.exit_pauser()  
        pop_layout=BoxLayout()
        popup=Popup(title="Are u sure u want to refresh",content=pop_layout)       
        pop_label=Label(text="Refresh will make \n current time lost",font_size=50,color=[1,0.7,0.435,1],halign='right',valign='middle') 
        q=BoxLayout(orientation="horizontal")
        yes_button=Button(text="yes",size_hint=(0.6,0.2))
        no_button=Button(text="no",size_hint=(0.6,0.2)) 
        def out(instance):          
            Clock.unschedule(self.decrease_time_default_white)
            Clock.unschedule(self.decrease_time_default_black)
            self.flags=-1
            self.pause_flag=1
            labels=self.ids['pause_button']                            
            labels.text="pause"
            self.white_time=self.white_time_init
            self.black_time=self.black_time_init
            self.white_string=format_time(self.white_time)
            self.black_string=format_time(self.black_time)
            white=self.ids['white']
            black=self.ids['black']
            white.background_color=[0,1,1,1]
            black.background_color=[0,1,1,1]
            popup.dismiss()

        yes_button.bind(on_press=out)
        no_button.bind(on_press=lambda x:popup.dismiss())
        pop_layout.add_widget(pop_label)
        q.add_widget(yes_button)
        q.add_widget(no_button)
        pop_layout.add_widget(q)
        popup.open()
     
    def exit_pauser(self):
        if(self.pause_flag==1):                                      # if flag 1 then clock is ticking
            if(self.flags==1):
                Clock.unschedule(self.decrease_time_default_white)            # unschedule white  flags=1 represents white time is going 
            elif(self.flags==0):                                                # unschedule black  flags=1 represents black time is going 
                Clock.unschedule(self.decrease_time_default_black)
            labels=self.ids['pause_button']                            
            labels.text="resume"                                          #interchange between resume and pause
            self.pause_flag=0

    def pauser(self):                                               # used to pause the clock
        if(self.pause_flag==1):                                      # if flag 1 then clock is ticking
            if(self.flags==1):
                Clock.unschedule(self.decrease_time_default_white)            # unschedule white  flags=1 represents white time is going 
            elif(self.flags==0):                                                # unschedule black  flags=1 represents black time is going 
                Clock.unschedule(self.decrease_time_default_black)
            labels=self.ids['pause_button']                            
            labels.text="resume"                                          #interchange between resume and pause
            self.pause_flag=0
        elif(self.pause_flag==0):                                            # if flag=0 clock is paused either side it remains constant
            if(self.flags==1):                                             
                Clock.schedule_interval(self.decrease_time_default_white,1)        # resume time if move belongs to white
            elif(self.flags==0):                                                   
                Clock.schedule_interval(self.decrease_time_default_black,1)
            labels=self.ids['pause_button']
            labels.text="pause"                                         #interchange the name 
            self.pause_flag=1

    def decrease_time_default_black(self,dt):
        if(self.value_time(self.black_time)==0):
            white=self.ids['black']
            white.background_color=[1,0,0,1]
            self.flags=-2
            return      
        self.black_time['second']=str(int(self.black_time['second'])-1)
        if(int(self.black_time['second'])<0):
            self.black_time['minute']=str(int(self.black_time['minute'])-1)
            self.black_time['second']=str(int(self.black_time['second'])+60)                   #decrease the time in black by 1 sec
            
        if(int(self.black_time['minute'])<0):
            self.black_time['hour']=str(int(self.black_time['hour'])-1)
            self.black_time['minute']=str(int(self.black_time['minute'])+60)
        self.black_string=format_time(self.black_time) # update in the string
    
    def incrementer_black(self):
        self.black_time['second']=str(int(self.black_time['second'])+int(self.increment_black_time['second']))
        self.black_time['minute']=str(int(self.black_time['minute'])+int(self.increment_black_time['minute']))
        self.black_time['hour']=str(int(self.black_time['hour'])+int(self.increment_black_time['hour']))
        seconder=int(self.black_time['second'])%60
        minuter=int(int(self.black_time['second'])/60)+int(self.black_time['minute'])
        hourer=int(self.black_time['hour'])+int(minuter/60)
        minuter=minuter%60
        hourer=hourer%24
        self.black_time['hour']=str(hourer)
        self.black_time['minute']=str(minuter)
        self.black_time['second']=str(seconder)
        self.black_string=format_time(self.black_time)

    def incrementer_white(self):
        self.white_time['second']=str(int(self.white_time['second'])+int(self.increment_white_time['second']))
        self.white_time['minute']=str(int(self.white_time['minute'])+int(self.increment_white_time['minute']))
        self.white_time['hour']=str(int(self.white_time['hour'])+int(self.increment_white_time['hour']))
        seconder=int(self.white_time['second'])%60
        minuter=int(int(self.white_time['second'])/60)+int(self.white_time['minute'])
        hourer=int(self.white_time['hour'])+int(minuter/60)
        minuter=minuter%60
        hourer=hourer%24
        self.white_time['hour']=str(hourer)
        self.white_time['minute']=str(minuter)
        self.white_time['second']=str(seconder)
        self.white_string=format_time(self.white_time)


    def decrease_time_default_white(self,dt):
        if(self.value_time(self.white_time)==0):
            white=self.ids['white']
            white.background_color=[1,0,0,1]
            self.flags=2
            return
        self.white_time['second']=str(int(self.white_time['second'])-1)
        if(int(self.white_time['second'])<0):
            self.white_time['minute']=str(int(self.white_time['minute'])-1)
            self.white_time['second']=str(int(self.white_time['second'])+60)                #decrease the time in black by 1 sec
            
        if(int(self.white_time['minute'])<0):
            self.white_time['hour']=str(int(self.white_time['hour'])-1)
            self.white_time['minute']=str(int(self.white_time['minute'])+60)

        self.white_string=format_time(self.white_time)
        

            
    def click_setter_black(self ):
        white=self.ids['white']                #if clicked on black
        black=self.ids['black']           
        if(self.flags ==-1 and self.value_time(self.black_time)>0 and self.pause_flag==1):          # beginning of the game
            white.background_color=[1,1,1,1]  #running color
            black.background_color=[0,1,0,1]  #dormant color        
            self.flags=1                                                     
            Clock.schedule_interval(self.decrease_time_default_white,1)
            print(self.white_string)
        elif(self.flags ==-1 and self.value_time(self.black_time)==0 and self.pause_flag==1):
            black.background_color=[1,0,0,1] 
            white.background_color=[1,0,0,1] 
            self.flags=-2
            Clock.unschedule(self.decrease_time_default_black)
            Clock.unschedule(self.decrease_time_default_white)
        elif(self.flags==0 and self.value_time(self.black_time)>0 and self.pause_flag==1):               # if black presses and its his turn
            white.background_color=[1,1,1,1]
            black.background_color=[0,1,0,1]  
            self.flags=1  
            self.incrementer_black() 
            Clock.unschedule(self.decrease_time_default_black)     
             
            Clock.schedule_interval(self.decrease_time_default_white,1)
        elif(self.flags==0 and self.value_time(self.black_time)==0 and self.pause_flag==1):
            white.background_color=[0,1,1,1]
            black.background_color=[1,0,0,1] 
            self.flags=-2
            Clock.unschedule(self.decrease_time_default_black)
            Clock.unschedule(self.decrease_time_default_white)
    
    def click_setter_white(self):        # similar to black
        white=self.ids['white']
        black=self.ids['black']     
        if(self.flags==1 and self.value_time(self.white_time)>0 and self.pause_flag==1):
            white.background_color=[0,1,0,1]
            black.background_color=[1,1,1,1]  
            self.flags=0
            self.incrementer_white()
            Clock.unschedule(self.decrease_time_default_white)
            Clock.schedule_interval(self.decrease_time_default_black,1)
        elif(self.flags==1 and self.value_time(self.white_time)==0 and self.pause_flag==1):
            white.background_color=[1,0,0,1]
            black.background_color=[0,1,1,1]
            self.flags=2
            Clock.unschedule(self.decrease_time_default_black)
            Clock.unschedule(self.decrease_time_default_white)
예제 #11
0
class GameApp(App):
    points = kp.NumericProperty(settings.POINTS["game"]["init"])
    languages = kp.ListProperty(["", ""])
    words = kp.ListProperty()
    number_of_words = kp.NumericProperty()
    current_word = kp.DictProperty()
    last_word = kp.DictProperty()

    def build(self):
        Window.size = (400, 600)
        self.meta_game = MetaGame()
        self.bind(words=self.calc_number_of_words)
        return self.meta_game

    def add_languages(self, lang1, lang2):
        self.languages = [lang1, lang2]

    def add_word(self, word1, word2):
        # print("add_word(%s, %s)" % (word1, word2))
        new_word = {self.languages[0]: word1, self.languages[1]: word2}
        new_word["points"] = settings.POINTS["word"]["init"]
        self.words.append(new_word)

    def delete_word(self, word_to_delete="", language=""):
        # print("delete_word()", word_to_delete, language)
        # word_to_delete could be a string or a dict/obj
        if not language:
            language = self.languages[0]
        if not isinstance(word_to_delete, str):
            word_to_delete = word_to_delete[language]
        for word in self.words:
            if word[language] == word_to_delete:
                self.words.remove(word)
                return

    def calc_number_of_words(self, *args):
        # print("number_of_words()", args)
        self.number_of_words = len(self.words)
        return self.number_of_words

    def pick_random_word(self, lang1="", lang2=""):
        print("\npick_random_word(%s, %s)" % (lang1, lang2))
        if not lang1:
            lang1 = self.languages[0]
        if not lang2:
            lang2 = self.languages[1]
        if lang1 not in self.languages or lang2 not in self.languages or lang1 == lang2:
            raise Exception("please insert a valid languages not: %s and %s" %
                            (lang1, lang2))
        if len(self.words) == 1:
            return self.words[0]
        # calc n_of_words_to_choose_from
        # it depends of the points, more points -> more degree -> more difficult
        # if the degree is 0 all the words have the same prob to appear
        # if the degree is high, will always appear the same words (with less points)
        n_of_words_to_choose_from = self.number_of_words
        print("n_of_words_to_choose_from: %s" % n_of_words_to_choose_from)
        degree = int(self.points / 100)
        print("degree: %s" % degree)
        for _ in range(degree):
            n_of_words_to_choose_from = max(
                random.randrange(n_of_words_to_choose_from) + 1, 2)
            print("n_of_words_to_choose_from: %s" % n_of_words_to_choose_from)

        self.order_by("points")
        print("self.words:", self.words)
        possible_words_to_choose = self.words[0:n_of_words_to_choose_from]
        print("possible_words_to_choose", possible_words_to_choose)
        word_choosed = random.choice(possible_words_to_choose)
        print(word_choosed, self.last_word)
        print(word_choosed[self.languages[0]],
              self.last_word.get(self.languages[0], ""))
        if word_choosed[self.languages[0]] == self.last_word.get(
                self.languages[0], ""):
            print("word_choosed == self.last_word")
            possible_words_to_choose.remove(word_choosed)
            word_choosed = random.choice(possible_words_to_choose)

        return word_choosed

    def check_solution(self, word1, word2):
        print("self.languages", self.languages)
        for word in self.words:
            print("word", word)
            if word[self.languages[0]] == word1:
                correct_word = word[self.languages[1]]
                correct_word = correct_word.split(", ")
                # print("correct_word: %s" % correct_word)
                correct_word = [word.lower() for word in correct_word]
                if word2 and word2.lower() in correct_word:
                    # print("gain", correct_word == word2, word2 in correct_word)
                    return True, word
                else:
                    # print("lose", correct_word)
                    return False, word

    def update_word_points(self, word1, word2):
        # print("update_word_points(%s, %s)" % (word1, word2))
        increase_rate = settings.POINTS["word"]["increase_rate"]
        decreased_rate = settings.POINTS["word"]["decreased_rate"]
        is_correct, word = self.check_solution(word1, word2)
        if is_correct:
            word["points"] *= increase_rate
        else:
            word["points"] /= decreased_rate
        return word

    def update_points(self, word1, word2):
        print("update_points()", self.points)
        down4right_words = settings.POINTS["game"]["down4right_words"]
        up4wrong_words_a = settings.POINTS["game"]["up4wrong_words_a"]
        up4wrong_words_b = settings.POINTS["game"]["up4wrong_words_b"]
        is_correct, _ = self.check_solution(word1, word2)
        if is_correct:
            increment = up4wrong_words_a / (self.points + up4wrong_words_b)
            self.points += increment
        else:
            self.points -= self.points / down4right_words

    def order_by(self, what, reverse=False):
        print("order_by(%s, %s)" % (what, reverse))
        # print(self.words)
        if what in ["points"]:
            self.words =\
                sorted(self.words, key=lambda x: float(x[what]), reverse=reverse)
        else:
            self.words =\
                sorted(self.words, key=lambda x: strip_accents(x[what]), reverse=reverse)
        # print(self.words)
        return self.words

    # GUI:
    def update_word_after_check(self, word1, word2):
        print("update_word_after_check(%s, %s)" % (word1, word2))
        # print("self.current_word: %s" % self.current_word)
        self.current_word = self.update_word_points(word1, word2)
        self.update_points(word1, word2)
        # print("self.current_word: %s" % self.current_word)
        game_menu = self.meta_game.manager.game_menu
        game_menu.points_label.text = "Word Points: %s" % round(
            self.current_word["points"], 2)
        game_menu.word_input.text = str(self.current_word[self.languages[1]])
        self.save_game()

    def update_word(self):
        print("update_word()", self.current_word)
        self.last_word = self.current_word.copy()
        print("self.last_word:", self.last_word)
        self.current_word = self.pick_random_word()
        print("self.current_word:", self.current_word)
        game_menu = self.meta_game.manager.game_menu
        game_menu.points_label.text = "Word Points: %s" % round(
            self.current_word["points"], 2)
        game_menu.word_label.text = self.current_word[self.languages[0]]
        game_menu.word_input.text = ""

    def quit(self):
        print("quit()")
        print(self.meta_game.manager.current)
        print(self.meta_game.manager.current_screen.previous_screen)
        previous_screen = self.meta_game.manager.current_screen.previous_screen
        if previous_screen:
            self.meta_game.manager.current = previous_screen
        else:
            exit()

    # load / save game:
    def load_game(self):
        try:
            with open(settings.SAVES_FILE) as f:
                data = json.load(f)
                self.points = data["points"]
                self.languages = data["languages"]
                self.words = data["words"]
                self.calc_number_of_words()
        except FileNotFoundError:
            pass

    def save_game(self):
        with open(settings.SAVES_FILE, "w") as f:
            data = {
                "points": self.points,
                "languages": self.languages,
                "words": self.words
            }
            json.dump(data, f, indent=4)