Created
January 26, 2015 07:25
-
-
Save hinchley/3c5114d23a17bd0cd8e8 to your computer and use it in GitHub Desktop.
Enigma M3 Machine in PHP
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
<?php namespace Enigma; | |
class Reflector { | |
protected $table; | |
public function __construct($table) { | |
$this->table = array_combine(range('A', 'Z'), str_split($table)); | |
} | |
public function convert($character) { | |
return $this->table[$character]; | |
} | |
public static function select($type) { | |
switch ($type) { | |
case 'A': | |
return new static('EJMZALYXVBWFCRQUONTSPIKHGD'); | |
case 'B': | |
return new static('YRUHQSLDPXNGOKMIEBFZCWVJAT'); | |
case 'C': | |
return new static('FVPJIAOYEDRZXWGCTKUQSBNMHL'); | |
} | |
throw new \InvalidArgumentException('Invalid Reflector'); | |
} | |
} | |
class Plugboard { | |
protected $plugs; | |
public function __construct(array $plugs) { | |
$this->plugs = $plugs + array_flip($plugs); | |
} | |
public function convert($character) { | |
return isset($this->plugs[$character]) ? | |
$this->plugs[$character] : $character; | |
} | |
} | |
class Rotor { | |
protected $table; | |
protected $notch; | |
public function __construct($table, array $notch) { | |
$this->table = array_combine(range('A', 'Z'), str_split($table)); | |
$this->notch = $notch; | |
} | |
public function step() { | |
$keys = array_keys($this->table); | |
array_unshift($keys, array_pop($keys)); | |
$vals = array_map(function($c) { | |
$i = ord($c) - 1; | |
return $i < 65 ? 'Z' : chr($i); | |
}, array_values($this->table)); | |
$this->table = array_combine($keys, $vals); | |
} | |
public function set($character) { | |
for ($i = 0; $i < ord($character) - 65; $i++) | |
$this->step(); | |
} | |
public function notched() { | |
return in_array(current($this->table), $this->notch); | |
} | |
public function in($character) { | |
return $this->table[$character]; | |
} | |
public function out($character) { | |
return array_flip($this->table)[$character]; | |
} | |
public static function select($type) { | |
switch ($type) { | |
case 'I': | |
return new static('EKMFLGDQVZNTOWYHXUSPAIBRCJ', ['Q']); | |
case 'II': | |
return new static('AJDKSIRUXBLHWTMCQGZNPYFVOE', ['E']); | |
case 'III': | |
return new static('BDFHJLCPRTXVZNYEIWGAKMUSQO', ['V']); | |
case 'IV': | |
return new static('ESOVPZJAYQUIRHXLNFTGKDCMWB', ['J']); | |
case 'V': | |
return new static('VZBRGITYUPSDNHLXAWMJQOFECK', ['Z']); | |
case 'VI': | |
return new static('JPGVOUMFYQBENHZRDKASXLICTW', ['Z', 'M']); | |
case 'VII': | |
return new static('NZJHGRCXMYSWBOUFAIVLPEKQDT', ['Z', 'M']); | |
case 'VII': | |
return new static('FKQHTLXOCBJSPDZRAMEWNIUYGV', ['Z', 'M']); | |
} | |
throw new \InvalidArgumentException('Invalid Rotor'); | |
} | |
} | |
class Rotors { | |
protected $rotors; | |
public function __construct(...$rotors) { | |
$this->rotors = array_reverse($rotors); | |
} | |
public function step() { | |
reset($this->rotors); | |
do { | |
current($this->rotors)->step(); | |
} while (next($this->rotors)->notched()); | |
} | |
public function in($character) { | |
foreach ($this->rotors as $rotor) | |
$character = $rotor->in($character); | |
return $character; | |
} | |
public function out($character) { | |
foreach (array_reverse($this->rotors) as $rotor) | |
$character = $rotor->out($character); | |
return $character; | |
} | |
} | |
class Machine { | |
protected $plugboard; | |
protected $reflector; | |
protected $rotors; | |
public function __construct($plugboard, $reflector, $rotors) { | |
$this->plugboard = $plugboard; | |
$this->reflector = $reflector; | |
$this->rotors = $rotors; | |
} | |
protected function clean($text) { | |
return preg_replace('/[^A-Z]/', '', strtoupper($text)); | |
} | |
public function convert($text) { | |
$output = ''; | |
foreach (str_split($this->clean($text)) as $c) { | |
$this->rotors->step(); | |
$c = $this->plugboard->convert($c); | |
$c = $this->rotors->in($c); | |
$c = $this->reflector->convert($c); | |
$c = $this->rotors->out($c); | |
$c = $this->plugboard->convert($c); | |
$output .= $c; | |
} | |
return $output; | |
} | |
} | |
// example usage. | |
$plugboard = new Plugboard(['H' => 'F']); | |
$reflector = Reflector::select('B'); | |
$i = Rotor::select('I'); | |
$ii = Rotor::select('II'); | |
$iii = Rotor::select('III'); | |
$i->set('B'); | |
$ii->set('B'); | |
$iii->set('B'); | |
$rotors = new Rotors($i, $ii, $iii); | |
$machine = new Machine($plugboard, $reflector, $rotors); | |
echo $machine->convert('ATTACKATDAWN'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment