Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit d8e89b0727411f97f7c9e44b0c4b2d1b8af61810 0 parents
@kpshek authored
1  .rvmrc
@@ -0,0 +1 @@
+rvm use 1.9.3@mm2pwd --create
4 Gemfile
@@ -0,0 +1,4 @@
+source :rubygems
+
+gem 'rake', '10.0.3'
+gem 'rspec', '2.12.0'
202 LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2012 Kevin Shekleton
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
91 README.md
@@ -0,0 +1,91 @@
+# Mega Man 2 Password Generator #
+
+## Overview ##
+
+Mega Man 2, like many games of its era, utilized a password system in order to continue your progress between game sessions.
+This removed the need for a battery in the game catridge and allowed gamers to share passwords (and thus progress) with others.
+
+In Mega Man 2, the password is represented as a 5x5 grid in which the columns are labled 1-5 and the rows A-E. Each password
+is comprised of 9 cells which are 'set', indicated by a red dot.
+
+Thus, a password can be communicated as A5, B2, B4, C1, C3, C5, D4, D5, E2.
+
+Put another way, this 5x5 grid represents 25 bits in which a password always has exactly 9 bits set. Using this representation,
+the password algorithm can be expressed succinctly in terms of these bits and using basic bitwise operations.
+
+In the 25 bits, there are 5 words of 5 bits each where each word represents a row in the grid. The entire 25-bit password
+is thus comprised of the words A E D C B (using little endian). So, the first word (lowest 5 bits) are the 5 bits of the row B
+and the last word (bits 20-25) are the 6 bits of row A.
+
+### Words 1-4 (bits 1-20) ###
+
+A Mega Man 2 password has exactly 9 bits set. 8 of these bits represent the alive/defeated status of each of the 8 bosses in
+the game. The follow table illustrates the bit values for the alive/defeated status for each of the 8 bosses.
+
+Boss | Alive | Defeated
+---------- | ----- | --------
+Bubble Man | C3 | D1
+Air Man | D2 | E3
+Quick Man | C4 | B4
+Wood Man | B5 | D3
+Crash Man | E2 | C5
+Flash Man | E4 | C1
+Metal Man | E1 | E5
+Heat Man | D5 | B2
+
+Thus, if both Bubble Man and Air Man were defeated but all other bosses were still alive, this is represented as the following
+bits (1-20) 01111 10001 01000 10000.
+
+Row | E | D | C | B
+---- | ----- | ----- | ----- | -----
+Word | 01111 | 10001 | 01000 | 10000
+
+### E-Tank Word (bits 21-25) ###
+
+The last bit (9th) represents the number of E-Tanks Mega Man has. This is stored in the 5th word (row A) and represents bits
+21-25, the most significant bits of the password. Mega Man can have between 0-4 E-Tanks and this is encoded simply per the bit
+position in this last word. Thus, if Mega Man has 0 E-Tanks the word is 00001, 1 E-Tank is 00010, 2 E-Tanks is 00100, and so
+forth. Unlike the other words, the 5th word (row A) will thus only ever have a single bit set.
+
+The E-Tank word (row A) is important in that it encodes bits 1-20 by performing a rotate left operations on bits 1-20 by the
+number of E-Tanks that Mega Man has. Thus, if Mega Man has 2 E-Tanks, bits 1-20 are rotated left by 2 positions. If Mega Man
+has 0 E-Tanks, this is effectively a no-op. The table above illustrating the bits set for each of the 8 bosses represent the
+bits prior to the rotate left operation. The bits of the E-Tank word are not included in the left rotation.
+
+## Algorithm ##
+
+The algorithm for calculating a password can be summarized as follows:
+
+1. Set the bits of the first 4 words (rows B, C, D, E) based on the table above (bits 1-20)
+2. Rotate left bits 1-20 based on the number of E-Tanks
+3. Add the E-Tank word (bits 21-25) as the most significant word of the password
+
+## Setup ##
+
+To run mm2pwd you will need [Ruby](http://www.ruby-lang.org/) installed.
+mm2pwd has been tested with Ruby 1.9.3p362 which is the latest version as of this writing.
+
+## Running ##
+
+To run mm2pwd, simply open a terminal session in the root directory and execute the following command:
+
+ $ ./mm2pwd.rb
+
+Without an modification, this will generate a password in which Mega Man has all 4 E-Tanks and has defeated all 8 bosses. If you
+want to modify this, simply change the values in the initialize method.
+
+## License ##
+
+Copyright 2012 Kevin Shekleton
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
144 mm2pwd.rb
@@ -0,0 +1,144 @@
+#!/usr/bin/env ruby
+# coding: UTF-8
+
+# Copyright 2013 Kevin Shekleton
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Mm2Pwd
+ attr_accessor :e_tanks, :bubble_man, :air_man, :quick_man, :wood_man, :crash_man, :flash_man, :metal_man, :heat_man
+
+ # Initializes an instance of this class with the desired password properties.
+ # Change the instance variable values here to change the generated password.
+ #
+ # Returns an instance of Mm2Pwd.
+ def initialize
+ @e_tanks = 4
+
+ # alive (true) ; defeated (false)
+ @bubble_man = false
+ @air_man = false
+ @quick_man = false
+ @wood_man = false
+ @crash_man = false
+ @flash_man = false
+ @metal_man = false
+ @heat_man = false
+ end
+
+ # Public: Generates the password coordinates suitable for input in Mega Man 2.
+ #
+ # This method will also print the 25-bit password and coordinates to the console.
+ #
+ # Returns the Array of password coordinates (Strings) for this class.
+ def generate
+ bits = generate_password_bits
+ puts bits.to_s(2)
+
+ coordinates = bits_to_coordinates(bits)
+ puts coordinates.inspect
+
+ coordinates
+ end
+
+ private
+
+ # Internal: Generates the password bits (1-25).
+ #
+ # Returns the 25-bit password (Integer) for this class.
+ def generate_password_bits
+ # row E D C B
+ bits = 0b00000_00000_00000_00000
+
+ # Determine the boss bits (bits 1-20)
+ bits |= @bubble_man ? 0b00000_00000_00100_00000 : 0b00000_00001_00000_00000 # C3 / D1
+ bits |= @air_man ? 0b00000_00010_00000_00000 : 0b00100_00000_00000_00000 # D2 / E3
+ bits |= @quick_man ? 0b00000_00000_01000_00000 : 0b00000_00000_00000_01000 # C4 / B4
+ bits |= @wood_man ? 0b00000_00000_00000_10000 : 0b00000_00100_00000_00000 # B5 / D3
+ bits |= @crash_man ? 0b00010_00000_00000_00000 : 0b00000_00000_10000_00000 # E2 / C5
+ bits |= @flash_man ? 0b01000_00000_00000_00000 : 0b00000_00000_00001_00000 # E4 / C1
+ bits |= @metal_man ? 0b00001_00000_00000_00000 : 0b10000_00000_00000_00000 # E1 / E5
+ bits |= @heat_man ? 0b00000_10000_00000_00000 : 0b00000_00000_00000_00010 # D5 / B2
+
+ # Rotate bits left based on the number of E-Tanks
+ bits = rotate_left(bits, @e_tanks)
+
+ # Set the E-Tank bits
+ bits |= (1 << 20 + @e_tanks)
+
+ bits
+ end
+
+ # Internal: Given the following bits, returns the coordinates of the set bits.
+ #
+ # bits - [Integer] The 25-bit password.
+ #
+ # Examples
+ #
+ # bits_to_coordinates(0b10000_01000_00100_00010_00011)
+ # # => ['A5', 'B1', 'B2', 'C2', 'D3', 'E4']
+ #
+ # Returns the coordinates of the set bits expressed in terms of the grid.
+ def bits_to_coordinates(bits)
+ a = (bits & 0b11111_00000_00000_00000_00000) >> 20
+ e = (bits & 0b11111_00000_00000_00000) >> 15
+ d = (bits & 0b11111_00000_00000) >> 10
+ c = (bits & 0b11111_00000) >> 5
+ b = bits & 0b11111
+
+ coordinates = []
+
+ coordinates.push(*word_to_coordinates(:A, a))
+ coordinates.push(*word_to_coordinates(:B, b))
+ coordinates.push(*word_to_coordinates(:C, c))
+ coordinates.push(*word_to_coordinates(:D, d))
+ coordinates.push(*word_to_coordinates(:E, e))
+ end
+
+ # Internal: Given the following word, returns the coordinates of the set bits.
+ #
+ # row_name - [Symbol] The name of the row being evaluated
+ # word - [Integer] The word (5 bits) being evaluated
+ #
+ # Examples
+ #
+ # word_to_coordinates(:B, 0b01101)
+ # # => ['B1', 'B3', 'B4']
+ #
+ # Returns a non-nil Array of the coordinates that are 'set'.
+ def word_to_coordinates(row_name, word)
+ coordinates = []
+ 5.times do |i|
+ coordinates << "#{row_name}#{i+1}" if (word & (1 << i)) > 0
+ end
+
+ coordinates
+ end
+
+ # Internal: Rotate the bits of the given value left by the given shift
+ # Note that a word size of 20 is assumed
+ #
+ # value - [Integer] The bit value to shift
+ # shift - [Integer] The number of left shifts
+ #
+ # Examples
+ #
+ # rotate_left(0b01010_00000_00000_00000, 2)
+ # # => 0b01000_00000_00000_00001
+ #
+ # Returns the given value left shifted by the given shift.
+ def rotate_left(value, shift)
+ ((value << shift) | (value >> (20 - shift))) & 0xFFFFF
+ end
+end
+
+Mm2Pwd.new.generate
97 mm2pwd_spec.rb
@@ -0,0 +1,97 @@
+# coding: UTF-8
+
+# Copyright 2013 Kevin Shekleton
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require './mm2pwd'
+
+describe Mm2Pwd do
+ let(:m) { Mm2Pwd.new }
+
+ context '#initialize' do
+ it 'returns a non-nill instance' do
+ m.should be_an_instance_of(Mm2Pwd)
+ end
+ end
+
+ context '#generate' do
+ it 'returns the correct coordinates for 4 E-Tanks and all 8 bosses defeated' do
+ expect(m.generate).to eq(['A5', 'B2', 'B4', 'C1', 'C3', 'C5', 'D4', 'D5', 'E2'])
+ end
+
+ it 'returns the correct coordinates for 0 E-Tanks and all 8 bosses defeated' do
+ m.e_tanks = 0
+ expect(m.generate).to eq(['A1', 'B2', 'B4', 'C1', 'C5', 'D1', 'D3', 'E3', 'E5'])
+ end
+ end
+
+ context '#generate_password_bits' do
+ it 'returns the correct bits for 4 E-Tanks and all 8 bosses defeated' do
+ expect(m.send(:generate_password_bits)).to eq(0b10000_00010_11000_10101_01010)
+ end
+ end
+
+ context '#bits_to_coordinates' do
+ it 'returns no coordinates if all bits are unset' do
+ expect(m.send(:bits_to_coordinates, 0b00000_00000_00000_00000_00000)).to eq([])
+ end
+
+ it 'correctly pulls the 1st word (B)' do
+ expect(m.send(:bits_to_coordinates, 0b00000_00000_00000_00000_01110)).to eq(['B2', 'B3', 'B4'])
+ end
+
+ it 'correctly pulls the 2nd word (C)' do
+ expect(m.send(:bits_to_coordinates, 0b00000_00000_00000_11011_00000)).to eq(['C1', 'C2', 'C4', 'C5'])
+ end
+
+ it 'correctly pulls the 3rd word (D)' do
+ expect(m.send(:bits_to_coordinates, 0b00000_00000_00110_00000_00000)).to eq(['D2', 'D3'])
+ end
+
+ it 'correctly pulls the 4th word (E)' do
+ expect(m.send(:bits_to_coordinates, 0b00000_01001_00000_00000_00000)).to eq(['E1', 'E4'])
+ end
+
+ it 'correctly pulls the 5th word (A)' do
+ expect(m.send(:bits_to_coordinates, 0b10010_00000_00000_00000_00000)).to eq(['A2', 'A5'])
+ end
+ end
+
+ context '#word_to_coordinates' do
+ it 'correctly identifies the set bits when all bits are set' do
+ expect(m.send(:word_to_coordinates, :A, 0b11111)).to eq(['A1', 'A2', 'A3', 'A4', 'A5'])
+ end
+
+ it 'correctly identifies the set bits when all bits are unset' do
+ expect(m.send(:word_to_coordinates, :A, 0b00000)).to eq([])
+ end
+
+ it 'correctly identifies the set bits when there are a mixture of set and unset bits' do
+ expect(m.send(:word_to_coordinates, :A, 0b01010)).to eq(['A2', 'A4'])
+ end
+ end
+
+ context '#rotate_left' do
+ it 'correctly does not rotation if the shift is 0' do
+ expect(m.send(:rotate_left, 0b10000_00000_00000_00000, 0)).to eq(0b10000_00000_00000_00000)
+ end
+
+ it 'correctly roates and wraps values for a shift of 1' do
+ expect(m.send(:rotate_left, 0b10100_00000_00000_00000, 1)).to eq(0b01000_00000_00000_00001)
+ end
+
+ it 'correctly roates and wraps values for a shift of 2' do
+ expect(m.send(:rotate_left, 0b10100_00000_00000_00000, 2)).to eq(0b10000_00000_00000_00010)
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.