Last active
May 14, 2024 13:38
-
-
Save Pinacolada64/299ec94b96c6839cc7a643f4079e740c to your computer and use it in GitHub Desktop.
Flag operations using Enum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
from enum import Enum | |
from dataclasses import dataclass, field | |
from typing import Tuple | |
import doctest | |
@dataclass | |
class PlayerFlagTypes(str, Enum): | |
YESNO: str = "yes/no" | |
TRUEFALSE: str = "true/false" | |
ONOFF: str = "on/off" | |
class PlayerFlag(tuple, Enum): | |
# (display_name, flag_type, default_flag_status: bool) | |
ARCHITECT = ("Architect", PlayerFlagTypes.YESNO, False) | |
DUNGEON_MASTER = ("Dungeon Master", PlayerFlagTypes.YESNO, False) | |
# a speaker on a chat channel/in an amphitheater (public chat room): | |
ORATOR = ("Orator", PlayerFlagTypes.YESNO, False) | |
# guild stuff: | |
GUILD_AUTODUEL = ("Guild Autoduel", PlayerFlagTypes.ONOFF, False) | |
GUILD_FOLLOW_MODE = ("Guild Follow Mode", PlayerFlagTypes.ONOFF, False) | |
GUILD_MEMBER = ("Guild Member", PlayerFlagTypes.YESNO, False) | |
# toggles: | |
EXPERT_MODE = ("Expert Mode", PlayerFlagTypes.ONOFF, False) | |
HOURGLASS = ("Hourglass", PlayerFlagTypes.ONOFF, True) | |
MORE_PROMPT = ("More Prompt", PlayerFlagTypes.ONOFF, True) | |
ROOM_DESCRIPTIONS = ("Room Descriptions", PlayerFlagTypes.ONOFF, True) | |
# health: | |
DISEASE = ("Diseased", PlayerFlagTypes.YESNO, False) | |
HUNGER = ("Hungry", PlayerFlagTypes.YESNO, False) | |
POISON = ("Poisoned", PlayerFlagTypes.YESNO, False) | |
THIRST = ("Thirsty", PlayerFlagTypes.YESNO, False) | |
TIRED = ("Tired", PlayerFlagTypes.YESNO, False) | |
UNCONSCIOUS = ("Unconscious", PlayerFlagTypes.YESNO, False) | |
# horse: | |
HAS_HORSE = ("Has horse", PlayerFlagTypes.YESNO, False) | |
MOUNTED = ("Mounted on horse", PlayerFlagTypes.YESNO, False) | |
@dataclass | |
class Flag(object): | |
flag_name: str | |
# should Flag introspect the flag type from PlayerFlagTypes in order to | |
# avoid repeating 'flag_type' here from PlayerFlagTypes? | |
flag_type: PlayerFlagTypes | |
flag_status: bool | |
@dataclass | |
class Player(object): | |
name: str | |
bad_hombre_rating: int | |
""" | |
suggested by gemini: | |
flags: list[PlayerFlag] = field(default_factory=lambda: [ | |
PlayerFlag(flag.name, PlayerFlagTypes[flag.value.split()[1]]) | |
for flag in PlayerFlagNames | |
""" | |
# Initialize flags on object creation: | |
flags: list[Flag] = field(default_factory=lambda: [Flag(flag_name=flag_element[0], flag_type=flag_element[1], flag_status=flag_element[2]) | |
for flag_element in PlayerFlag]) | |
def clear_flag(self, flag_name: str): | |
for flag in self.flags: | |
if flag.flag_name == flag_name: | |
flag.flag_status = False | |
return # Flag found and cleared, exit the loop | |
def set_flag(self, flag_name: PlayerFlag): | |
for flag in self.flags: | |
if flag.flag_name == flag_name: | |
flag.flag_status = True | |
# Flag found and set, exit the loop | |
return | |
def show_flag(self, flag: PlayerFlag, dot_leader=False, lead_number=None) -> str: | |
""" | |
display the flag status using the proper string based on the type of flag it is | |
:param flag: name of flag to display | |
:param dot_leader: True lists the flag prefixed with a number, "...:" and the status | |
:returns: str | |
""" | |
try: | |
name = flag.flag_name # lowercased version of Enum string | |
status = flag.flag_status | |
flag_type = flag.flag_type | |
logging.info(f"{name=}, {status=}, {flag_type=}") | |
if flag.flag_type is PlayerFlagTypes.YESNO: | |
result = "Yes" if flag.flag_status else "No" | |
elif flag.flag_type is PlayerFlagTypes.ONOFF: | |
result = "On" if flag.flag_status else "Off" | |
elif flag.flag_type is PlayerFlagTypes.TRUEFALSE: | |
result = "True" if flag.flag_status else "False" | |
else: | |
result = "N/A" | |
if dot_leader: | |
print(f"{lead_number:>2}. {name:.<20}: {result}") | |
else: | |
print(f"{name}: {result}") | |
except ValueError: | |
logging.warning(f"Can't show unknown flag: {flag}") | |
"""" | |
def toggle_flag(self, flag: Flag): | |
try: | |
if flag.flag_name: | |
flag.flag_status = not flag.flag_status | |
except ValueError: | |
logging.warning(f"Can't toggle unknown flag: {flag}") | |
""" | |
if __name__ == '__main__': | |
# set up logging: | |
logging.basicConfig(level=logging.DEBUG) | |
# set up doctest: | |
doctest.testmod(verbose=True) | |
# understand some things: | |
""" | |
for i in PlayerFlag: | |
# i[0] = title case name, i[1] = True/False, Yes/No, On/Off, i[2] = True/False | |
print(i[0], i[1], i[2]) | |
""" | |
test = PlayerFlag.UNCONSCIOUS | |
print(f'Name: {test[0]}, Type: {test[1]}, Value: {test[2]}') | |
""" | |
>>> test_player = Player(name="test", bad_hombre_rating=100) | |
>>> print(test_player.show_flag(PlayerFlag.UNCONSCIOUS)) | |
Unconscious: No | |
""" | |
rulan = Player(name="Rulan", bad_hombre_rating=100) | |
print("Show bare flags:") | |
for flag in rulan.flags: | |
rulan.show_flag(flag) | |
print("Show dot leaders and flags:") | |
for number, flag in enumerate(rulan.flags, start=1): | |
rulan.show_flag(flag, dot_leader=True, lead_number=number) | |
# rulan.show_flag(rulan.flags[UNCONSCIOUS]) | |
# rulan.toggle_flag(flag=PlayerFlag.UNCONSCIOUS) | |
# rulan.show_flag(flag=PlayerFlagNames.UNCONSCIOUS) | |
""" | |
jasmine = Player(name="Jasmine", bad_hombre_rating=20 | |
# flags=[PlayerFlag(flag_name=PlayerFlags.EXPERT_MODE, | |
# flag_type=PlayerFlagTypes.TRUEFALSE, | |
# flag_status=True)] | |
) | |
# logging.basicConfig(level=logging.DEBUG, format=f'[{levelname}] | {message}') | |
logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] | %(message)s') | |
# https://www.reddit.com/r/learnpython/comments/z56z3m/how_can_i_create_key_value_dictionary_from_list/ | |
# data = dict(next(iter(d.items())) for d in features) | |
# 1) show_flag(flag_name) -> str | |
print() | |
print(rulan.show_flag(PlayerFlag.DUNGEON_MASTER)) | |
# Dungeon Master: Yes | |
print() | |
print("Menu format:") | |
print(rulan.show_flag(Flag.DUNGEON_MASTER, dot_leader=True, lead_number=1)) | |
# 1. Dungeon Master......: Yes | |
print() | |
print("Short format:") | |
print(jasmine.show_flag(Flag.HUNGER)) | |
# Hungry: No | |
print() | |
print("Show all four flag states:") | |
print(rulan.show_flag(Flag.THIRST)) | |
# Thirsty: Yes | |
print(rulan.show_flag(Flag.HUNGER)) | |
# Hungry: No | |
print(rulan.show_flag(Flag.ROOM_DESCRIPTIONS)) | |
# Room Descriptions: On | |
print(rulan.show_flag(PlayerFlag.HOURGLASS)) | |
# Hourglass: Off | |
# print("Deliberate error:") | |
# print(rulan.show_flag(PlayerFlag.BUNK)) | |
# <<error>> | |
print() | |
print("toggle_flag():") | |
""" | |
""" | |
>>> print(jasmine.show_flag(PlayerFlag.UNCONSCIOUS)) | |
Unconscious: Yes | |
>>> jasmine.toggle_flag(PlayerFlag.UNCONSCIOUS) | |
>>> print(jasmine.show_flag(PlayerFlag.UNCONSCIOUS)) | |
Unconscious: No | |
""" | |
""" | |
print() | |
print("List all Jasmine's flags:") | |
count = 0 | |
for i, v in enumerate(jasmine.flags): | |
print(jasmine.show_flag(v, dot_leader=True)) | |
""" |
Much closer to expected output!
16 items had no tests:
__main__
__main__.Flag
__main__.Flag.__eq__
__main__.Flag.__init__
__main__.Flag.__repr__
__main__.Player
__main__.Player.__eq__
__main__.Player.__init__
__main__.Player.__repr__
__main__.Player.clear_flag
__main__.Player.set_flag
__main__.Player.show_flag
__main__.PlayerFlag
__main__.PlayerFlagTypes
__main__.PlayerFlagTypes.__eq__
__main__.PlayerFlagTypes.__init__
0 tests in 16 items.
0 passed and 0 failed.
Test passed.
Name: Unconscious, Type: yes/no, Value: False
Architect: No
None
Dungeon Master: No
None
Orator: No
None
Guild Autoduel: Off
None
Guild Follow Mode: Off
None
Guild Member: No
None
Expert Mode: Off
None
Hourglass: On
None
More Prompt: On
None
Room Descriptions: On
None
Diseased: No
None
Hungry: No
None
Poisoned: No
None
Thirsty: No
None
Tired: No
None
Unconscious: No
None
Has horse: No
None
Mounted on horse: No
None
16 items had no tests:
__main__
__main__.Flag
__main__.Flag.__eq__
__main__.Flag.__init__
__main__.Flag.__repr__
__main__.Player
__main__.Player.__eq__
__main__.Player.__init__
__main__.Player.__repr__
__main__.Player.clear_flag
__main__.Player.set_flag
__main__.Player.show_flag
__main__.PlayerFlag
__main__.PlayerFlagTypes
__main__.PlayerFlagTypes.__eq__
__main__.PlayerFlagTypes.__init__
0 tests in 16 items.
0 passed and 0 failed.
Test passed.
Name: Unconscious, Type: yes/no, Value: False
Show bare flags:
Architect: No
Dungeon Master: No
Orator: No
Guild Autoduel: Off
Guild Follow Mode: Off
Guild Member: No
Expert Mode: Off
Hourglass: On
More Prompt: On
Room Descriptions: On
Diseased: No
Hungry: No
Poisoned: No
Thirsty: No
Tired: No
Unconscious: No
Has horse: No
Mounted on horse: No
Show dot leaders and flags:
1. Architect...........: No
2. Dungeon Master......: No
3. Orator..............: No
4. Guild Autoduel......: Off
5. Guild Follow Mode...: Off
6. Guild Member........: No
7. Expert Mode.........: Off
8. Hourglass...........: On
9. More Prompt.........: On
10. Room Descriptions...: On
11. Diseased............: No
12. Hungry..............: No
13. Poisoned............: No
14. Thirsty.............: No
15. Tired...............: No
16. Unconscious.........: No
17. Has horse...........: No
18. Mounted on horse....: No
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unconscious, yes/no, False
ARCHITECT: None
DUNGEON_MASTER: None
ORATOR: None
GUILD_AUTODUEL: None
GUILD_FOLLOW_MODE: None
GUILD_MEMBER: None
EXPERT_MODE: None
HOURGLASS: None
MORE_PROMPT: None
ROOM_DESCRIPTIONS: None
DISEASE: None
HUNGER: None
POISON: None
THIRST: None
TIRED: None
UNCONSCIOUS: None
HAS_HORSE: None
MOUNTED: None