| # Metroid (NES) Random Password Generator | |||||
| # Author: Noëlle Anthony | |||||
| # License: MIT | |||||
| # Date: October 2019 | |||||
| # This uses http://games.technoplaza.net/mpg/password.txt as a basis for its password algorithm | # This uses http://games.technoplaza.net/mpg/password.txt as a basis for its password algorithm | ||||
| import random, sys | import random, sys | ||||
| class MetroidState: | class MetroidState: | ||||
| """ Stores the game state | |||||
| """ | |||||
| def __init__(self): | def __init__(self): | ||||
| # Alphabet is 64 characters - 6 bits per character | |||||
| self.alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?-" | self.alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?-" | ||||
| # The password has different flags for "item available for pickup" and | |||||
| # "Samus has the item". I'm keeping them separate, but when the generator | |||||
| # selects an item as "picked up", that means Samus has it and it's not available. | |||||
| self.itemsCollected = { | self.itemsCollected = { | ||||
| "Maru Mari": False, | "Maru Mari": False, | ||||
| "Bombs": False, | "Bombs": False, | ||||
| "Varia": False, | "Varia": False, | ||||
| "Screw Attack": False | "Screw Attack": False | ||||
| } | } | ||||
| # Missile tanks are listed in the order in which they appear in the password, | |||||
| # NOT in zone order or in any reasonable collection order. | |||||
| self.missileTanks = { | self.missileTanks = { | ||||
| 1: False, | 1: False, | ||||
| 2: False, | 2: False, | ||||
| 20: False, | 20: False, | ||||
| 21: False | 21: False | ||||
| } | } | ||||
| # Likewise energy tanks are listed in password order. | |||||
| self.energyTanks = { | self.energyTanks = { | ||||
| 1: False, | 1: False, | ||||
| 2: False, | 2: False, | ||||
| 7: False, | 7: False, | ||||
| 8: False | 8: False | ||||
| } | } | ||||
| # This may be left-to-right (Samus approaches from the right). I haven't checked. | |||||
| self.zebetitesDestroyed = { | self.zebetitesDestroyed = { | ||||
| 1: False, | 1: False, | ||||
| 2: False, | 2: False, | ||||
| 4: False, | 4: False, | ||||
| 5: False | 5: False | ||||
| } | } | ||||
| # I'm not sure why I decided to segregate these by zone, except that that's how | |||||
| # truepeacein.space does it. | |||||
| self.doors = { | self.doors = { | ||||
| "Brinstar": { | "Brinstar": { | ||||
| 1: False, | 1: False, | ||||
| 3: False | 3: False | ||||
| } | } | ||||
| } | } | ||||
| # The next three are self-explanatory. | |||||
| self.kraidKilled = False | self.kraidKilled = False | ||||
| self.ridleyKilled = False | self.ridleyKilled = False | ||||
| self.motherBrainKilled = False | self.motherBrainKilled = False | ||||
| # The Kraid and Ridley statues rise when Kraid and Ridley are killed, but | |||||
| # their states are stored separately in the password. It's possible to | |||||
| # raise them without killing the bosses, granting early access to Tourian. | |||||
| self.kraidStatue = False | self.kraidStatue = False | ||||
| self.ridleyStatue = False | self.ridleyStatue = False | ||||
| # Is Samus wearing her armor (False) or her swimsuit (True)? | |||||
| self.swimsuit = False | self.swimsuit = False | ||||
| # 0-255. You can have more missiles than 5*collected tanks (in fact, you | |||||
| # can only collect 21 tanks - thus 105 missiles - but can have up to 255 | |||||
| # missiles in your inventory). | |||||
| self.missileCount = 0 | self.missileCount = 0 | ||||
| # How advanced is the game clock? After 3 hours you don't get the good ending. | |||||
| self.gameAge = 0 | self.gameAge = 0 | ||||
| # There are five possible start locations: Brinstar, where you start, and | |||||
| # at the bottom of the elevator where you enter each subsequent zone. | |||||
| self.locations = ["Brinstar", "Norfair", "Kraid's Lair", "Ridley's Lair", "Tourian"] | self.locations = ["Brinstar", "Norfair", "Kraid's Lair", "Ridley's Lair", "Tourian"] | ||||
| self.startLocation = 0 | self.startLocation = 0 | ||||
| # Arrays to store the 144 bits that compose the password | |||||
| self.bitfield = [] | self.bitfield = [] | ||||
| self.initializeBitfield() | self.initializeBitfield() | ||||
| self.fullbitfield = [] | self.fullbitfield = [] | ||||
| def initializeBitfield(self): | def initializeBitfield(self): | ||||
| """ Set the first 128 bits of the bitfield to 0. | |||||
| The remaining 16 bits will be set later. | |||||
| """ | |||||
| self.bitfield = [] | self.bitfield = [] | ||||
| for _ in range(128): | for _ in range(128): | ||||
| self.bitfield.append(0) | self.bitfield.append(0) | ||||
| def toggleItem(self, itm): | def toggleItem(self, itm): | ||||
| """ Mark an item as collected or uncollected. | |||||
| """ | |||||
| if itm in self.itemsCollected.keys(): | if itm in self.itemsCollected.keys(): | ||||
| self.itemsCollected[itm] = not self.itemsCollected[itm] | self.itemsCollected[itm] = not self.itemsCollected[itm] | ||||
| self.samusHas[itm] = not self.samusHas[itm] | self.samusHas[itm] = not self.samusHas[itm] | ||||
| print("Couldn't find item: {}".format(str(itm))) | print("Couldn't find item: {}".format(str(itm))) | ||||
| def toggleMissileTank(self, num): | def toggleMissileTank(self, num): | ||||
| """ Mark a missile tank as collected or uncollected. | |||||
| """ | |||||
| try: | try: | ||||
| num = int(num) | num = int(num) | ||||
| except: | except: | ||||
| print("Couldn't find missile tank: {}".format(num)) | print("Couldn't find missile tank: {}".format(num)) | ||||
| def toggleEnergyTank(self, num): | def toggleEnergyTank(self, num): | ||||
| """ Mark an energy tank as collected or uncollected. | |||||
| """ | |||||
| try: | try: | ||||
| num = int(num) | num = int(num) | ||||
| except: | except: | ||||
| print("Couldn't find energy tank: {}".format(num)) | print("Couldn't find energy tank: {}".format(num)) | ||||
| def toggleZebetite(self, num): | def toggleZebetite(self, num): | ||||
| """ Mark a Zebetite stem as destroyed or intact. | |||||
| """ | |||||
| try: | try: | ||||
| num = int(num) | num = int(num) | ||||
| except: | except: | ||||
| print("Couldn't find Zebetite: {}".format(num)) | print("Couldn't find Zebetite: {}".format(num)) | ||||
| def toggleKraid(self): | def toggleKraid(self): | ||||
| """ Mark Kraid as killed or alive. | |||||
| """ | |||||
| self.kraidKilled = not self.kraidKilled | self.kraidKilled = not self.kraidKilled | ||||
| self.kraidStatue = self.kraidKilled | self.kraidStatue = self.kraidKilled | ||||
| def toggleKraidStatue(self): | def toggleKraidStatue(self): | ||||
| """ Mark Kraid's statue as raised or lowered. | |||||
| If Kraid is killed but his statue isn't raised, you can't complete the game. | |||||
| """ | |||||
| self.kraidStatue = not self.kraidStatue | self.kraidStatue = not self.kraidStatue | ||||
| if self.kraidKilled and not self.kraidStatue: | if self.kraidKilled and not self.kraidStatue: | ||||
| print("WARNING: Kraid has been killed but his statue has not been raised.") | print("WARNING: Kraid has been killed but his statue has not been raised.") | ||||
| def toggleRidley(self): | def toggleRidley(self): | ||||
| """ Mark Ridley as killed or alive. | |||||
| """ | |||||
| self.ridleyKilled = not self.ridleyKilled | self.ridleyKilled = not self.ridleyKilled | ||||
| self.ridleyStatue = self.ridleyKilled | self.ridleyStatue = self.ridleyKilled | ||||
| def toggleRidleyStatue(self): | def toggleRidleyStatue(self): | ||||
| """ Mark Ridley's statue as raised or lowered. | |||||
| If Ridley is killed but his statue isn't raised, you can't complete the game. | |||||
| """ | |||||
| self.ridleyStatue = not self.ridleyStatue | self.ridleyStatue = not self.ridleyStatue | ||||
| if self.ridleyKilled and not self.ridleyStatue: | if self.ridleyKilled and not self.ridleyStatue: | ||||
| print("WARNING: Ridley has been killed but his statue has not been raised.") | print("WARNING: Ridley has been killed but his statue has not been raised.") | ||||
| def toggleMotherBrain(self): | def toggleMotherBrain(self): | ||||
| """ Mark Mother Brain as killed or alive. | |||||
| If Mother Brain is marked as killed, the self-destruct timer won't go off | |||||
| when you reach her room. | |||||
| """ | |||||
| self.motherBrainKilled = not self.motherBrainKilled | self.motherBrainKilled = not self.motherBrainKilled | ||||
| def toggleDoor(self, area, door): | def toggleDoor(self, area, door): | ||||
| """ Mark a given red/yellow door as opened or locked. | |||||
| """ | |||||
| try: | try: | ||||
| area = str(area) | area = str(area) | ||||
| door = int(door) | door = int(door) | ||||
| print("Couldn't find door {} in area {}".format(door, area)) | print("Couldn't find door {} in area {}".format(door, area)) | ||||
| def toggleSwimsuit(self): | def toggleSwimsuit(self): | ||||
| """ Determine whether or not Samus is wearing her armor. | |||||
| """ | |||||
| self.swimsuit = not self.swimsuit | self.swimsuit = not self.swimsuit | ||||
| def newLocation(self, loc): | def newLocation(self, loc): | ||||
| """ Set a new starting location (0-4). | |||||
| """ | |||||
| try: | try: | ||||
| loc = str(loc) | loc = str(loc) | ||||
| except: | except: | ||||
| print("Couldn't find location: {}".format(loc)) | print("Couldn't find location: {}".format(loc)) | ||||
| def collectedItems(self): | def collectedItems(self): | ||||
| """ List which items have been collected. | |||||
| Under this generator's rules, if Samus doesn't have an item, | |||||
| it's available to be picked up. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| for k,v in self.itemsCollected.items(): | for k,v in self.itemsCollected.items(): | ||||
| if v == True: | if v == True: | ||||
| return ", ".join(o) | return ", ".join(o) | ||||
| def collectedMissiles(self): | def collectedMissiles(self): | ||||
| """ List which missile tanks have been collected. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| for k, v in self.missileTanks.items(): | for k, v in self.missileTanks.items(): | ||||
| if v == True: | if v == True: | ||||
| return ", ".join([str(b) for b in o]) | return ", ".join([str(b) for b in o]) | ||||
| def collectedEtanks(self): | def collectedEtanks(self): | ||||
| """ List which energy tanks have been collected. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| for k, v in self.energyTanks.items(): | for k, v in self.energyTanks.items(): | ||||
| if v == True: | if v == True: | ||||
| return ", ".join([str(b) for b in o]) | return ", ".join([str(b) for b in o]) | ||||
| def killedZebetites(self): | def killedZebetites(self): | ||||
| """ List which Zebetite stems have been destroyed. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| for k, v in self.zebetitesDestroyed.items(): | for k, v in self.zebetitesDestroyed.items(): | ||||
| if v == True: | if v == True: | ||||
| return ", ".join([str(b) for b in o]) | return ", ".join([str(b) for b in o]) | ||||
| def killedBosses(self): | def killedBosses(self): | ||||
| """ List which bosses have been killed. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| if self.kraidKilled: | if self.kraidKilled: | ||||
| o.append("Kraid") | o.append("Kraid") | ||||
| return ", ".join(o) | return ", ".join(o) | ||||
| def raisedStatues(self): | def raisedStatues(self): | ||||
| """ List which statues have been raised. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| if self.kraidStatue: | if self.kraidStatue: | ||||
| o.append("Kraid") | o.append("Kraid") | ||||
| return ", ".join(o) | return ", ".join(o) | ||||
| def inBailey(self): | def inBailey(self): | ||||
| """ Show whether Samus is in her swimsuit or not. | |||||
| 'inBailey' refers to an old (false) explanation of the JUSTIN BAILEY | |||||
| password, in which a 'bailey' was English slang for a bathing suit, | |||||
| so with that password, Samus was "Just In Bailey" - i.e. in her swimsuit. | |||||
| """ | |||||
| if self.swimsuit: | if self.swimsuit: | ||||
| return "Yes" | return "Yes" | ||||
| else: | else: | ||||
| return "No" | return "No" | ||||
| def openedDoors(self): | def openedDoors(self): | ||||
| """ List which red/yellow doors have been unlocked. | |||||
| """ | |||||
| d = {"Brinstar": 0, "Norfair": 0, "Kraid": 0, "Ridley": 0, "Tourian": 0} | d = {"Brinstar": 0, "Norfair": 0, "Kraid": 0, "Ridley": 0, "Tourian": 0} | ||||
| o = [] | o = [] | ||||
| for k,v in self.doors["Brinstar"].items(): | for k,v in self.doors["Brinstar"].items(): | ||||
| return ", ".join(o) | return ", ".join(o) | ||||
| def getBits(self): | def getBits(self): | ||||
| """ Return the bitfield in an easily-readable format. | |||||
| """ | |||||
| o = [] | o = [] | ||||
| word = [] | word = [] | ||||
| for i in range(128): | for i in range(128): | ||||
| return o1 + "\n" + o2 | return o1 + "\n" + o2 | ||||
| def toString(self): | def toString(self): | ||||
| """ Output the game state as a newline-delimited string. | |||||
| """ | |||||
| ic = "Items Collected: {}".format(self.collectedItems()) | ic = "Items Collected: {}".format(self.collectedItems()) | ||||
| mt = "Missile Tanks Collected: {}".format(self.collectedMissiles()) | mt = "Missile Tanks Collected: {}".format(self.collectedMissiles()) | ||||
| et = "Energy Tanks Collected: {}".format(self.collectedEtanks()) | et = "Energy Tanks Collected: {}".format(self.collectedEtanks()) | ||||
| dr = "Unlocked Doors: {}".format(self.openedDoors()) | dr = "Unlocked Doors: {}".format(self.openedDoors()) | ||||
| ms = "Missiles: {}".format(self.missileCount) | ms = "Missiles: {}".format(self.missileCount) | ||||
| pw = "Password: {}".format(self.password) | pw = "Password: {}".format(self.password) | ||||
| # bf = "Bitfield:\n{}".format(self.getBits()) | |||||
| return "\n".join([ic, mt, et, zb, kb, rs, sw, sl, dr, ms, pw]) | return "\n".join([ic, mt, et, zb, kb, rs, sw, sl, dr, ms, pw]) | ||||
| def randomize(self): | def randomize(self): | ||||
| """ The randomizer! | |||||
| """ | |||||
| # Items | # Items | ||||
| if random.randint(0,1) == 1: | if random.randint(0,1) == 1: | ||||
| self.toggleItem("Maru Mari") | self.toggleItem("Maru Mari") | ||||
| if random.randint(0,1) == 1: | if random.randint(0,1) == 1: | ||||
| self.doors["Tourian"][i+1] = True | self.doors["Tourian"][i+1] = True | ||||
| # Swimsuit | # Swimsuit | ||||
| # Samus has a 1/3 chance of spawning in her swimsuit. | |||||
| # There's no technical reason for this, just a personal choice. | |||||
| if random.randint(0,2) == 2: | if random.randint(0,2) == 2: | ||||
| self.toggleSwimsuit() | self.toggleSwimsuit() | ||||
| # Start Location | # Start Location | ||||
| self.missileCount = random.randint(0,255) | self.missileCount = random.randint(0,255) | ||||
| def createBitfield(self): | def createBitfield(self): | ||||
| """ Create the 144-bit field from the game state | |||||
| that will generate the password. | |||||
| """ | |||||
| self.initializeBitfield() | self.initializeBitfield() | ||||
| # Doing this in order, which is dumb and tedious but accurate. | # Doing this in order, which is dumb and tedious but accurate. | ||||
| if self.itemsCollected["Maru Mari"]: | if self.itemsCollected["Maru Mari"]: | ||||
| self.bitfield[57] = 1 | self.bitfield[57] = 1 | ||||
| if self.motherBrainKilled: | if self.motherBrainKilled: | ||||
| self.bitfield[58] = 1 | self.bitfield[58] = 1 | ||||
| # 59-63 unknown | # 59-63 unknown | ||||
| # if self.: | |||||
| # self.bitfield[59] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[60] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[61] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[62] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[63] = 1 | |||||
| # not 64, 65, or 66 = Brinstar | # not 64, 65, or 66 = Brinstar | ||||
| # 64 = Norfair | # 64 = Norfair | ||||
| # 65 and not 66 = Kraid's Lair | # 65 and not 66 = Kraid's Lair | ||||
| self.bitfield[65] = 1 | self.bitfield[65] = 1 | ||||
| if self.startLocation == 3 or self.startLocation == 4: | if self.startLocation == 3 or self.startLocation == 4: | ||||
| self.bitfield[66] = 1 | self.bitfield[66] = 1 | ||||
| # 67 is the reset bit, I want all passwords to be valid | # 67 is the reset bit, I want all passwords to be valid | ||||
| # if self.: | # if self.: | ||||
| # self.bitfield[67] = 1 | # self.bitfield[67] = 1 | ||||
| # 68-70 are unknown | # 68-70 are unknown | ||||
| # if self.: | |||||
| # self.bitfield[68] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[69] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[70] = 1 | |||||
| if self.swimsuit: | if self.swimsuit: | ||||
| self.bitfield[71] = 1 | self.bitfield[71] = 1 | ||||
| if self.samusHas["Bombs"]: | if self.samusHas["Bombs"]: | ||||
| self.bitfield[78] = 1 | self.bitfield[78] = 1 | ||||
| if self.samusHas["Ice Beam"]: | if self.samusHas["Ice Beam"]: | ||||
| self.bitfield[79] = 1 | self.bitfield[79] = 1 | ||||
| # Missile count | # Missile count | ||||
| # +2^n from 0 to 7 | # +2^n from 0 to 7 | ||||
| binMissiles = bin(self.missileCount).replace('0b','')[::-1] | binMissiles = bin(self.missileCount).replace('0b','')[::-1] | ||||
| if int(binMissiles[7]) == 1: | if int(binMissiles[7]) == 1: | ||||
| self.bitfield[87] = 1 | self.bitfield[87] = 1 | ||||
| # 88-119 are game age, leaving at 0 | # 88-119 are game age, leaving at 0 | ||||
| # if self.: | |||||
| # self.bitfield[88] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[89] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[90] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[91] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[92] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[93] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[94] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[95] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[96] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[97] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[98] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[99] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[100] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[101] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[102] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[103] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[104] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[105] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[106] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[107] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[108] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[109] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[110] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[111] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[112] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[113] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[114] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[115] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[116] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[117] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[118] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[119] = 1 | |||||
| # 120-123 are unknown | # 120-123 are unknown | ||||
| # if self.: | |||||
| # self.bitfield[120] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[121] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[122] = 1 | |||||
| # if self.: | |||||
| # self.bitfield[123] = 1 | |||||
| # I have no idea why these are at the end. I wonder if Kraid and | |||||
| # Ridley were relatively late additions to the game? (Or maybe | |||||
| # they were just implemented late in the game's development.) | |||||
| if self.ridleyKilled: | if self.ridleyKilled: | ||||
| self.bitfield[124] = 1 | self.bitfield[124] = 1 | ||||
| if self.ridleyStatue: | if self.ridleyStatue: | ||||
| self.bitfield[127] = 1 | self.bitfield[127] = 1 | ||||
| def generatePassword(self): | def generatePassword(self): | ||||
| """ Generate the password from the bitfield. | |||||
| This is a five-step process. | |||||
| 1) Reverse the order of each 8-bit byte to make it little-endian. | |||||
| 2) Cycle the entire bitfield 0-7 bits to the right. | |||||
| Append the number of shifts in binary to the end - again, little-endian. | |||||
| 3) Create the checksum by turning each byte into a decimal number, | |||||
| summing them, converting the sum *back* to binary, and taking the lowest | |||||
| 8 bits of that binary sum and adding it - BIG-ENDIAN - to the end. | |||||
| 4) Separate the bitstream into ***6-bit*** chunks and create a decimal | |||||
| number from each chunk (0-63). | |||||
| 5) Associate each decimal number with a letter from the Metroid Alphabet | |||||
| (listed at the top of __init__()). | |||||
| I'm not doing step 2 yet, which is equivalent to shifting 0 places | |||||
| and making the shift byte 00000000. | |||||
| """ | |||||
| # not gonna do the bit-shifting yet | # not gonna do the bit-shifting yet | ||||
| # shiftbit = random.randint(0,7) | |||||
| bitfield = self.bitfield | bitfield = self.bitfield | ||||
| # for _ in range(shiftbit): | |||||
| # [bitfield[127]] + bitfield[:127] | |||||
| # binShift = bin(shiftbit).replace('0b','') | |||||
| # while len(binShift) < 8: | |||||
| # binShift = "0" + binShift | |||||
| # for bit in binShift: | |||||
| # bitfield.append(int(bit)) | |||||
| bitfield = bitfield + [0,0,0,0,0,0,0,0] | |||||
| # checking = [] | |||||
| # for i in range(16): | |||||
| # checking.append(int("".join([str(x) for x in bitfield[i:i+8]]), 2)) | |||||
| # print("Full Bitfield: {}".format("".join([str(x) for x in bitfield]))) | |||||
| bitfield = bitfield + [0,0,0,0,0,0,0,0] # add the zero shift byte | |||||
| self.fullbitfield = "".join([str(x) for x in bitfield]) | self.fullbitfield = "".join([str(x) for x in bitfield]) | ||||
| newBitfield = [] | newBitfield = [] | ||||
| for i in range(17): | for i in range(17): | ||||
| checksum = binChecksum[-8:] | checksum = binChecksum[-8:] | ||||
| while len(checksum) < 8: | while len(checksum) < 8: | ||||
| checksum = "0" + checksum | checksum = "0" + checksum | ||||
| # print(checksum) | |||||
| for bit in checksum: | for bit in checksum: | ||||
| bitfield += bit | bitfield += bit | ||||
| # print("Real Bitfield: {}".format(bitfield)) | |||||
| letters = [] | letters = [] | ||||
| letter = [] | letter = [] | ||||
| return self.password | return self.password | ||||
| def decodePassword(self, pwd): | def decodePassword(self, pwd): | ||||
| """ Sanity checking! This function decodes an input password back into a bitfield, | |||||
| so that you can check that it was properly encoded. | |||||
| """ | |||||
| densePwd = pwd.replace(" ","") | densePwd = pwd.replace(" ","") | ||||
| numPwd = [] | numPwd = [] | ||||
| for chr in densePwd: | for chr in densePwd: | ||||
| while len(longword) < 6: | while len(longword) < 6: | ||||
| longword = "0" + longword | longword = "0" + longword | ||||
| longBitPwd.append(longword) | longBitPwd.append(longword) | ||||
| # print(self.fullbitfield) | |||||
| newBitfield = "".join(longBitPwd) | newBitfield = "".join(longBitPwd) | ||||
| # print(newBitfield) | |||||
| # print(newBitfield == self.fullbitfield) | |||||
| # print(len(newBitfield[:136])) | |||||
| # print(newBitfield[:136]) | |||||
| csm = sum([int(x) for x in newBitfield[:136]]) | csm = sum([int(x) for x in newBitfield[:136]]) | ||||
| print(csm) | print(csm) | ||||
| # print(bin(csm).replace("0b","")) | |||||
| for i in range(len(newBitfield)): | for i in range(len(newBitfield)): | ||||
| print(newBitfield[i], end="") | print(newBitfield[i], end="") | ||||
| if i%8 == 7: | if i%8 == 7: | ||||
| gs = MetroidState() | gs = MetroidState() | ||||
| gs.randomize() | gs.randomize() | ||||
| gs.createBitfield() | gs.createBitfield() | ||||
| pwd = gs.generatePassword() | |||||
| gs.generatePassword() | |||||
| print(gs.toString()) | print(gs.toString()) | ||||
| # print(pwd) | |||||
| # gs.decodePassword(pwd) | |||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||
| if len(sys.argv) == 2: | if len(sys.argv) == 2: |