-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathelements.py
113 lines (91 loc) · 3.72 KB
/
elements.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
from __future__ import annotations
from enum import auto
from typing import Optional
from base_enum import BaseEnum
from data_structures.referential_array import ArrayR
class Element(BaseEnum):
"""
Element Class to store all different elements as constants, and associate indicies with them.
Example:
```
print(Element.FIRE.value) # 1
print(Element.GRASS.value) # 3
print(Element.from_string("Ice")) # Element.ICE
```
"""
FIRE = auto()
WATER = auto()
GRASS = auto()
BUG = auto()
DRAGON = auto()
ELECTRIC = auto()
FIGHTING = auto()
FLYING = auto()
GHOST = auto()
GROUND = auto()
ICE = auto()
NORMAL = auto()
POISON = auto()
PSYCHIC = auto()
ROCK = auto()
FAIRY = auto()
DARK = auto()
STEEL = auto()
@classmethod
def from_string(cls, string: str) -> Element:
for elem in Element:
if elem.name.lower() == string.lower():
return elem
raise ValueError(f"Unexpected string {string}")
class EffectivenessCalculator:
"""
Helper class for calculating the element effectiveness for two elements.
This class follows the singleton pattern.
Usage:
EffectivenessCalculator.get_effectiveness(elem1, elem2)
"""
instance: Optional[EffectivenessCalculator] = None
def __init__(self, element_names: ArrayR[str], effectiveness_values: ArrayR[float]) -> None:
"""
Initialise the Effectiveness Calculator.
The first parameter is an ArrayR of size n containing all element_names.
The second parameter is an ArrayR of size n*n, containing all effectiveness values.
The first n values in the array is the effectiveness of the first element
against all other elements, in the same order as element_names.
The next n values is the same, but the effectiveness of the second element, and so on.
Example:
element_names: ['Fire', 'Water', 'Grass']
effectivness_values: [0.5, 0.5, 2, 2, 0.5, 0.5, 0.5, 2, 0.5]
Fire is half effective to Fire and Water, and double effective to Grass [0.5, 0.5, 2]
Water is double effective to Fire, and half effective to Water and Grass [2, 0.5, 0.5]
Grass is half effective to Fire and Grass, and double effective to Water [0.5, 2, 0.5]
"""
raise NotImplementedError
@classmethod
def get_effectiveness(cls, type1: Element, type2: Element) -> float:
"""
Returns the effectivness of elem1 attacking elem2.
Example: EffectivenessCalculator.get_effectiveness(Element.FIRE, Element.WATER) == 0.5
"""
raise NotImplementedError
@classmethod
def from_csv(cls, csv_file: str) -> EffectivenessCalculator:
# NOTE: This is a terrible way to open csv files, if writing your own code use the `csv` module.
# This is done this way to facilitate the second half of the task, the __init__ definition.
with open(csv_file, "r") as file:
header, rest = file.read().strip().split("\n", maxsplit=1)
header = header.split(",")
rest = rest.replace("\n", ",").split(",")
a_header = ArrayR(len(header))
a_all = ArrayR(len(rest))
for i in range(len(header)):
a_header[i] = header[i]
for i in range(len(rest)):
a_all[i] = float(rest[i])
return EffectivenessCalculator(a_header, a_all)
@classmethod
def make_singleton(cls):
cls.instance = EffectivenessCalculator.from_csv("type_effectiveness.csv")
EffectivenessCalculator.make_singleton()
if __name__ == "__main__":
print(EffectivenessCalculator.get_effectiveness(Element.FIRE, Element.WATER))