forked from pythonwars/PythonWars-1996
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bit.py
415 lines (337 loc) · 14.1 KB
/
bit.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# PythonWars copyright © 2020 by Paul Penner. All rights reserved. In order to
# use this codebase you must comply with all licenses.
#
# Original Diku Mud copyright © 1990, 1991 by Sebastian Hammer,
# Michael Seifert, Hans Henrik Stærfeldt, Tom Madsen, and Katja Nyboe.
#
# Merc Diku Mud improvements copyright © 1992, 1993 by Michael
# Chastain, Michael Quan, and Mitchell Tse.
#
# ROM 2.4 is copyright 1993-1998 Russ Taylor. ROM has been brought to
# you by the ROM consortium: Russ Taylor (rtaylor@hypercube.org),
# Gabrielle Taylor (gtaylor@hypercube.org), and Brian Moore (zump@rom.org).
#
# Ported to Python by Davion of MudBytes.net using Miniboa
# (https://code.google.com/p/miniboa/).
#
# In order to use any part of this Merc Diku Mud, you must comply with
# both the original Diku license in 'license.doc' as well the Merc
# license in 'license.txt'. In particular, you may not remove either of
# these copyright notices.
#
# Much time and thought has gone into this software, and you are
# benefiting. We hope that you share your changes too. What goes
# around, comes around.
from collections import OrderedDict
import json
import game_utils
import state_checks
import tables
class Bit:
"""
The Bit() class is meant to be a drop-in replacement for the old
DikuMUD style 'bitflag' variable. Because DikuMUD was written on
limited hardware, many techniques were used to try and fit as much
data as possible into a small amount of memory.
Rather than using distinct variables, 32 boolean values were
crammed into a single integer, with each bit being assigned a
use. #define'd macros were created to make it somewhat eaasier
to check, set, and clear them. And, in Rom and later derivatives,
functions were made to convert them to and from textual names, so
they could be stored in area files without worrying about architecture
changes screwing up the order.
This class reimplements that concept, but in a more useful way. You
can directly use a set of names to set, clear, or check a bit. You can
use a list of names to do this for multiples at a time. You can get back
the name OR numerical value, and you can still use the numbers if you
like.
"""
def __init__(self, default: int = 0, flags: str = None, flagset_name: str = None):
"""
The constructor allows you to specify the default value, as
well as providing an ordered dict which will be used for
bit position/name to number mapping.
:param default: An integer of the starting bit values, usually 0.
:type default: int
:param flags: An ordered dict holding the name/number mappings used.
:type flags: OrderedDict
:return:
:rtype:
"""
self.bits = default
self.flagset_name = flagset_name
if flagset_name is not None:
self._flags = tables.bit_flags[flagset_name]
elif flags is not None:
self._flags = flags
def __add__(self, other):
"""
This implements addition between integers and Bit() objects.
It creates a new Bit() object containing the result.
:param other: An integer value to be numerically added to self.bits.
:type other: int
:return: A new Bit() object with the value added.
:rtype: Bit
"""
return Bit(self.bits + self.from_name(other), flags=self.flags)
def __radd__(self, other):
"""
This implements addition between integers and Bit() objects.
It creates a new Bit() object containing the result.
This version is for the reversed form, where the right-hand side is
the Bit() object.
:param other: An integer value to be numerically added to self.bits.
:type other: int
:return: A new Bit() object with the value added.
:rtype: Bit
"""
return Bit(self.from_name(other) + self.bits, flags=self.flags)
def __iadd__(self, other):
"""
This adds the given integer value to the Bit() object and
returns the Bit() object with the new value.
:param other: An integer value to be numerically added to self.bits.
:type other: int
:return: A new Bit() object with the value added.
:rtype: Bit
"""
self.bits += self.from_name(other)
return self
def __sub__(self, other):
return Bit(self.bits - self.from_name(other), flags=self.flags)
def __rsub__(self, other):
return Bit(self.from_name(other) - self.bits, flags=self.flags)
def __isub__(self, other):
self.bits -= self.from_name(other)
return self
def __mul__(self, other):
if isinstance(other, int):
return Bit(self.bits * other, flags=self.flags)
raise TypeError("You can only multiply a Bit() value by an integer, not a " + repr(other))
def __rmul__(self, other):
if isinstance(other, int):
return Bit(other * self.bits, flags=self.flags)
raise TypeError("You can only multiply a Bit() value by an integer, not a " + repr(other))
def __imul__(self, other):
if isinstance(other, int):
self.bits *= other
return self
raise TypeError("You can only multiply a Bit() value by an integer, not a " + repr(other))
def __truediv__(self, other):
if isinstance(other, int):
return Bit(self.bits // other, flags=self.flags)
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __rtruediv__(self, other):
if isinstance(other, int):
return Bit(other // self.bits, flags=self.flags)
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __itruediv__(self, other):
if isinstance(other, int):
self.bits //= other
return self
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __floordiv__(self, other):
if isinstance(other, int):
return Bit(self.bits // other, flags=self.flags)
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __rfloordiv__(self, other):
if isinstance(other, int):
return Bit(other // self.bits, flags=self.flags)
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __ifloordiv__(self, other):
if isinstance(other, int):
self.bits //= other
return self
raise TypeError("You can only divide a Bit() value by an integer, not a " + repr(other))
def __mod__(self, other):
if isinstance(other, int):
return Bit(self.bits % other, flags=self.flags)
raise TypeError("You can only get the integer modulo of a Bit() value, not a " + repr(other))
def __rmod__(self, other):
if isinstance(other, int):
return Bit(other % self.bits, flags=self.flags)
raise TypeError("You can only get the integer modulo of a Bit() value, not a " + repr(other))
def __imod__(self, other):
if isinstance(other, int):
self.bits %= other
return self
raise TypeError("You can only get the integer modulo of a Bit() value, not a " + repr(other))
def __pow__(self, power, modulo=None):
if isinstance(power, int):
return Bit(self.bits ** power, flags=self.flags)
raise TypeError("You can only raise a Bit() value to an integer power, not a " + repr(power))
def __rpow__(self, power, modulo=None):
if isinstance(power, int):
return Bit(power ** self.bits, flags=self.flags)
raise TypeError("You can only raise a Bit() value to an integer power, not a " + repr(power))
def __ipow__(self, power, modulo=None):
if isinstance(power, int):
self.bits **= power
return self
raise TypeError("You can only raise a Bit() value to an integer power, not a " + repr(power))
def __lshift__(self, other):
if isinstance(other, int):
return Bit(self.bits << other, flags=self.flags)
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __rlshift__(self, other):
if isinstance(other, int):
return Bit(other << self.bits, flags=self.flags)
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __ilshift__(self, other):
if isinstance(other, int):
self.bits <<= other
return self
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __rshift__(self, other):
if isinstance(other, int):
return Bit(self.bits >> other, flags=self.flags)
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __rrshift__(self, other):
if isinstance(other, int):
return Bit(other >> self.bits, flags=self.flags)
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __irshift__(self, other):
if isinstance(other, int):
self.bits >>= other
return self
raise TypeError("You can only shift a Bit() value by an integer, not a " + repr(other))
def __and__(self, other):
return Bit(self.bits & self.from_name(other), flags=self.flags)
def __rand__(self, other):
return Bit(self.from_name(other) & self.bits, flags=self.flags)
def __iand__(self, other):
self.bits &= self.from_name(other)
return self
def __xor__(self, other):
return Bit(self.bits ^ self.from_name(other), flags=self.flags)
def __rxor__(self, other):
return Bit(self.from_name(other) ^ self.bits, flags=self.flags)
def __ixor__(self, other):
self.bits ^= self.from_name(other)
return self
def __or__(self, other):
return Bit(self.bits | self.from_name(other), flags=self.flags)
def __ror__(self, other):
return Bit(self.from_name(other) | self.bits, flags=self.flags)
def __ior__(self, other):
self.bits |= self.from_name(other)
return self
def __bool__(self):
return True if self.bits else False
def __neg__(self):
return Bit(-self.bits, flags=self.flags)
def __pos__(self):
return Bit(+self.bits, flags=self.flags)
def __abs__(self):
return Bit(abs(self.bits), flags=self.flags)
def __int__(self):
return self.bits
def __getattr__(self, name):
if not name.startswith("is_"):
raise AttributeError
flags = self.flags
flag = state_checks.name_lookup(flags, name[3:])
if not flag:
raise AttributeError
return self.is_set(flags[flag].bit)
@property
def flags(self):
flags = OrderedDict()
if type(self._flags) == list:
for d in self._flags:
for k, v in d:
flags[k] = v
else:
flags = self._flags
return flags
def name(self):
return self.flagset_name if self.flagset_name else "Flagset_name not set."
def erase(self):
self.bits = 0
def empty(self):
return self.bits == 0
def tog_bit(self, bit):
self.bits ^= self.from_name(bit)
def set_bit(self, bit):
self.bits |= self.from_name(bit)
def clear_bit(self, bit):
self.bits &= ~self.from_name(bit)
def rem_bit(self, bit):
self.bits &= ~self.from_name(bit)
def is_set(self, bit):
return self.bits & self.from_name(bit)
def read_bits(self, area, default=0):
area, bits = game_utils.read_flags(area)
self.set_bit(bits)
self.set_bit(default)
return area
# lets you chose the flag table. so act/plr flags will save correctly.
def print_flags(self, flags):
holder = self._flags
self._flags = flags
as_str = repr(self)
self._flags = holder
return as_str
def from_name(self, name):
if type(name) is int:
return name
elif type(name) is list or type(name) is tuple:
bitstring = name
elif isinstance(name, Bit):
bitstring = repr(name)
else:
name = name.strip()
bitstring = name.split(" ")
bits = 0
flags = self.flags
for tok in flags.values():
if tok.name in bitstring:
bits += tok.bit
return bits
def __repr__(self):
buf = ""
if not self.flags:
return buf
flags = self.flags
for k, fl in flags.items():
if self.is_set(fl.bit):
buf += " %s" % fl.name
return buf
def to_json(self, outer_encoder=None):
"""
This method implements the serialization of a Bit() object
for the JSON module to use.
:param outer_encoder:
:type outer_encoder:
:return: JSON serialization
:rtype: str
"""
if outer_encoder is None:
outer_encoder = json.JSONEncoder.default
cls_name = "__class__/" + __name__ + "." + self.__class__.__name__
return {
cls_name: {
"bits": outer_encoder(self.bits),
"flagset_name": outer_encoder(self.flagset_name),
}
}
@classmethod
def from_json(cls, data, outer_decoder=None):
"""
This class method implements turning a JSON serialization of the data
from a Bit() class back into an actual Bit() object.
:param data:
:type data:
:param outer_decoder:
:type outer_decoder:
:return: Bit() object or unrecognized data
:rtype:
"""
if outer_decoder is None:
outer_decoder = json.JSONDecoder.decode
cls_name = "__class__/" + __name__ + "." + cls.__name__
if cls_name in data:
return cls(default=outer_decoder(data[cls_name]["bits"]),
flagset_name=outer_decoder(data[cls_name]["flagset_name"]))
return data
bitvector_table = {}