Created
September 27, 2016 23:43
-
-
Save peterc/e5aa1315154813d0de48f9c555b8c055 to your computer and use it in GitHub Desktop.
Decoding and encoding of Solar Jetman (NES) passwords / game codes
This file contains 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
# Decoding and encoding of Solar Jetman (NES) | |
# game password codes | |
# | |
# Based on research done by Bisqwit / Joel Yliluoma | |
# See https://www.youtube.com/watch?v=Ex1iFZuUdJ4 | |
SYMBOLS = %w{B D G H K L M N P Q R T V W X Z} | |
def checksum_for_bytes(bytes) | |
((((bytes[0] ^ bytes[1]) + bytes[2]) ^ bytes[4]) * 257 / 256 + bytes[5]) & 0b11111111 | |
end | |
def decode(code) | |
{}.tap do |o| | |
nibbles = code.chars.map { |c| SYMBOLS.index(c) } | |
bytes = nibbles.each_slice(6).to_a.transpose.map { |a, b| (a << 4) + b } | |
o[:extra_lives] = (bytes[0] & 0b11110000) >> 4 | |
o[:level] = (bytes[2] & 0b11111100) >> 2 | |
o[:map] = bytes[2] & 1 | |
o[:map2] = (bytes[2] & 2) >> 1 | |
o[:booster] = bytes[4] & 1 | |
o[:shield] = (bytes[4] & 2) >> 1 | |
o[:pod] = (bytes[4] & 0b1100) >> 2 | |
o[:score] = (bytes[5] & 0b1111) * 100000 + (bytes[1] & 0b1111) * 10000 + (bytes[0] & 0b1111) * 1000 + ((bytes[4] & 0b11110000) >> 4) * 100 + ((bytes[5] & 0b11110000) >> 4) * 10 + ((bytes[1] & 0b11110000) >> 4) | |
raise "Invalid code" unless bytes[3] == checksum_for_bytes(bytes) | |
end | |
end | |
def encode(o) | |
bytes = [] | |
bytes[0] = (o[:extra_lives] << 4) + ((o[:score] % 10000) / 1000) | |
bytes[1] = ((o[:score] % 10) << 4) + ((o[:score] % 100000) / 10000) | |
bytes[2] = (o[:level] << 2) + (o[:map2] << 1) + o[:map] | |
bytes[4] = (((o[:score] % 1000) / 100) << 4) + (o[:pod] << 2) + (o[:shield] << 1) + o[:booster] | |
bytes[5] = (((o[:score] % 100) / 10) << 4) + ((o[:score] % 1000000) / 100000) | |
bytes[3] = checksum_for_bytes(bytes) | |
bytes.map { |b| [(b & 0b11110000) >> 4, b & 0b1111] }.transpose.flatten.map { |c| SYMBOLS[c] }.join | |
end | |
# Decode an existing code | |
data = decode("PMGPBPBBZLTB") | |
puts "Extra lives: #{data[:extra_lives]}\t\tLevel: #{data[:level]}" | |
puts "Map: #{data[:map]}\t\t\tMap2: #{data[:map2]}" | |
puts "Booster: #{data[:booster]}\t\tShield: #{data[:shield]}" | |
puts "Pod: #{data[:pod]}\t\t\tScore: #{data[:score]}" | |
# Create a new code | |
puts encode(extra_lives: 8, level: 11, map: 1, map2: 1, booster: 1, shield: 1, pod: 2, score: 86) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment