using System;
using System.Console;
using System.Text;
using System.Security.Cryptography;
using Nemerle.Collections;
using Nemerle.Collections.NCollectionsExtensions;

module Md5
{
    HashMD5(input : string) : string
    {
        BitConverter.ToString
            (MD5.Create().ComputeHash(Encoding.Default.GetBytes(input))).Replace("-", "").ToLower()
    }

    IsValidMD5(text : string, hash : string) : bool
    {
        HashMD5(text) == hash.ToLower()
    }

    Main() : void
    {
        def examples = ["The quick brown fox jumped over the lazy dog's back", "", "a", "abc", "message digest",
                        "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
                        "12345678901234567890123456789012345678901234567890123456789012345678901234567890"];
        def hashes = ["e38ca1d920c4b8b8d3946b2c72f01680", "d41d8cd98f00b204e9800998ecf8427e",
                      "0cc175b9c0f1b6a831c399e269772661", "900150983cd24fb0d6963f7d28e17f72",
                      "f96b697d7cb7938d525a2f31aaf161d0", "c3fcd3d76192e4007dfb496cca67e13b",
                      "d174ab98d277d9f5a5611c2c9f419d9f", "57edf4a22be3c955ac49da2e2107b67a"];
        def tests = Hashtable(ZipLazy(examples, hashes));
        foreach (test in tests)
            Write($"$(IsValidMD5(test.Key, test.Value))   ");
    }
}


/* NetRexx */

options replace format comments java crossref savelog symbols binary

import java.security.MessageDigest

MD5('The quick brown fox jumps over the lazy dog', '9e107d9d372bb6826bd81d3542a419d6')
-- RFC 1321 MD5 test suite:
MD5("", 'd41d8cd98f00b204e9800998ecf8427e')
MD5("a", '0cc175b9c0f1b6a831c399e269772661')
MD5("abc", '900150983cd24fb0d6963f7d28e17f72')
MD5("message digest", 'f96b697d7cb7938d525a2f31aaf161d0')
MD5("abcdefghijklmnopqrstuvwxyz", 'c3fcd3d76192e4007dfb496cca67e13b')
MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 'd174ab98d277d9f5a5611c2c9f419d9f')
MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", '57edf4a22be3c955ac49da2e2107b67a')

return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method MD5(messageText, verifyCheck) public static

  algorithm   = 'MD5'
  digestSum = getDigest(messageText, algorithm)

  say '<Message>'messageText'</Message>'
  say Rexx('<'algorithm'>').right(12) || digestSum'</'algorithm'>'
  say Rexx('<Verify>').right(12) || verifyCheck'</Verify>'
  if digestSum == verifyCheck then say algorithm 'Confirmed'
                              else say algorithm 'Failed'

  return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getDigest(messageText = Rexx, algorithm = Rexx 'MD5', encoding = Rexx 'UTF-8', lowercase = boolean 1) public static returns Rexx

  algorithm = algorithm.upper
  encoding  = encoding.upper

  message      = String(messageText)
  messageBytes = byte[]
  digestBytes  = byte[]
  digestSum    = Rexx ''

  do
    messageBytes = message.getBytes(encoding)
    md = MessageDigest.getInstance(algorithm)
    md.update(messageBytes)
    digestBytes = md.digest

    loop b_ = 0 to digestBytes.length - 1
      bb = Rexx(digestBytes[b_]).d2x(2)
      if lowercase then digestSum = digestSum || bb.lower
                   else digestSum = digestSum || bb.upper
      end b_
  catch ex = Exception
    ex.printStackTrace
  end

  return digestSum


;; using the crypto module from http://www.newlisp.org/code/modules/crypto.lsp.html
;; (import native functions from the crypto library, provided by OpenSSL)
(module "crypto.lsp")
(crypto:md5 "The quick brown fox jumped over the lazy dog's back")


import md5

echo toMD5("The quick brown fox jumped over the lazy dog's back")


MODULE MD5;
IMPORT
  Crypto:MD5,
  Crypto:Utils,
  Strings,
  Out;
VAR
  h: MD5.Hash;
  str: ARRAY 128 OF CHAR;
BEGIN
  h := MD5.NewHash();
  h.Initialize;
  str := "The quick brown fox jumped over the lazy dog's back";
  h.Update(str,0,Strings.Length(str));
  h.GetHash(str,0);
  Out.String("MD5: ");Utils.PrintHex(str,0,h.size);Out.Ln
END MD5.


class MD5 {
   function : Main(args : String[]) ~ Nil {
      in := "The quick brown fox jumped over the lazy dog's back"->ToByteArray();
      hash := Encryption.Hash->MD5(in);
      hash->ToHexString()->PrintLine();
   }
}


NSString *myString = @"The quick brown fox jumped over the lazy dog's back";
NSData *digest = [[myString dataUsingEncoding:NSUTF8StringEncoding] md5Digest]; // or another encoding of your choosing
NSLog(@"%@", [digest hexadecimalRepresentation]);


# Digest.to_hex(Digest.string "The quick brown fox jumped over the lazy dog's back") ;;
- : string = "e38ca1d920c4b8b8d3946b2c72f01680"


s = "The quick brown fox jumped over the lazy dog's back";
hash = md5sum(s, true);
disp(hash)


(import (otus ffi))
(define libcrypto (load-dynamic-library "libcrypto.so.1.0.0"))
(define MD5 (libcrypto type-vptr "MD5" type-string fft-unsigned-long type-string))


MESSAGE
   1 STRING( HEX-ENCODE( MD5-DIGEST( "" ) ) ) SKIP
   2 STRING( HEX-ENCODE( MD5-DIGEST( "a" ) ) ) SKIP
   3 STRING( HEX-ENCODE( MD5-DIGEST( "abc" ) ) ) SKIP
   4 STRING( HEX-ENCODE( MD5-DIGEST( "message digest" ) ) ) SKIP
   5 STRING( HEX-ENCODE( MD5-DIGEST( "abcdefghijklmnopqrstuvwxyz" ) ) ) SKIP
   6 STRING( HEX-ENCODE( MD5-DIGEST( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ) ) ) SKIP
   7 STRING( HEX-ENCODE( MD5-DIGEST( "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ) ) )
VIEW-AS ALERT-BOX


#include <pari/pari.h>
#include <openssl/md5.h>

#define HEX(x)  (((x) < 10)? (x)+'0': (x)-10+'a')

/*
 * PARI/GP func: MD5 hash
 *
 * gp code: install("plug_md5", "s", "MD5", "<library path>");
 */
GEN plug_md5(char *text)
{
  char md[MD5_DIGEST_LENGTH];
  char hash[sizeof(md) * 2 + 1];
  int i;

  MD5((unsigned char*)text, strlen(text), (unsigned char*)md);

  for (i = 0; i < sizeof(md); i++) {
    hash[i+i]   = HEX((md[i] >> 4) & 0x0f);
    hash[i+i+1] = HEX(md[i] & 0x0f);
  }

  hash[sizeof(md) * 2] = 0;

  return strtoGENstr(hash);
}


program GetMd5;

uses md5;

var
  strEncrypted : string;

begin
  strEncrypted := md5Print(md5String('The quick brown fox jumped over the lazy dog''s back'));
  writeln(strEncrypted);
end.


use Digest::MD5 qw(md5_hex);

print md5_hex("The quick brown fox jumped over the lazy dog's back"), "\n";


$string = "The quick brown fox jumped over the lazy dog's back";
echo md5( $string );


(let Str "The quick brown fox jumped over the lazy dog's back"
   (pack
      (mapcar '((B) (pad 2 (hex B)))
         (native "libcrypto.so" "MD5" '(B . 16) Str (length Str) '(NIL (16))) ) ) )


import String;
import Crypto.MD5;

int main(){
   write( string2hex( hash( "The quick brown fox jumped over the lazy dog's back" ) ) + "\n" );
}


$string = "The quick brown fox jumped over the lazy dog's back"
$data = [Text.Encoding]::UTF8.GetBytes($string)
$hash = [Security.Cryptography.MD5]::Create().ComputeHash($data)
([BitConverter]::ToString($hash) -replace '-').ToLower()


UseMD5Fingerprint() ; register the MD5 fingerprint plugin

test$ = "The quick brown fox jumped over the lazy dog's back"

; Call StringFingerprint() function and display MD5 result in Debug window
Debug StringFingerprint(test$, #PB_Cipher_MD5)


library(digest)
hexdigest <- digest("The quick brown fox jumped over the lazy dog's back",
                    algo="md5", serialize=FALSE)


#lang racket
(require file/md5)

(md5 "")
(md5 "a")
(md5 "abc")
(md5 "message digest")
(md5 "abcdefghijklmnopqrstuvwxyz")
(md5 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
(md5 "12345678901234567890123456789012345678901234567890123456789012345678901234567890")


use Digest::MD5;
say Digest::MD5.md5_hex: "The quick brown fox jumped over the lazy dog's back";


>> checksum/method "The quick brown fox jumped over the lazy dog" 'md5
== #{08A008A01D498C404B0C30852B39D3B8}


/*REXX program tests the MD5 procedure (below) as per a test suite the  IETF RFC (1321).*/
msg.1 =                                          /*─────MD5 test suite [from above doc].*/
msg.2 = 'a'
msg.3 = 'abc'
msg.4 = 'message digest'
msg.5 = 'abcdefghijklmnopqrstuvwxyz'
msg.6 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
msg.7 =  12345678901234567890123456789012345678901234567890123456789012345678901234567890
msg.0 = 7                                        /* [↑]  last value doesn't need quotes.*/
                do m=1  for  msg.0;       say    /*process each of the seven messages.  */
                say ' in ='  msg.m               /*display the      in      message.    */
                say 'out ='  MD5(msg.m)          /*   "     "       out        "        */
                end   /*m*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
MD5: procedure; parse arg !;  numeric digits 20  /*insure there's enough decimal digits.*/
     a='67452301'x;  b="efcdab89"x;  c='98badcfe'x;  d="10325476"x;   x00='0'x;  x80="80"x
     #=length(!)                                 /*length in bytes of the input message.*/
     L=#*8//512;   if L<448  then plus=448 - L   /*is the length  less   than  448 ?    */
                   if L>448  then plus=960 - L   /* "  "     "   greater   "    "       */
                   if L=448  then plus=512       /* "  "     "    equal    to   "       */
                                                 /* [↓]  a little of this, ···          */
     $=! || x80 || copies(x00, plus%8 -1)reverse(right(d2c(8 * #), 4, x00)) || '00000000'x
                                                 /* [↑]       ···  and a little of that.*/
       do j=0  to length($) % 64 - 1             /*process the message  (lots of steps).*/
       a_=a;       b_=b;       c_=c;       d_=d  /*save the  original values  for later.*/
       chunk=j*64                                /*calculate the  size  of the chunks.  */
                       do k=1  for 16            /*process the message in chunks.       */
                       !.k=reverse( substr($, chunk + 1 + 4*(k-1), 4) )   /*magic stuff.*/
                       end   /*k*/                                        /*────step────*/
       a  =  .part1( a,   b,   c,   d,    0,    7,   3614090360)          /*■■■■  1 ■■■■*/
       d  =  .part1( d,   a,   b,   c,    1,   12,   3905402710)          /*■■■■  2 ■■■■*/
       c  =  .part1( c,   d,   a,   b,    2,   17,    606105819)          /*■■■■  3 ■■■■*/
       b  =  .part1( b,   c,   d,   a,    3,   22,   3250441966)          /*■■■■  4 ■■■■*/
       a  =  .part1( a,   b,   c,   d,    4,    7,   4118548399)          /*■■■■  5 ■■■■*/
       d  =  .part1( d,   a,   b,   c,    5,   12,   1200080426)          /*■■■■  6 ■■■■*/
       c  =  .part1( c,   d,   a,   b,    6,   17,   2821735955)          /*■■■■  7 ■■■■*/
       b  =  .part1( b,   c,   d,   a,    7,   22,   4249261313)          /*■■■■  8 ■■■■*/
       a  =  .part1( a,   b,   c,   d,    8,    7,   1770035416)          /*■■■■  9 ■■■■*/
       d  =  .part1( d,   a,   b,   c,    9,   12,   2336552879)          /*■■■■ 10 ■■■■*/
       c  =  .part1( c,   d,   a,   b,   10,   17,   4294925233)          /*■■■■ 11 ■■■■*/
       b  =  .part1( b,   c,   d,   a,   11,   22,   2304563134)          /*■■■■ 12 ■■■■*/
       a  =  .part1( a,   b,   c,   d,   12,    7,   1804603682)          /*■■■■ 13 ■■■■*/
       d  =  .part1( d,   a,   b,   c,   13,   12,   4254626195)          /*■■■■ 14 ■■■■*/
       c  =  .part1( c,   d,   a,   b,   14,   17,   2792965006)          /*■■■■ 15 ■■■■*/
       b  =  .part1( b,   c,   d,   a,   15,   22,   1236535329)          /*■■■■ 16 ■■■■*/
       a  =  .part2( a,   b,   c,   d,    1,    5,   4129170786)          /*■■■■ 17 ■■■■*/
       d  =  .part2( d,   a,   b,   c,    6,    9,   3225465664)          /*■■■■ 18 ■■■■*/
       c  =  .part2( c,   d,   a,   b,   11,   14,    643717713)          /*■■■■ 19 ■■■■*/
       b  =  .part2( b,   c,   d,   a,    0,   20,   3921069994)          /*■■■■ 20 ■■■■*/
       a  =  .part2( a,   b,   c,   d,    5,    5,   3593408605)          /*■■■■ 21 ■■■■*/
       d  =  .part2( d,   a,   b,   c,   10,    9,     38016083)          /*■■■■ 22 ■■■■*/
       c  =  .part2( c,   d,   a,   b,   15,   14,   3634488961)          /*■■■■ 23 ■■■■*/
       b  =  .part2( b,   c,   d,   a,    4,   20,   3889429448)          /*■■■■ 24 ■■■■*/
       a  =  .part2( a,   b,   c,   d,    9,    5,    568446438)          /*■■■■ 25 ■■■■*/
       d  =  .part2( d,   a,   b,   c,   14,    9,   3275163606)          /*■■■■ 26 ■■■■*/
       c  =  .part2( c,   d,   a,   b,    3,   14,   4107603335)          /*■■■■ 27 ■■■■*/
       b  =  .part2( b,   c,   d,   a,    8,   20,   1163531501)          /*■■■■ 28 ■■■■*/
       a  =  .part2( a,   b,   c,   d,   13,    5,   2850285829)          /*■■■■ 29 ■■■■*/
       d  =  .part2( d,   a,   b,   c,    2,    9,   4243563512)          /*■■■■ 30 ■■■■*/
       c  =  .part2( c,   d,   a,   b,    7,   14,   1735328473)          /*■■■■ 31 ■■■■*/
       b  =  .part2( b,   c,   d,   a,   12,   20,   2368359562)          /*■■■■ 32 ■■■■*/
       a  =  .part3( a,   b,   c,   d,    5,    4,   4294588738)          /*■■■■ 33 ■■■■*/
       d  =  .part3( d,   a,   b,   c,    8,   11,   2272392833)          /*■■■■ 34 ■■■■*/
       c  =  .part3( c,   d,   a,   b,   11,   16,   1839030562)          /*■■■■ 35 ■■■■*/
       b  =  .part3( b,   c,   d,   a,   14,   23,   4259657740)          /*■■■■ 36 ■■■■*/
       a  =  .part3( a,   b,   c,   d,    1,    4,   2763975236)          /*■■■■ 37 ■■■■*/
       d  =  .part3( d,   a,   b,   c,    4,   11,   1272893353)          /*■■■■ 38 ■■■■*/
       c  =  .part3( c,   d,   a,   b,    7,   16,   4139469664)          /*■■■■ 39 ■■■■*/
       b  =  .part3( b,   c,   d,   a,   10,   23,   3200236656)          /*■■■■ 40 ■■■■*/
       a  =  .part3( a,   b,   c,   d,   13,    4,    681279174)          /*■■■■ 41 ■■■■*/
       d  =  .part3( d,   a,   b,   c,    0,   11,   3936430074)          /*■■■■ 42 ■■■■*/
       c  =  .part3( c,   d,   a,   b,    3,   16,   3572445317)          /*■■■■ 43 ■■■■*/
       b  =  .part3( b,   c,   d,   a,    6,   23,     76029189)          /*■■■■ 44 ■■■■*/
       a  =  .part3( a,   b,   c,   d,    9,    4,   3654602809)          /*■■■■ 45 ■■■■*/
       d  =  .part3( d,   a,   b,   c,   12,   11,   3873151461)          /*■■■■ 46 ■■■■*/
       c  =  .part3( c,   d,   a,   b,   15,   16,    530742520)          /*■■■■ 47 ■■■■*/
       b  =  .part3( b,   c,   d,   a,    2,   23,   3299628645)          /*■■■■ 48 ■■■■*/
       a  =  .part4( a,   b,   c,   d,    0,    6,   4096336452)          /*■■■■ 49 ■■■■*/
       d  =  .part4( d,   a,   b,   c,    7,   10,   1126891415)          /*■■■■ 50 ■■■■*/
       c  =  .part4( c,   d,   a,   b,   14,   15,   2878612391)          /*■■■■ 51 ■■■■*/
       b  =  .part4( b,   c,   d,   a,    5,   21,   4237533241)          /*■■■■ 52 ■■■■*/
       a  =  .part4( a,   b,   c,   d,   12,    6,   1700485571)          /*■■■■ 53 ■■■■*/
       d  =  .part4( d,   a,   b,   c,    3,   10,   2399980690)          /*■■■■ 54 ■■■■*/
       c  =  .part4( c,   d,   a,   b,   10,   15,   4293915773)          /*■■■■ 55 ■■■■*/
       b  =  .part4( b,   c,   d,   a,    1,   21,   2240044497)          /*■■■■ 56 ■■■■*/
       a  =  .part4( a,   b,   c,   d,    8,    6,   1873313359)          /*■■■■ 57 ■■■■*/
       d  =  .part4( d,   a,   b,   c,   15,   10,   4264355552)          /*■■■■ 58 ■■■■*/
       c  =  .part4( c,   d,   a,   b,    6,   15,   2734768916)          /*■■■■ 59 ■■■■*/
       b  =  .part4( b,   c,   d,   a,   13,   21,   1309151649)          /*■■■■ 60 ■■■■*/
       a  =  .part4( a,   b,   c,   d,    4,    6,   4149444226)          /*■■■■ 61 ■■■■*/
       d  =  .part4( d,   a,   b,   c,   11,   10,   3174756917)          /*■■■■ 62 ■■■■*/
       c  =  .part4( c,   d,   a,   b,    2,   15,    718787259)          /*■■■■ 63 ■■■■*/
       b  =  .part4( b,   c,   d,   a,    9,   21,   3951481745)          /*■■■■ 64 ■■■■*/
       a  =  .a(a_, a);     b=.a(b_, b);      c=.a(c_, c);    d=.a(d_, d)
       end   /*j*/

     return c2x( reverse(a) )c2x( reverse(b) )c2x( reverse(c) )c2x( reverse(d) )
/*──────────────────────────────────────────────────────────────────────────────────────*/
.a:     return  right( d2c( c2d( arg(1) )   +   c2d( arg(2) ) ),  4, '0'x)
.h:     return  bitxor( bitxor( arg(1), arg(2) ), arg(3) )
.i:     return  bitxor( arg(2), bitor(arg(1), bitxor(arg(3),        'ffffffff'x)))
.f:     return  bitor( bitand(arg(1),arg(2)), bitand(bitxor(arg(1), 'ffffffff'x), arg(3)))
.g:     return  bitor( bitand(arg(1),arg(3)), bitand(arg(2), bitxor(arg(3), 'ffffffff'x)))
.Lr:    procedure;  parse arg _,#;           if #==0  then return _       /*left rotate.*/
                  ?=x2b(c2x(_));     return x2c( b2x( right(? || left(?, #), length(?) )))
.part1: procedure expose !.;   parse arg w,x,y,z,n,m,_;        n=n+1
                  return .a(.Lr(right(d2c(_+c2d(w) +c2d(.f(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part2: procedure expose !.;   parse arg w,x,y,z,n,m,_;        n=n+1
                  return .a(.Lr(right(d2c(_+c2d(w) +c2d(.g(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part3: procedure expose !.;   parse arg w,x,y,z,n,m,_;        n=n+1
                  return .a(.Lr(right(d2c(_+c2d(w) +c2d(.h(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part4: procedure expose !.;   parse arg w,x,y,z,n,m,_;        n=n+1
                  return .a(.Lr(right(d2c(c2d(w) +c2d(.i(x,y,z))+c2d(!.n)+_),4,'0'x),m),x)


See MD5("my string!") + nl
# output : a83a049fbe50cf7334caa86bf16a3520


>> x = "The quick brown fox jumped over the lazy dog's back"
The quick brown fox jumped over the lazy dog's back

>> hash("md5", x)
e38ca1d920c4b8b8d3946b2c72f01680


**FREE
Ctl-opt MAIN(Main);
Ctl-opt DFTACTGRP(*NO) ACTGRP(*NEW);

dcl-pr QDCXLATE EXTPGM('QDCXLATE');
  dataLen         packed(5 : 0) CONST;
  data            char(32767) options(*VARSIZE);
  conversionTable char(10) CONST;
end-pr;

dcl-pr Qc3CalculateHash EXTPROC('Qc3CalculateHash');
  inputData             pointer value;
  inputDataLen          int(10) const;
  inputDataFormat       char(8) const;
  algorithmDscr         char(16) const;
  algorithmFormat       char(8) const;
  cryptoServiceProvider char(1) const;
  cryptoDeviceName      char(1) const options(*OMIT);
  hash                  char(64) options(*VARSIZE : *OMIT);
  errorCode             char(32767) options(*VARSIZE);
end-pr;

dcl-c HEX_CHARS CONST('0123456789ABCDEF');

dcl-proc Main;
  dcl-s inputData char(45);
  dcl-s inputDataLen int(10) INZ(0);
  dcl-s outputHash char(16);
  dcl-s outputHashHex char(32);
  dcl-ds algorithmDscr QUALIFIED;
    hashAlgorithm int(10) INZ(0);
  end-ds;
  dcl-ds ERRC0100_NULL QUALIFIED;
    bytesProvided int(10) INZ(0);  // Leave at zero
    bytesAvailable int(10);
  end-ds;

  dow inputDataLen = 0;
    DSPLY 'Input: ' '' inputData;
    inputData = %trim(inputData);
    inputDataLen = %len(%trim(inputData));
    DSPLY ('Input=' + inputData);
    DSPLY ('InputLen=' + %char(inputDataLen));
    if inputDataLen = 0;
      DSPLY 'Input must not be blank';
    endif;
  enddo;

  // Convert from EBCDIC to ASCII
  QDCXLATE(inputDataLen : inputData : 'QTCPASC');
  algorithmDscr.hashAlgorithm = 1;   // MD5
  // Calculate hash
  Qc3CalculateHash(%addr(inputData) : inputDataLen : 'DATA0100' : algorithmDscr
                   : 'ALGD0500' : '0' : *OMIT : outputHash : ERRC0100_NULL);
  // Convert to hex
  CVTHC(outputHashHex : outputHash : 32);
  DSPLY ('MD5: ' + outputHashHex);
  return;
end-proc;

// This procedure is actually a MI, but I couldn't get it to bind so I wrote my own version
dcl-proc CVTHC;
  dcl-pi *N;
    target char(65534) options(*VARSIZE);
    srcBits char(32767) options(*VARSIZE) CONST;
    targetLen int(10) value;
  end-pi;
  dcl-s i int(10);
  dcl-s lowNibble ind INZ(*OFF);
  dcl-s inputOffset int(10) INZ(1);
  dcl-ds dataStruct QUALIFIED;
    numField int(5) INZ(0);
    // IBM i is big-endian
    charField char(1) OVERLAY(numField : 2);
  end-ds;

  for i = 1 to targetLen;
    if lowNibble;
      dataStruct.charField = %BitAnd(%subst(srcBits : inputOffset : 1) : X'0F');
      inputOffset += 1;
    else;
      dataStruct.charField = %BitAnd(%subst(srcBits : inputOffset : 1) : X'F0');
      dataStruct.numField /= 16;
    endif;
    %subst(target : i : 1) = %subst(HEX_CHARS : dataStruct.numField + 1 : 1);
    lowNibble = NOT lowNibble;
  endfor;
  return;
end-proc;


require 'digest'
Digest::MD5.hexdigest("The quick brown fox jumped over the lazy dog's back")
# => "e38ca1d920c4b8b8d3946b2c72f01680"


require("chksum");
print(md5sum("The quick brown fox jumped over the lazy dog's back"));


object RosettaMD5 extends App {

  def MD5(s: String): String = {
    // Besides "MD5", "SHA-256", and other hashes are available
    val m = java.security.MessageDigest.getInstance("MD5").digest(s.getBytes("UTF-8"))
    m.map("%02x".format(_)).mkString
  }

  assert("d41d8cd98f00b204e9800998ecf8427e" == MD5(""))
  assert("0cc175b9c0f1b6a831c399e269772661" == MD5("a"))
  assert("900150983cd24fb0d6963f7d28e17f72" == MD5("abc"))
  assert("f96b697d7cb7938d525a2f31aaf161d0" == MD5("message digest"))
  assert("c3fcd3d76192e4007dfb496cca67e13b" == MD5("abcdefghijklmnopqrstuvwxyz"))
  assert("e38ca1d920c4b8b8d3946b2c72f01680" == MD5("The quick brown fox jumped over the lazy dog's back"))
  assert("d174ab98d277d9f5a5611c2c9f419d9f" ==
    MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))
  assert("57edf4a22be3c955ac49da2e2107b67a" ==
    MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890"))
  import scala.compat.Platform.currentTime
  println(s"Successfully completed without errors. [total ${currentTime - executionStart} ms]")
}


$ include "seed7_05.s7i";
  include "msgdigest.s7i";

const proc: main is func
  begin
    writeln(hex(md5("The quick brown fox jumped over the lazy dog's back")));
  end func;


F dijkstra(graph, source)
   V n = graph.len
   V dist = [Float.infinity] * n
   V previous = [-1] * n
   dist[source] = 0
   V Q = Array(0 .< n)
   L !Q.empty
      V u = min(Q, key' n -> @dist[n])
      Q.remove(u)
      I dist[u] == Float.infinity
         L.break
      L(v) 0 .< n
         I graph[u][v] & (v C Q)
            V alt = dist[u] + graph[u][v]
            I alt < dist[v]
               dist[v] = alt
               previous[v] = u
   R previous

F display_solution(predecessor)
   V cell = predecessor.len - 1
   L cell != 0
      print(cell, end' ‘<’)
      cell = predecessor[cell]
   print(0)

V graph = [
    [0,1,0,0,0,0],
    [1,0,1,0,1,0],
    [0,1,0,0,0,1],
    [0,0,0,0,1,0],
    [0,1,0,1,0,0],
    [0,0,1,0,0,0]
]

display_solution(dijkstra(graph, 0))


var digest = frequire('Digest::MD5');
say digest.md5_hex("The quick brown fox jumped over the lazy dog's back");


'The quick brown fox jumped over the lazy dog\'s back' md5String. "==> 'e38ca1d920c4b8b8d3946b2c72f01680'"


PackageLoader fileInPackage: 'Digest' !
(MD5 hexDigestOf: 'The quick brown fox jumped over the lazy dog''s back') displayNl.


DEFINE TOP="0"
DEFINE RIGHT="1"
DEFINE BOTTOM="2"
DEFINE LEFT="3"
DEFINE WIDTH="160"
DEFINE HEIGHT="96"

DEFINE STACK_SIZE="5000"
BYTE ARRAY stack(STACK_SIZE)
INT stackSize

PROC InitStack()
  stackSize=0
RETURN

BYTE FUNC IsEmpty()
  IF stackSize=0 THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC IsFull()
  IF stackSize>=STACK_SIZE THEN
    RETURN (1)
  FI
RETURN (0)

PROC Push(BYTE x,y)
  IF IsFull() THEN Break() RETURN FI
  stack(stackSize)=x stackSize==+1
  stack(stackSize)=y stackSize==+1
RETURN

PROC Pop(BYTE POINTER x,y)
  IF IsEmpty() THEN Break() RETURN FI
  stackSize==-1 y^=stack(stackSize)
  stackSize==-1 x^=stack(stackSize)
RETURN

PROC Push3(BYTE x,y,d)
  IF IsFull() THEN Break() RETURN FI
  stack(stackSize)=x stackSize==+1
  stack(stackSize)=y stackSize==+1
  stack(stackSize)=d stackSize==+1
RETURN

PROC Pop3(BYTE POINTER x,y,d)
  IF IsEmpty() THEN Break() RETURN FI
  stackSize==-1 d^=stack(stackSize)
  stackSize==-1 y^=stack(stackSize)
  stackSize==-1 x^=stack(stackSize)
RETURN

PROC FillScreen()
  BYTE POINTER ptr ;pointer to the screen memory
  INT screenSize=[3840]

  ptr=PeekC(88)
  SetBlock(ptr,screenSize,$55)

  Color=0
  Plot(0,HEIGHT-1) DrawTo(WIDTH-1,HEIGHT-1) DrawTo(WIDTH-1,0)
RETURN

PROC GetNeighbors(BYTE x,y BYTE ARRAY n BYTE POINTER count)
  DEFINE WALL="1"

  count^=0
  IF y>2 AND Locate(x,y-2)=WALL THEN
    n(count^)=TOP count^==+1
  FI
  IF x<WIDTH-3 AND Locate(x+2,y)=WALL THEN
    n(count^)=RIGHT count^==+1
  FI
  IF y<HEIGHT-3 AND Locate(x,y+2)=WALL THEN
    n(count^)=BOTTOM count^==+1
  FI
  IF x>2 AND Locate(x-2,y)=WALL THEN
    n(count^)=LEFT count^==+1
  FI
RETURN

PROC DrawConnection(BYTE POINTER x,y BYTE dir)
  Plot(x^,y^)
  IF dir=TOP THEN
    y^==-2
  ELSEIF dir=RIGHT THEN
    x^==+2
  ELSEIF dir=BOTTOM THEN
    y^==+2
  ELSE
    x^==-2
  FI
  DrawTo(x^,y^)
RETURN

PROC Maze(BYTE x,y)
  BYTE ARRAY stack,neighbors
  BYTE dir,nCount

  FillScreen()

  Color=2
  InitStack()
  Push(x,y)
  WHILE IsEmpty()=0
  DO
    Pop(@x,@y)
    GetNeighbors(x,y,neighbors,@nCount)
    IF nCount>0 THEN
      Push(x,y)
      dir=neighbors(Rand(nCount))
      DrawConnection(@x,@y,dir)
      Push(x,y)
    FI
  OD
RETURN

BYTE FUNC IsConnection(BYTE x,y,dir)
  DEFINE WAY="2"
  IF dir=TOP AND y>2 AND Locate(x,y-1)=WAY THEN
    RETURN (1)
  ELSEIF dir=RIGHT AND x<WIDTH-3 AND Locate(x+1,y)=WAY THEN
    RETURN (1)
  ELSEIF dir=BOTTOM AND y<HEIGHT-3 AND Locate(x,y+1)=WAY THEN
    RETURN (1)
  ELSEIF dir=LEFT AND x>2 AND Locate(x-1,y)=WAY THEN
    RETURN (1)
  FI
RETURN (0)

PROC Solve(BYTE x1,y1,x2,y2)
  BYTE dir,x,y,lastX,lastY,back

  Color=3
  Plot(x1,y1)
  Plot(x2,y2)

  InitStack()
  Push3(x1,y1,TOP)
  WHILE IsEmpty()=0
  DO
    Pop3(@x,@y,@dir)
    IF back THEN
      Color=2
      Plot(lastX,lastY)
      DrawTo(x,y)
    FI
    IF IsConnection(x,y,dir) THEN
      Color=3
      Push3(x,y,dir+1)
      DrawConnection(@x,@y,dir)
      IF x=x2 AND y=y2 THEN
        RETURN
      FI
      Push3(x,y,TOP)
      back=0
    ELSEIF dir<=LEFT THEN
      Push3(x,y,dir+1)
      back=0
    ELSE
      lastX=x
      lastY=y
      back=1
    FI
  OD
RETURN

PROC Main()
  BYTE CH=$02FC,COLOR0=$02C4,COLOR1=$02C5,COLOR2=$02C6
  BYTE x,y,x2,y2

  Graphics(7+16)
  COLOR0=$0A
  COLOR1=$04
  COLOR2=$A6

  x=Rand((WIDTH RSH 1)-1) LSH 1+1
  y=Rand((HEIGHT RSH 1)-1) LSH 1+1
  Maze(x,y)

  x=Rand((WIDTH RSH 1)-1) LSH 1+1
  y=Rand((HEIGHT RSH 1)-1) LSH 1+1
  x2=Rand((WIDTH RSH 1)-1) LSH 1+1
  y2=Rand((HEIGHT RSH 1)-1) LSH 1+1
  Solve(x,y,x2,y2)

  DO UNTIL CH#$FF OD
  CH=$FF
RETURN


with Ada.Text_IO;

procedure Maze_Solver is

   X_Size: constant Natural := 45;
   Y_Size: constant Natural := 17;

   subtype X_Range is Natural range 1 .. X_Size;
   subtype Y_Range is Natural range 1 .. Y_Size;

   East:  constant X_Range := 2;
   South: constant Y_Range := 1;

   X_Start: constant X_Range  := 3; -- start at the upper left
   Y_Start: constant Y_Range  := 1;
   X_Finish: constant X_Range := X_Size-East; -- go to the lower right
   Y_Finish: constant Y_Range := Y_Size;

   type Maze_Type is array (Y_Range) of String(X_Range);

   function Solved(X: X_Range; Y: Y_Range) return Boolean is
   begin
      return (X = X_Finish) and (Y = Y_Finish);
   end Solved;

   procedure Output_Maze(M: Maze_Type; Message: String := "") is
   begin
      if Message /= "" then
         Ada.Text_IO.Put_Line(Message);
      end if;
      for I in M'Range loop
         Ada.Text_IO.Put_Line(M(I));
      end loop;
   end Output_Maze;

   procedure Search(M: in out Maze_Type; X: X_Range; Y:Y_Range) is
   begin
      M(Y)(X) := '*';
      if Solved(X, Y) then
         Output_Maze(M, "Solution found!");
      else
         if Integer(Y)-South >= 1 and then M(Y-South)(X) = ' ' then
            Search(M, X, Y-South);
         end if;
         if Integer(Y)+South <= Y_Size and then M(Y+South)(X) = ' ' then
            Search(M, X, Y+South);
         end if;
         if Integer(X)-East >= 1 and then M(Y)(X-East) = ' ' then
            Search(M, X-East, Y);
         end if;
         if Integer(Y)+East <= Y_Size and then M(Y)(X+East) = ' ' then
            Search(M, X+East, Y);
         end if;
      end if;
      M(Y)(X) := ' ';
   end Search;

   Maze: Maze_Type;
   X: X_Range := X_Start;
   Y: Y_Range := Y_Start;

begin
   for I in 1 .. Y_Size loop
      Maze(I) := Ada.Text_IO.Get_Line;
   end loop;
   Maze(Y_Start)(X_Start)   := ' '; -- Start from
   Maze(Y_Finish)(X_Finish) := ' '; -- Go_To
   Output_Maze(Maze, "The Maze:");
   Ada.Text_IO.New_Line;

   Search(Maze, X, Y) ; -- Will output *all* Solutions.
                        -- If there is no output, there is no solution.
end Maze_Solver;


SELECT MD5('The quick brown fox jumped over the lazy dog\'s back')


Md5('The quick brown fox jumped over the lazy dog\'s back')


package require md5
puts [md5::md5 -hex "The quick brown fox jumped over the lazy dog's back"]
# ==> E38CA1D920C4B8B8D3946B2C72F01680


echo -n "The quick brown fox jumped over the lazy dog's back" | md5sum


Width := 10, Height	:= 10												; set grid size
SleepTime := 0

gosub, Startup

Gui, +AlwaysOnTop
Gui, font, s12, consolas
Gui, add, edit, vEditGrid x10, % maze
Gui, add, button, xs gStartup Default, Generate maze
Gui, add, button, x+10 gSolve, Solve
Gui, show,, maze
GuiControl,, EditGrid, % maze											; show maze
return

;-----------------------------------------------------------------------
^Esc::
GuiEscape:
GuiClose:
ExitApp
return

;-----------------------------------------------------------------------
Startup:
oMaze := []																; initialize
Solved := false
loop, % Height
{
	row := A_Index
	loop, % Width														; create oMaze[row,column] borders
		col := A_Index, oMaze[row,col] :=  "LRTB"						; i.e. oMaze[2,5] := LRTB (add all borders)
}
Random, row, 1, % Height												; random row
Random, col, 1, % Width													; random col
grid := maze2text(oMaze)												; object to text
GuiControl,, EditGrid, % Grid											; show Grid
row := col := 1															; reset to 1,1
oMaze := Generate_maze(row, col, oMaze)									; generate maze starting from random row/column
oMaze[1,1] .= "X"														; start from 1,1
maze := maze2text(oMaze)												; object to text
GuiControl,, EditGrid, % maze											; show maze
GuiControl,, EditRoute													; clear route
GuiControl, Enable, Solve
return

;-----------------------------------------------------------------------
Solve:
GuiControl, Disable, Generate maze
GuiControl, Disable, Solve
loop % oRoute.MaxIndex()
	oRoute.pop()

oSolution	:= Solve(1, 1, oMaze)										; solve starting from 1,1
oMaze 		:= oSolution.1
oRoute 		:= oSolution.2
Update(oMaze, oRoute)
Solved := true
GuiControl, Enable, Generate maze
return

;-----------------------------------------------------------------------
Update(oMaze, oRoute){
	global SleepTime
	GuiControl,, EditGrid, % maze2text(oMaze)
	Sleep, % SleepTime
}

;-----------------------------------------------------------------------
maze2text(oMaze){
	width := oMaze.1.MaxIndex()
	BLK := "█"
	for row, objRow in oMaze
	{
		for col, val in objRow											; add ceiling
		{
			ceiling := InStr(oMaze[row, col] , "x") && InStr(oMaze[row-1, col] , "x") ? "+ " BLK " " : "+   "
			grid .= (InStr(val, "T") ? "+---" : ceiling) (col = Width ? "+`n" : "")
		}
		for col, val in objRow											; add left wall
		{
			wall := SubStr(val, 0) = "X" ? BLK : " "
			grid .= (InStr(val, "L") ? "| " : "  ") wall " " (col = Width ? "|`n" : "") ; add left wall if needed then outer right border
		}
	}
	Loop % Width
		Grid .= "+---"													; add bottom floor
	Grid .= "+"															; add right bottom corner
	return RegExReplace(grid , BLK "   (?=" BLK ")" ,  BLK BLK BLK BLK)	; fill gaps
}

;-----------------------------------------------------------------------
Generate_maze(row, col, oMaze) {
	neighbors := row+1 "," col "`n" row-1 "," col  "`n" row "," col+1  "`n" row "," col-1
	Sort, neighbors, random												; randomize neighbors list
	Loop, parse, neighbors, `n											; for each neighbor
	{
		rowX := StrSplit(A_LoopField, ",").1							; this neighbor row
		colX := StrSplit(A_LoopField, ",").2							; this neighbor column
		if !instr(oMaze[rowX,colX], "LRTB") || !oMaze[rowX, colX]		; if visited (has a missing border) or out of bounds
			continue													; skip

		; remove borders
		if (row > rowX)													; Cell is below this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "T") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "B")
		else if (row < rowX)											; Cell is above this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "B") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "T")
		else if (col > colX)											; Cell is right of this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "L") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "R")
		else if (col < colX)											; Cell is left of this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "R") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "L")

		Generate_maze(rowX, colX, oMaze)								; recurse for this neighbor
	}
	return, oMaze
}

;-----------------------------------------------------------------------
Solve(row, col, oMaze){
	static oRoute := []
	oNeighbor := [], targetrow := oMaze.MaxIndex(), targetCol := oMaze.1.MaxIndex()

	;~ Update(oMaze, oRoute)
	oRoute.push(row ":" col)											; push current cell address to oRoute
	oMaze[row, col] .= "X"												; mark it visited "X"

	if (row = targetrow) && (Col = targetCol)							; if solved
		return true														; return ture

	; create list of Neighbors
	oNeighbor[row, col] := []
	if !InStr(oMaze[row, col], "R")										; if no Right border
		oNeighbor[row, col].push(row "," col+1)							; add neighbor
	if !InStr(oMaze[row, col], "B")										; if no Bottom border
		oNeighbor[row, col].push(row+1 "," col)							; add neighbor
	if !InStr(oMaze[row, col], "T")										; if no Top border
		oNeighbor[row, col].push(row-1 "," col)							; add neighbor
	if !InStr(oMaze[row, col], "L")										; if no Left border
		oNeighbor[row, col].push(row "," col-1)							; add neighbor

	; recurese for each oNeighbor
	for each, neighbor in oNeighbor[row, col]							; for each neighbor
	{
		Update(oMaze, oRoute)
		startrow := StrSplit(neighbor, ",").1							; this neighbor
		startCol := StrSplit(neighbor, ",").2							; becomes starting point

		if !InStr(oMaze[startrow, startCol], "X")						; if it was not visited
			if Solve(startrow, startCol, oMaze)							; recurse for current neighbor
				return [oMaze, oRoute]									; return solution if solved
	}
	oRoute.pop()														; no solution found, back track
	oMaze[row, Col] := StrReplace(oMaze[row, Col], "X")					; no solution found, back track
	;~ Update(oMaze, oRoute)
}

;-----------------------------------------------------------------------
#IfWinActive, maze
Right::
Left::
Up::
Down::
if Solved
	return

if (A_ThisHotkey="Right") && (!InStr(oMaze[row,col], "R"))
	oMaze[row, col] := StrReplace(oMaze[row, col], "X")		, col++
if (A_ThisHotkey="Left") && (!InStr(oMaze[row,col], "L"))
	oMaze[row, col] := StrReplace(oMaze[row, col], "X")		, col--
if (A_ThisHotkey="Up") && (!InStr(oMaze[row,col], "T"))
	oMaze[row, col] := StrReplace(oMaze[row, col], "X")		, row--
if (A_ThisHotkey="Down") && (!InStr(oMaze[row,col], "B"))
	oMaze[row, col] := StrReplace(oMaze[row, col], "X")		, row++

oMaze[row, col] .= "X"
GuiControl,, EditGrid, % maze2text(oMaze)

if (col = Width) && (row = Height)
{
	Solved := true
	oMaze[height, width] := StrReplace(oMaze[height, width], "X")
	SleepTime := 0
	gosub, solve
	return
}
return
#IfWinActive


Imports System.Security.Cryptography
Imports System.Text

Module MD5hash
    Sub Main(args As String())
        Console.WriteLine(GetMD5("Visual Basic .Net"))
    End Sub

    Private Function GetMD5(plainText As String) As String
        Dim hash As String = ""

        Using hashObject As MD5 = MD5.Create()
            Dim ptBytes As Byte() = hashObject.ComputeHash(Encoding.UTF8.GetBytes(plainText))
            Dim hashBuilder As New StringBuilder

            For i As Integer = 0 To ptBytes.Length - 1
                hashBuilder.Append(ptBytes(i).ToString("X2"))
            Next
            hash = hashBuilder.ToString
        End Using

        Return hash
    End Function

End Module


import crypto.md5

fn main() {
    for p in [
        // RFC 1321 test cases
        ["d41d8cd98f00b204e9800998ecf8427e", ""],
        ["0cc175b9c0f1b6a831c399e269772661", "a"],
        ["900150983cd24fb0d6963f7d28e17f72", "abc"],
        ["f96b697d7cb7938d525a2f31aaf161d0", "message digest"],
        ["c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"],
        ["d174ab98d277d9f5a5611c2c9f419d9f",
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"],
        ["57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890" +
            "123456789012345678901234567890123456789012345678901234567890"],
        // test case popular with other RC solutions
        ["e38ca1d920c4b8b8d3946b2c72f01680",
            "The quick brown fox jumped over the lazy dog's back"],
        ] {
        validate(p[0], p[1])
    }
}

fn validate(check string, s string) {
    sum := md5.hexhash(s)
    if sum != check {
        println("MD5 fail")
        println("  for string, $s")
        println("  expected:  $check")
        println("  got:       $sum")
    } else {
        println('MD5 succeeded $s')
    }
}


      MazeWidth% = 11
      MazeHeight% = 9
      MazeCell% = 50

      VDU 23,22,MazeWidth%*MazeCell%/2+3;MazeHeight%*MazeCell%/2+3;8,16,16,128
      VDU 23,23,3;0;0;0; : REM Line thickness
      OFF
      PROCgeneratemaze(Maze&(), MazeWidth%, MazeHeight%, MazeCell%)
      PROCsolvemaze(Path{()}, Maze&(), 0, MazeHeight%-1, MazeWidth%-1, 0, MazeCell%)
      END

      DEF PROCsolvemaze(RETURN s{()}, m&(), x%, y%, dstx%, dsty%, s%)
      LOCAL h%, i%, n%, p%, q%, w%
      w% = DIM(m&(),1)
      h% = DIM(m&(),2)
      DIM s{(w%*h%) x%,y%}
      GCOL 3,14
      m&(x%,y%) OR= &80
      REPEAT
        FOR i% = 0 TO 3
          CASE i% OF
            WHEN 0: p% = x%-1 : q% = y%
            WHEN 1: p% = x%+1 : q% = y%
            WHEN 2: p% = x% : q% = y%-1
            WHEN 3: p% = x% : q% = y%+1
          ENDCASE
          IF p% >= 0 IF p% < w% IF q% >= 0 IF q% < h% IF m&(p%,q%) < &80 THEN
            IF p% > x% IF m&(p%,q%) AND 1 EXIT FOR
            IF q% > y% IF m&(p%,q%) AND 2 EXIT FOR
            IF x% > p% IF m&(x%,y%) AND 1 EXIT FOR
            IF y% > q% IF m&(x%,y%) AND 2 EXIT FOR
          ENDIF
        NEXT
        IF i% < 4 THEN
          m&(p%,q%) OR= &80
          s{(n%)}.x% = x%
          s{(n%)}.y% = y%
          n% += 1
        ELSE
          IF n% > 0 THEN
            n% -= 1
            p% = s{(n%)}.x%
            q% = s{(n%)}.y%
          ENDIF
        ENDIF
        LINE (x%+0.5)*s%,(y%+0.5)*s%,(p%+0.5)*s%,(q%+0.5)*s%
        x% = p%
        y% = q%
      UNTIL x%=dstx% AND y%=dsty%
      s{(n%)}.x% = x%
      s{(n%)}.y% = y%
      ENDPROC

      DEF PROCgeneratemaze(RETURN m&(), w%, h%, s%)
      LOCAL x%, y%
      DIM m&(w%, h%)
      FOR y% = 0 TO h%
        LINE 0,y%*s%,w%*s%,y%*s%
      NEXT
      FOR x% = 0 TO w%
        LINE x%*s%,0,x%*s%,h%*s%
      NEXT
      GCOL 15
      PROCcell(m&(), RND(w%)-1, y% = RND(h%)-1, w%, h%, s%)
      ENDPROC

      DEF PROCcell(m&(), x%, y%, w%, h%, s%)
      LOCAL i%, p%, q%, r%
      m&(x%,y%) OR= &40 : REM Mark visited
      r% = RND(4)
      FOR i% = r% TO r%+3
        CASE i% MOD 4 OF
          WHEN 0: p% = x%-1 : q% = y%
          WHEN 1: p% = x%+1 : q% = y%
          WHEN 2: p% = x% : q% = y%-1
          WHEN 3: p% = x% : q% = y%+1
        ENDCASE
        IF p% >= 0 IF p% < w% IF q% >= 0 IF q% < h% IF m&(p%,q%) < &40 THEN
          IF p% > x% m&(p%,q%) OR= 1 : LINE p%*s%,y%*s%+4,p%*s%,(y%+1)*s%-4
          IF q% > y% m&(p%,q%) OR= 2 : LINE x%*s%+4,q%*s%,(x%+1)*s%-4,q%*s%
          IF x% > p% m&(x%,y%) OR= 1 : LINE x%*s%,y%*s%+4,x%*s%,(y%+1)*s%-4
          IF y% > q% m&(x%,y%) OR= 2 : LINE x%*s%+4,y%*s%,(x%+1)*s%-4,y%*s%
          PROCcell(m&(), p%, q%, w%, h%, s%)
        ENDIF
      NEXT
      ENDPROC


#include <windows.h>
#include <iostream>
#include <string>

//--------------------------------------------------------------------------------------------------
using namespace std;

//--------------------------------------------------------------------------------------------------
const int BMP_SIZE = 512, CELL_SIZE = 8;

//--------------------------------------------------------------------------------------------------
enum directions { NONE, NOR = 1, EAS = 2, SOU = 4, WES = 8 };

//--------------------------------------------------------------------------------------------------
class myBitmap
{
public:
    myBitmap() : pen( NULL ) {}
    ~myBitmap()
    {
	DeleteObject( pen );
	DeleteDC( hdc );
	DeleteObject( bmp );
    }

    bool create( int w, int h )
    {
	BITMAPINFO	bi;
	ZeroMemory( &bi, sizeof( bi ) );
	bi.bmiHeader.biSize	   = sizeof( bi.bmiHeader );
	bi.bmiHeader.biBitCount	   = sizeof( DWORD ) * 8;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biPlanes	   = 1;
	bi.bmiHeader.biWidth	   =  w;
	bi.bmiHeader.biHeight	   = -h;

	HDC dc = GetDC( GetConsoleWindow() );
	bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
	if( !bmp ) return false;

	hdc = CreateCompatibleDC( dc );
	SelectObject( hdc, bmp );
	ReleaseDC( GetConsoleWindow(), dc );
	width = w; height = h;

	return true;
    }

    void clear()
    {
	ZeroMemory( pBits, width * height * sizeof( DWORD ) );
    }

    void setPenColor( DWORD clr )
    {
	if( pen ) DeleteObject( pen );
	pen = CreatePen( PS_SOLID, 1, clr );
	SelectObject( hdc, pen );
    }

    void saveBitmap( string path )
    {
	BITMAPFILEHEADER fileheader;
	BITMAPINFO	 infoheader;
	BITMAP		 bitmap;
	DWORD		 wb;

	GetObject( bmp, sizeof( bitmap ), &bitmap );

	DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
	ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
	ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
	ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );

	infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
	infoheader.bmiHeader.biCompression = BI_RGB;
	infoheader.bmiHeader.biPlanes = 1;
	infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
	infoheader.bmiHeader.biHeight = bitmap.bmHeight;
	infoheader.bmiHeader.biWidth = bitmap.bmWidth;
	infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );

	fileheader.bfType    = 0x4D42;
	fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
	fileheader.bfSize    = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;

	GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );

	HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
	WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
	WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
	WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
	CloseHandle( file );

	delete [] dwpBits;
    }

    HDC getDC() const     { return hdc; }
    int getWidth() const  { return width; }
    int getHeight() const { return height; }

private:
    HBITMAP bmp;
    HDC	    hdc;
    HPEN    pen;
    void    *pBits;
    int	    width, height;
};
//--------------------------------------------------------------------------------------------------
class mazeGenerator
{
public:
    mazeGenerator()
    {
	_world = 0;
	_bmp.create( BMP_SIZE, BMP_SIZE );
	_bmp.setPenColor( RGB( 0, 255, 0 ) );
    }

    ~mazeGenerator() { killArray(); }

    BYTE* getMaze() const { return _world; }

    void create( int side )
    {
	_s = side;
	generate();
    }

private:
    void generate()
    {
	killArray();
	_world = new BYTE[_s * _s];
	ZeroMemory( _world, _s * _s );
	_ptX = rand() % _s; _ptY = rand() % _s;
	carve();
    }

    void carve()
    {
	while( true )
	{
	    int d = getDirection();
	    if( d < NOR ) return;

	    switch( d )
	    {
		case NOR:
		    _world[_ptX + _s * _ptY] |= NOR; _ptY--;
		    _world[_ptX + _s * _ptY] = SOU | SOU << 4;
		break;
		case EAS:
		    _world[_ptX + _s * _ptY] |= EAS; _ptX++;
		    _world[_ptX + _s * _ptY] = WES | WES << 4;
		break;
		case SOU:
		    _world[_ptX + _s * _ptY] |= SOU; _ptY++;
		    _world[_ptX + _s * _ptY] = NOR | NOR << 4;
		break;
		case WES:
		    _world[_ptX + _s * _ptY] |= WES; _ptX--;
		    _world[_ptX + _s * _ptY] = EAS | EAS << 4;
	    }
	}
    }

    int getDirection()
    {
	int d = 1 << rand() % 4;
	while( true )
	{
	    for( int x = 0; x < 4; x++ )
	    {
		if( testDir( d ) ) return d;
		d <<= 1;
		if( d > 8 ) d = 1;
	    }
	    d = ( _world[_ptX + _s * _ptY] & 0xf0 ) >> 4;
	    if( !d ) return -1;
	    switch( d )
	    {
		case NOR: _ptY--; break;
		case EAS: _ptX++; break;
		case SOU: _ptY++; break;
		case WES: _ptX--; break;
	    }

	    d = 1 << rand() % 4;
        }
    }

    bool testDir( int d )
    {
	switch( d )
	{
	    case NOR: return ( _ptY - 1 > -1 && !_world[_ptX + _s * ( _ptY - 1 )] );
	    case EAS: return ( _ptX + 1 < _s && !_world[_ptX + 1 + _s * _ptY] );
	    case SOU: return ( _ptY + 1 < _s && !_world[_ptX + _s * ( _ptY + 1 )] );
	    case WES: return ( _ptX - 1 > -1 && !_world[_ptX - 1 + _s * _ptY] );
	}
	return false;
    }

    void killArray() { if( _world ) delete [] _world; }

    BYTE*    _world;
    int      _s, _ptX, _ptY;
    myBitmap _bmp;
};
//--------------------------------------------------------------------------------------------------
class mazeSolver
{
public:
    mazeSolver()
    {
	_bmp.create( BMP_SIZE, BMP_SIZE );
	_pts = 0;
    }

    ~mazeSolver() { killPoints(); }

    void solveIt( BYTE* maze, int size, int sX, int sY, int eX, int eY )
    {
	_lastDir = NONE;
	_world = maze; _s = size; _sx = sX; _sy = sY; _ex = eX; _ey = eY;

	for( int y = 0; y < _s; y++ )
	    for( int x = 0; x < _s; x++ )
		_world[x + _s * y] &= 0x0f;

        _world[_sx + _s * _sy] |= NOR << 4;

	killPoints();
	_pts = new BYTE[_s * _s];
	ZeroMemory( _pts, _s * _s );

	findTheWay();

	_sx = sX; _sy = sY;
	display();
    }

private:
    int invert( int d )
    {
	switch( d )
	{
	    case NOR: return SOU;
	    case SOU: return NOR;
	    case WES: return EAS;
	    case EAS: return WES;
	}
	return NONE;
    }

    void updatePosition( int d )
    {
        switch( d )
	{
	    case NOR: _sy--; break;
	    case EAS: _sx++; break;
	    case SOU: _sy++; break;
	    case WES: _sx--;
	}
    }

    void findTheWay()
    {
	while( true )
	{
	    int d = getDirection();
	    if( d < NOR ) return;
	    _lastDir = invert( d );
	    _world[_sx + _s * _sy] |= d;
	    _pts[_sx + _s * _sy] = d;
	    updatePosition( d );
	    if( _sx == _ex && _sy == _ey ) return;
	    _world[_sx + _s * _sy] |= _lastDir << 4;
	}
    }

    int getDirection()
    {
	int d = 1 << rand() % 4;
	while( true )
	{
	    for( int x = 0; x < 4; x++ )
	    {
		if( testDirection( d ) ) return d;
		d <<= 1;
		if( d > 8 ) d = 1;
	    }

	    d = ( _world[_sx + _s * _sy] & 0xf0 ) >> 4;
	    if( !d ) return -1;
	    _pts[_sx + _s * _sy] = 0;
	    updatePosition( d );
	    _lastDir = invert( d );
	    d = 1 << rand() % 4;
	}
    }

    bool testDirection( int d )
    {
	if( d == _lastDir || !( _world[_sx + _s * _sy] & d ) ) return false;
	switch( d )
	{
	    case NOR:
		return _sy - 1 > -1 && !( _world[_sx + _s * ( _sy - 1 )] & 0xf0 );
	    case EAS:
		return _sx + 1 < _s && !( _world[_sx + 1 + _s * _sy] & 0xf0 );
	    case SOU:
		return _sy + 1 < _s && !( _world[_sx + _s * ( _sy + 1 )] & 0xf0 );
	    case WES:
		return _sx - 1 > -1 && !( _world[_sx - 1 + _s * _sy] & 0xf0 );
	}
	return false;
    }

    void display()
    {
	_bmp.setPenColor( RGB( 0, 255, 0 ) );
	_bmp.clear();
	HDC dc = _bmp.getDC();
	for( int y = 0; y < _s; y++ )
	{
	    int yy = y * _s;
	    for( int x = 0; x < _s; x++ )
	    {
		BYTE b = _world[x + yy];
		int nx = x * CELL_SIZE,
		    ny = y * CELL_SIZE;

		if( !( b & NOR ) )
		{
		    MoveToEx( dc, nx, ny, NULL );
		    LineTo( dc, nx + CELL_SIZE + 1, ny );
		}
		if( !( b & EAS ) )
		{
		    MoveToEx( dc, nx + CELL_SIZE, ny, NULL );
		    LineTo( dc, nx + CELL_SIZE, ny + CELL_SIZE + 1 );
		}
		if( !( b & SOU ) )
		{
		    MoveToEx( dc, nx, ny + CELL_SIZE, NULL );
		    LineTo( dc, nx + CELL_SIZE + 1, ny + CELL_SIZE );
		}
		if( !( b & WES ) )
		{
		    MoveToEx( dc, nx, ny, NULL );
		    LineTo( dc, nx, ny + CELL_SIZE + 1 );
		}
	    }
	}

	drawEndPoints( dc );
	_bmp.setPenColor( RGB( 255, 0, 0 ) );

	for( int y = 0; y < _s; y++ )
	{
	    int yy = y * _s;
	    for( int x = 0; x < _s; x++ )
	    {
		BYTE d = _pts[x + yy];
		if( !d ) continue;

		int nx = x * CELL_SIZE + 4,
		    ny = y * CELL_SIZE + 4;

		MoveToEx( dc, nx, ny, NULL );
		switch( d )
		{
		    case NOR: LineTo( dc, nx, ny - CELL_SIZE - 1 ); break;
		    case EAS: LineTo( dc, nx + CELL_SIZE + 1, ny ); break;
		    case SOU: LineTo( dc, nx, ny + CELL_SIZE + 1 ); break;
		    case WES: LineTo( dc, nx - CELL_SIZE - 1, ny ); break;
		}
	    }
	}

	_bmp.saveBitmap( "f:\\rc\\maze_s.bmp" );
	BitBlt( GetDC( GetConsoleWindow() ), 10, 60, BMP_SIZE, BMP_SIZE, _bmp.getDC(), 0, 0, SRCCOPY );
    }

    void drawEndPoints( HDC dc )
    {
	RECT rc;
	int x = 1 + _sx * CELL_SIZE, y = 1 + _sy * CELL_SIZE;
	SetRect( &rc, x, y, x + CELL_SIZE - 1, y + CELL_SIZE - 1 );
	FillRect( dc, &rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );
	x = 1 + _ex * CELL_SIZE, y = 1 + _ey * CELL_SIZE;
	SetRect( &rc, x, y, x + CELL_SIZE - 1, y + CELL_SIZE - 1 );
	FillRect( dc, &rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );
    }

    void killPoints() { if( _pts ) delete [] _pts; }

    BYTE*    _world, *_pts;
    int      _s, _sx, _sy, _ex, _ey, _lastDir;
    myBitmap _bmp;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
    ShowWindow( GetConsoleWindow(), SW_MAXIMIZE );
    srand( GetTickCount() );

    mazeGenerator mg;
    mazeSolver ms;
    int s;
    while( true )
    {
	cout << "Enter the maze size, an odd number bigger than 2 ( 0 to QUIT ): "; cin >> s;
	if( !s ) return 0;
	if( !( s & 1 ) ) s++;
	if( s >= 3 )
	{
	    mg.create( s );
	    int sx, sy, ex, ey;
	    while( true )
	    {
		sx = rand() % s; sy = rand() % s;
		ex = rand() % s; ey = rand() % s;
		if( ex != sx || ey != sy ) break;
	    }
	    ms.solveIt( mg.getMaze(), s, sx, sy, ex, ey );
	    cout << endl;
	}
	system( "pause" );
	system( "cls" );
    }
    return 0;
}
//--------------------------------------------------------------------------------------------------


import "/crypto" for Md5
import "/fmt" for Fmt

var strings = [
    "The quick brown fox jumps over the lazy dog",
    "The quick brown fox jumps over the lazy dog.",
    ""
]

for (s in strings) {
    var digest = Md5.digest(s)
    Fmt.print("$s <== '$0s'", digest, s)
}


Utils.MD5.calc("message digest"); //-->"f96b697d7cb7938d525a2f31aaf161d0"
Utils.MD5.calc("abcdefghijklmnopqrstuvwxyz"); //-->"c3fcd3d76192e4007dfb496cca67e13b"


(ns small-projects.find-shortest-way
  (:require [clojure.string :as str]))

;Misk functions
(defn cell-empty? [maze coords]
  (= :empty (get-in maze coords)))

(defn wall? [maze coords]
  (= :wall (get-in maze coords)))

(defn track? [maze coords]
  (= :track (get-in maze coords)))

(defn get-neighbours [maze [y x cell]]
  [[y (dec x)] [(inc y) x] [y (inc x)] [(dec y) x]])

(defn get-difference [coll1 filter-coll]
  (filter #(not (contains? filter-coll %)) coll1))

(defn get-empties [maze cell]
      (->> (get-neighbours maze cell)
           (filter (partial cell-empty? maze))))

(defn possible-ways [maze cell filter-coll]
  (-> (get-empties maze cell)
      (get-difference filter-coll)))

(defn replace-cells [maze coords v]
  (if (empty? coords)
    maze
    (recur (assoc-in maze (first coords) v) (rest coords) v)))

;Print and parse functions
(def cell-code->str
  ["  " "  " "  " "  " "· " "╵ " "╴ " "┘ "
   "  " "  " "  " "  " "╶─" "└─" "──" "┴─"
   "  " "  " "  " "  " "╷ " "│ " "┐ " "┤ "
   "  " "  " "  " "  " "┌─" "├─" "┬─" "┼─"
   "  " "  " "  " "  " "■ " "╹ " "╸ " "┛ "
   "  " "  " "  " "  " "╺━" "┗━" "━━" "┻━"
   "  " "  " "  " "  " "╻ " "┃ " "┓ " "┫ "
   "  " "  " "  " "  " "┏━" "┣━" "┳━" "╋━"
   "  "])

(defn get-cell-code [maze coords]
  (let [mode (if (track? maze coords) 1 0)
        check (if (zero? mode) wall? track?)]
    (transduce
      (comp
        (map (partial check maze))
        (keep-indexed (fn [idx test] (when test idx)))
        (map (partial bit-shift-left 1)))
      (completing bit-or)
      (bit-shift-left mode 5)
      (sort (conj (get-neighbours maze coords) coords)))))

(defn code->str [cell-code]
  (nth cell-code->str cell-code))

(defn maze->str-symbols [maze]
  (for [y (range (count maze))]
    (for [x (range (count (nth maze y)))]
      (code->str (get-cell-code maze [y x])))))

(defn maze->str [maze]
  (->> (maze->str-symbols maze)
       (map str/join)
       (str/join "\n")))

(defn parse-pretty-maze [maze-str]
  (->> (str/split-lines maze-str)
       (map (partial take-nth 2))
       (map (partial map #(if (= \space %) :empty :wall)))
       (map vec)
       (vec)))

;Core
(defn find-new-border [maze border old-border]
 (apply conj (map (fn [cell]
                    (zipmap (possible-ways maze cell (conj border old-border))
                            (repeat cell)))
                  (keys border))))

(defn backtrack [visited route]
  (let [cur-cell (get visited (first route))]
    (if (= cur-cell :start)
        route
        (recur visited (conj route cur-cell)))))

(defn breadth-first-search [maze start-cell end-cell]
    (loop [visited {start-cell :start}
           border {start-cell :start}
           old-border {start-cell :start}]
     (if (contains? old-border end-cell)
         (backtrack visited (list end-cell))
         (recur
           (conj visited border)
           (find-new-border maze border old-border)
           border))))

(def maze (parse-pretty-maze maze-str))

(def solved-maze
  (replace-cells maze (breadth-first-search maze [1 1] [19 19]) :track))

(println (maze->str solved-maze))


import std.stdio, std.random, std.string, std.array, std.algorithm,
       std.file, std.conv;

enum int cx = 4, cy = 2; // Cell size x and y.
enum int cx2 = cx / 2, cy2 = cy / 2;
enum pathSymbol = '.';
struct V2 { int x, y; }

bool solveMaze(char[][] maze, in V2 s, in V2 end) pure nothrow @safe @nogc {
    if (s == end)
        return true;

    foreach (immutable d; [V2(0, -cy), V2(+cx, 0), V2(0, +cy), V2(-cx, 0)])
        if (maze[s.y + (d.y / 2)][s.x + (d.x / 2)] == ' ' &&
            maze[s.y + d.y][s.x + d.x] == ' ') {
//Would this help?
//          maze[s.y + (d.y / 2)][s.x + (d.x / 2)] = pathSymbol;
            maze[s.y + d.y][s.x + d.x] = pathSymbol;
            if (solveMaze(maze, V2(s.x + d.x, s.y + d.y), end))
                return true;
            maze[s.y + d.y][s.x + d.x] = ' ';
        }

    return false;
}

void main() {
    auto maze = "maze.txt".File.byLine.map!(r => r.chomp.dup).array;
    immutable h = (maze.length.signed - 1) / cy;
    assert (h > 0);
    immutable w = (maze[0].length.signed - 1) / cx;

    immutable start = V2(cx2 + cx * uniform(0, w), cy2 + cy * uniform(0, h));
    immutable end = V2(cx2 + cx * uniform(0, w), cy2 + cy * uniform(0, h));

    maze[start.y][start.x] = pathSymbol;
    if (!solveMaze(maze, start, end))
        return "No solution path found.".writeln;
    maze[start.y][start.x] = 'S';
    maze[end.y][end.x] = 'E';
    writefln("%-(%s\n%)", maze);
}


procedure SolveMaze(var AMaze: TMaze; const S, E: TPoint);
var
  Route    : TRoute;
  Position : TPoint;
  V        : TPoint; // delta vector
begin
  ClearVisited(AMaze);
  Position := S;
  Route    := TStack<TPoint>.Create;
  with Position do
  try
    AMaze[x, y].Visited := True;
    repeat
      if (y > 0)         and not AMaze[x, y-1].Visited and AMaze[x, y].PassTop    then V := Point(0, -1) else
      if (x < mwidth-1)  and not AMaze[x+1, y].Visited and AMaze[x+1, y].PassLeft then V := Point(1,  0) else
      if (y < mheight-1) and not AMaze[x, y+1].Visited and AMaze[x, y+1].PassTop  then V := Point(0,  1) else
      if (x > 0)         and not AMaze[x-1, y].Visited and AMaze[x, y].PassLeft   then V := Point(-1, 0) else
      begin
        if Route.Count = 0 then Exit;  // we are back at start so no way found
        Position := Route.Pop;         // step back
        Continue;
      end;

      Route.Push(Position);            // save current position to route
      Offset(V);                       // move forward
      AMaze[x, y].Visited := True;
    until Position = E;                // solved

    ClearVisited(AMaze);
    while Route.Count > 0 do           // Route to Maze
      with Route.Pop do
        AMaze[x, y].Visited := True;

  finally
    Route.Free;
  end;
end;

procedure Main;
var
  Maze: TMaze;
  S, E: TPoint;
begin
  Randomize;
  PrepareMaze(Maze);
  S := Point(Random(mwidth), Random(mheight));
  E := Point(Random(mwidth), Random(mheight));
  SolveMaze(Maze, S, E);
  Write(MazeToString(Maze, S, E));
  ReadLn;
end;

begin
  Main;
end.


size = 20
n = 2 * size + 1
endpos = n * n - 2
startpos = n + 1
#
f = 100 / (n - 0.5)
len m[] n * n
#
background 000
func show_maze . .
  clear
  for i range len m[]
    if m[i] = 0
      x = i mod n
      y = i div n
      color 777
      move x * f - f / 2 y * f - f / 2
      rect f * 1.5 f * 1.5
    .
  .
  sleep 0.001
.
offs[] = [ 1 n -1 (-n) ]
brdc[] = [ n - 2 -1 1 -1 ]
brdr[] = [ -1 n - 2 -1 1 ]
#
func m_maze pos . .
  m[pos] = 0
  call show_maze
  d[] = [ 0 1 2 3 ]
  for i = 3 downto 0
    d = random (i + 1)
    dir = d[d]
    d[d] = d[i]
    r = pos div n
    c = pos mod n
    posn = pos + 2 * offs[dir]
    if c <> brdc[dir] and r <> brdr[dir] and m[posn] <> 0
      posn = pos + 2 * offs[dir]
      m[(pos + posn) div 2] = 0
      call m_maze posn
    .
  .
.
func make_maze . .
  for i range len m[]
    m[i] = 1
  .
  call m_maze startpos
  m[endpos] = 0
.
call make_maze
call show_maze
#
func mark pos col . .
  x = pos mod n
  y = pos div n
  color col
  move x * f + f / 4 y * f + f / 4
  circle f / 4
.
func solve dir0 pos . found .
  call mark pos 900
  sleep 0.05
  if pos = endpos
    found = 1
  else
    for dir range 4
      posn = pos + offs[dir]
      if dir <> dir0 and m[posn] = 0 and found = 0
        call solve (dir + 2) mod 4 posn found
        if found = 0
          call mark posn 777
          sleep 0.05
        .
      .
    .
  .
.
sleep 3
call solve -1 startpos found


program MazeGenAndSolve

    // First and last columns/rows are "dead" cells. Makes generating
    // a maze with border walls much easier. Therefore, a visible
    // 20x20 maze has a maze size of 22.
    mazeSize int = 22;

    south boolean[][];
    west boolean[][];
    visited boolean[][];

    // Solution variables
    solution Dictionary;
    done boolean;
    startingRow, startingCol, endingRow, endingCol int;

    function main()
        initMaze();
        generateMaze();
        drawMaze(false); // Draw maze without solution

        solveMaze();
        drawMaze(true); // Draw maze with solution
    end

    private function initMaze()

        visited = createBooleanArray(mazeSize, mazeSize, false);

        // Initialize border cells as already visited
        for(col int from 1 to mazeSize)
            visited[col][1] = true;
            visited[col][mazeSize] = true;
        end
        for(row int from 1 to mazeSize)
            visited[1][row] = true;
            visited[mazeSize][row] = true;
        end

        // Initialize all walls as present
        south = createBooleanArray(mazeSize, mazeSize, true);
        west = createBooleanArray(mazeSize, mazeSize, true);

    end

    private function createBooleanArray(col int in, row int in, initialState boolean in) returns(boolean[][])

        newArray boolean[][] = new boolean[0][0];

        for(i int from 1 to col)
            innerArray boolean[] = new boolean[0];
            for(j int from 1 to row)
                innerArray.appendElement(initialState);
            end
            newArray.appendElement(innerArray);
        end

        return(newArray);

    end

    private function createIntegerArray(col int in, row int in, initialValue int in) returns(int[][])

        newArray int[][] = new int[0][0];

        for(i int from 1 to col)
            innerArray int[] = new int[0];
            for(j int from 1 to row)
                innerArray.appendElement(initialValue);
            end
            newArray.appendElement(innerArray);
        end

        return(newArray);

    end

    private function generate(col int in, row int in)

	    // Mark cell as visited
        visited[col][row] = true;

        // Keep going as long as there is an unvisited neighbor
        while(!visited[col][row + 1] || !visited[col + 1][row] ||
                !visited[col][row - 1] || !visited[col - 1][row])

            while(true)
                r float = MathLib.random(); // Choose a random direction

                case
                    when(r < 0.25 && !visited[col][row + 1]) // Go south
                        south[col][row] = false; // South wall down
                        generate(col, row + 1);
                        exit while;
                    when(r >= 0.25 && r < 0.50 && !visited[col + 1][row]) // Go east
                        west[col + 1][row] = false; // West wall of neighbor to the east down
                        generate(col + 1, row);
                        exit while;
                    when(r >= 0.5 && r < 0.75 && !visited[col][row - 1]) // Go north
                        south[col][row - 1] = false; // South wall of neighbor to the north down
                        generate(col, row - 1);
                        exit while;
                    when(r >= 0.75 && r < 1.00 && !visited[col - 1][row]) // Go west
                        west[col][row] = false; // West wall down
                        generate(col - 1, row);
                        exit while;
                end
            end
        end

    end

    private function generateMaze()

    	// Pick random start position (within the visible maze space)
        randomStartCol int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
        randomStartRow int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);

        generate(randomStartCol, randomStartRow);

    end

    private function drawMaze(solve boolean in)

        line string;

        // Iterate over wall arrays (skipping dead border cells as required).
        // Construct a row at a time and output to console.
        for(row int from 1 to mazeSize - 1)

            if(row > 1)
                line = "";
                for(col int from 2 to mazeSize)
                    if(west[col][row])
                        line ::= cellTest(col, row, solve);
                    else
                        line ::= cellTest(col, row, solve);
                    end
                end
                Syslib.writeStdout(line);
            end

            line = "";
            for(col int from 2 to mazeSize - 1)
                if(south[col][row])
                    line ::= "+---";
                else
                    line ::= "+   ";
                end
            end
            line ::= "+";
            SysLib.writeStdout(line);

        end

    end

    private function cellTest(col int in, row int in, solve boolean in) returns(string)

        wall string;

        // Determine cell wall structure. If in solve mode, show start, end and
        // solution markers.
        if(!solve)
            if(west[col][row])
                wall = "|   ";
            else
                wall = "    ";
            end
        else
            if(west[col][row])

                case
                    when(col == startingCol and row == startingRow)
                        wall = "| S ";
                    when(col == endingCol and row == endingRow)
                        wall = "| E ";
                    when(solution.containsKey("x=" + col + "y=" + row))
                        wall = "| * ";
                    otherwise
                        wall = "|   ";
                end

            else
                case
                    when(col == startingCol and row == startingRow)
                        wall = "  S ";
                    when(col == endingCol and row == endingRow)
                        wall = "  E ";
                    when(solution.containsKey("x=" + col + "y=" + row))
                        wall = "  * ";
                    otherwise
                        wall = "    ";
                end
            end
        end

        return(wall);
    end

    private function solve(col int in, row int in)

        if(col == 1 || row == 1 || col == mazeSize || row == mazeSize)
            return;
        end

        if(done || visited[col][row])
            return;
        end

        visited[col][row] = true;

        solution["x=" + col + "y=" + row] = true;

        // Reached the end point
        if(col == endingCol && row == endingRow)
            done = true;
        end

        if(!south[col][row]) // Go South
            solve(col, row + 1);
        end
        if(!west[col + 1][row]) // Go East
            solve(col + 1, row);
        end
        if(!south[col][row - 1]) // Go North
            solve(col, row - 1);
        end
        if(!west[col][row]) // Go West
            solve(col - 1, row);
        end

        if(done)
            return;
        end

        solution.removeElement("x=" + col + "y=" + row);

    end

    private function solveMaze()
        for(col int from 1 to mazeSize)
            for(row int from 1 to mazeSize)
                visited[col][row] = false;
            end
        end

        solution = new Dictionary(false, OrderingKind.byInsertion);
        done = false;

        // Pick random start position on first visible row
        startingCol = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
        startingRow = 2;

        // Pick random end position on last visible row
        endingCol = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
        endingRow = mazeSize - 1;

        solve(startingCol, startingRow);
    end

end


(require 'cl-lib)

(cl-defstruct maze rows cols data)

(defmacro maze-pt (w r c)
  `(+ (* (mod ,r (maze-rows ,w)) (maze-cols ,w))
      (mod ,c (maze-cols ,w))))

(defmacro maze-ref (w r c)
  `(aref (maze-data ,w) (maze-pt ,w ,r ,c)))

(defun new-maze (rows cols)
  (setq rows (1+ rows)
        cols (1+ cols))
  (let ((m (make-maze :rows rows :cols cols :data (make-vector (* rows cols) nil))))

    (dotimes (r rows)
      (dotimes (c cols)
        (setf (maze-ref m r c) (copy-sequence '(wall ceiling)))))

    (dotimes (r rows)
      (maze-set m r (1- cols) 'visited))

    (dotimes (c cols)
      (maze-set m (1- rows) c 'visited))

    (maze-unset m 0 0 'ceiling) ;; Maze Entrance
    (maze-unset m (1- rows) (- cols 2) 'ceiling) ;; Maze Exit

    m))

(defun maze-is-set (maze r c v)
  (member v (maze-ref maze r c)))

(defun maze-set (maze r c v)
  (let ((cell (maze-ref maze r c)))
    (when (not (member v cell))
      (setf (maze-ref maze r c) (cons v cell)))))

(defun maze-unset (maze r c v)
  (setf (maze-ref maze r c) (delete v (maze-ref maze r c))))

(defun print-maze (maze &optional marks)
  (dotimes (r (1- (maze-rows maze)))

    (dotimes (c (1- (maze-cols maze)))
      (princ (if (maze-is-set maze r c 'ceiling) "+---" "+   ")))
    (princ "+")
    (terpri)

    (dotimes (c (1- (maze-cols maze)))
      (princ (if (maze-is-set maze r c 'wall) "|" " "))
      (princ (if (member (cons r c) marks) " * " "   ")))
    (princ "|")
    (terpri))

  (dotimes (c (1- (maze-cols maze)))
    (princ (if (maze-is-set maze (1- (maze-rows maze)) c 'ceiling) "+---" "+   ")))
  (princ "+")
  (terpri))

(defun shuffle (lst)
  (sort lst (lambda (a b) (= 1 (random 2)))))

(defun to-visit (maze row col)
  (let (unvisited)
    (dolist (p '((0 . +1) (0 . -1) (+1 . 0) (-1 . 0)))
      (let ((r (+ row (car p)))
            (c (+ col (cdr p))))
      (unless (maze-is-set maze r c 'visited)
        (push (cons r c) unvisited))))
    unvisited))

(defun make-passage (maze r1 c1 r2 c2)
  (if (= r1 r2)
      (if (< c1 c2)
          (maze-unset maze r2 c2 'wall) ; right
        (maze-unset maze r1 c1 'wall))  ; left
    (if (< r1 r2)
        (maze-unset maze r2 c2 'ceiling)   ; up
      (maze-unset maze r1 c1 'ceiling))))  ; down

(defun dig-maze (maze row col)
  (let (backup
        (run 0))
    (maze-set maze row col 'visited)
    (push (cons row col) backup)
    (while backup
      (setq run (1+ run))
      (when (> run (/ (+ row col) 3))
        (setq run 0)
        (setq backup (shuffle backup)))
      (setq row (caar backup)
            col (cdar backup))
      (let ((p (shuffle (to-visit maze row col))))
        (if p
            (let ((r (caar p))
                  (c (cdar p)))
              (make-passage maze row col r c)
              (maze-set maze r c 'visited)
              (push (cons r c) backup))
          (pop backup)
          (setq backup (shuffle backup))
          (setq run 0))))))

(defun generate (rows cols)
  (let* ((m (new-maze rows cols)))
    (dig-maze m (random rows) (random cols))
    (print-maze m)))

(defun parse-ceilings (line)
  (let (rtn
        (i 1))
    (while (< i (length line))
      (push (eq ?- (elt line i)) rtn)
      (setq i (+ i 4)))
    (nreverse rtn)))

(defun parse-walls (line)
  (let (rtn
        (i 0))
    (while (< i (length line))
      (push (eq ?| (elt line i)) rtn)
      (setq i (+ i 4)))
    (nreverse rtn)))

(defun parse-maze (file-name)
  (let ((rtn)
        (lines (with-temp-buffer
                 (insert-file-contents-literally file-name)
                 (split-string (buffer-string) "\n" t))))
    (while lines
      (push (parse-ceilings (pop lines)) rtn)
      (push (parse-walls (pop lines)) rtn))
    (nreverse rtn)))

(defun read-maze (file-name)
  (let* ((raw (parse-maze file-name))
         (rows (1- (/ (length raw) 2)))
         (cols (length (car raw)))
         (maze (new-maze rows cols)))
    (dotimes (r rows)
      (let ((ceilings (pop raw)))
        (dotimes (c cols)
          (unless (pop ceilings)
            (maze-unset maze r c 'ceiling))))
      (let ((walls (pop raw)))
        (dotimes (c cols)
          (unless (pop walls)
            (maze-unset maze r c 'wall)))))
    maze))

(defun find-exits (maze row col)
  (let (exits)
    (dolist (p '((0 . +1) (0 . -1) (-1 . 0) (+1 . 0)))
      (let ((r (+ row (car p)))
            (c (+ col (cdr p))))
        (unless
            (cond
             ((equal p '(0 . +1)) (maze-is-set maze r   c   'wall))
             ((equal p '(0 . -1)) (maze-is-set maze row col 'wall))
             ((equal p '(+1 . 0)) (maze-is-set maze r   c   'ceiling))
             ((equal p '(-1 . 0)) (maze-is-set maze row col 'ceiling)))
          (push (cons r c) exits))))
    exits))

(defun drop-visited (maze points)
  (let (not-visited)
    (while points
      (unless (maze-is-set maze (caar points) (cdar points) 'visited)
        (push (car points) not-visited))
      (pop points))
    not-visited))

(defun solve-maze (maze)
  (let (solution
        (exit (cons (- (maze-rows maze) 2) (- (maze-cols maze) 2)))
        (pt (cons 0 0)))
    (while (not (equal pt exit))
      (maze-set maze (car pt) (cdr pt) 'visited)
      (let ((exits (drop-visited maze (find-exits maze (car pt) (cdr pt)))))
        (if (null exits)
            (setq pt (pop solution))
          (push pt solution)
          (setq pt (pop exits)))))
    (push pt solution)))

(defun solve (file-name)
  (let* ((maze (read-maze file-name))
         (solution (solve-maze maze)))
    (print-maze maze solution)))

(solve "maze.txt")


-module( maze_solving ).

-export( [task/0] ).

cells( {Start_x, Start_y}, {Stop_x, Stop_y}, Maze ) ->
    Start_pid = maze:cell_pid( Start_x, Start_y, Maze ),
    Stop_pid =  maze:cell_pid( Stop_x,  Stop_y, Maze ),
    {ok, Cells} = loop( Start_pid, Stop_pid, maze:cell_accessible_neighbours(Start_pid), [Start_pid] ),
    Cells.

task() ->
    Max_x = 16,
    Max_y = 8,
    Maze = maze:generation( Max_x, Max_y ),
    Start_x = random:uniform( Max_x ),
    Start_y = random:uniform( Max_y ),
    Stop_x = random:uniform( Max_x ),
    Stop_y = random:uniform( Max_y ),
    Cells = cells( {Start_x, Start_y}, {Stop_x, Stop_y}, Maze ),
    [maze:cell_content_set(X, ".") || X <- Cells],
    maze:cell_content_set( maze:cell_pid(Start_x, Start_y, Maze), "S" ),
    maze:cell_content_set( maze:cell_pid(Stop_x, Stop_y, Maze), "G" ),
    maze:display( Maze ),
    maze:stop( Maze ).

loop( _Start, _Stop, [], _Acc) -> {error, dead_end};
loop( _Start, Stop, [Stop], Acc ) -> {ok, lists:reverse( [Stop | Acc] )};
loop( Start, Stop, [Next], [Previous | _T]=Acc ) -> loop( Start, Stop, lists:delete(Previous, maze:cell_accessible_neighbours(Next)), [Next | Acc] );
loop( Start, Stop, Nexts, Acc ) -> loop_stop( lists:member(Stop, Nexts), Start, Stop, Nexts, Acc ).

loop_stop( true, _Start, Stop, _Nexts, Acc ) -> {ok, lists:reverse( [Stop | Acc] )};
loop_stop( false, Start, Stop, Nexts, Acc ) ->
        My_pid = erlang:self(),
        [erlang:spawn( fun() -> My_pid ! loop( Start, Stop, [X], Acc ) end ) || X <- Nexts],
        receive
        {ok, Cells} -> {ok, Cells}
        end.


module MazeSolver where

import frege.IO
import Data.Maybe

-- given two points, returns the average of them
average :: (Int, Int) -> (Int, Int) -> (Int, Int)
average (x, y) (x', y') = ((x + x') `div` 2, (y + y') `div` 2)

-- given a maze and a tuple of position and wall position, returns
-- true if the wall position is not blocked (first position is unused)
notBlocked :: [String] -> ((Int, Int), (Int, Int)) -> Bool
notBlocked maze (_, (x, y)) = (' ' == String.charAt (maze !! y) x)

-- given a list, a position, and an element, returns a new list
-- with the new element substituted at the position
substitute :: [a] -> Int -> a -> [a]
substitute orig pos el =
  let (before, after) = splitAt pos orig
  in before ++ [el] ++ tail after

-- like above, but for strings, since Frege strings are not
-- lists of characters
substituteString :: String -> Int -> String -> String
substituteString orig pos el =
  let before = substr orig 0 pos
      after = strtail orig (pos + 1)
  in before ++ el ++ after

-- given a maze and a position, draw a '*' at that position in the maze
draw :: [String] -> (Int, Int) -> [String]
draw maze (x,y) = substitute maze y $ substituteString row x "*"
  where row = maze !! y

-- given a maze, a previous position, and a list of tuples of potential
-- new positions and their wall positions, returns the solved maze, or
-- None if it cannot be solved
tryMoves :: [String] -> (Int, Int) -> [((Int, Int), (Int, Int))] -> Maybe [String]
tryMoves _ _ [] = Nothing
tryMoves maze prevPos ((newPos,wallPos):more) =
  case solve' maze newPos prevPos
       of Nothing -> tryMoves maze prevPos more
          Just maze' -> Just $ foldl draw maze' [newPos, wallPos]

-- given a maze, a new position, and a previous position, returns
-- the solved maze, or None if it cannot be solved
-- (assumes goal is upper-left corner of maze)
solve' :: [String] -> (Int, Int) -> (Int, Int) -> Maybe [String]
solve' maze (2, 1) _ = Just maze
solve' maze (x, y) prevPos =
  let newPositions = [(x, y - 2), (x + 4, y), (x, y + 2), (x - 4, y)]
      notPrev pos' = pos' /= prevPos
      newPositions' = filter notPrev newPositions
      wallPositions = map (average (x,y)) newPositions'
      zipped = zip newPositions' wallPositions
      legalMoves = filter (notBlocked maze) zipped
  in tryMoves maze (x,y) legalMoves

-- given a maze, returns a solved maze, or None if it cannot be solved
-- (starts at lower right corner and goes to upper left corner)
solve :: [String] -> Maybe [String]
solve maze = solve' (draw maze start) start (-1, -1)
  where startx = (length $ head maze) - 3
        starty = (length maze) - 2
        start = (startx, starty)

-- takes unsolved maze on standard input, prints solved maze on standard output
main _ = do
  isin  <- stdin
  isrin <- InputStreamReader.new isin
  brin  <- BufferedReader.fromISR isrin
  lns <- BufferedReader.getlines brin
  printStr $ unlines $ fromMaybe ["can't solve"] $ solve lns


package main

import (
    "bytes"
    "fmt"
    "math/rand"
    "time"
)

type maze struct {
    c2 [][]byte // cells by row
    h2 [][]byte // horizontal walls by row (ignore first row)
    v2 [][]byte // vertical walls by row (ignore first of each column)
}

func newMaze(rows, cols int) *maze {
    c := make([]byte, rows*cols)              // all cells
    h := bytes.Repeat([]byte{'-'}, rows*cols) // all horizontal walls
    v := bytes.Repeat([]byte{'|'}, rows*cols) // all vertical walls
    c2 := make([][]byte, rows)                // cells by row
    h2 := make([][]byte, rows)                // horizontal walls by row
    v2 := make([][]byte, rows)                // vertical walls by row
    for i := range h2 {
        c2[i] = c[i*cols : (i+1)*cols]
        h2[i] = h[i*cols : (i+1)*cols]
        v2[i] = v[i*cols : (i+1)*cols]
    }
    return &maze{c2, h2, v2}
}

func (m *maze) String() string {
    hWall := []byte("+---")
    hOpen := []byte("+   ")
    vWall := []byte("|   ")
    vOpen := []byte("    ")
    rightCorner := []byte("+\n")
    rightWall := []byte("|\n")
    var b []byte
    for r, hw := range m.h2 {
        for _, h := range hw {
            if h == '-' || r == 0 {
                b = append(b, hWall...)
            } else {
                b = append(b, hOpen...)
                if h != '-' && h != 0 {
                    b[len(b)-2] = h
                }
            }
        }
        b = append(b, rightCorner...)
        for c, vw := range m.v2[r] {
            if vw == '|' || c == 0 {
                b = append(b, vWall...)
            } else {
                b = append(b, vOpen...)
                if vw != '|' && vw != 0 {
                    b[len(b)-4] = vw
                }
            }
            if m.c2[r][c] != 0 {
                b[len(b)-2] = m.c2[r][c]
            }
        }
        b = append(b, rightWall...)
    }
    for _ = range m.h2[0] {
        b = append(b, hWall...)
    }
    b = append(b, rightCorner...)
    return string(b)
}

func (m *maze) gen() {
    m.g2(rand.Intn(len(m.c2)), rand.Intn(len(m.c2[0])))
}

const (
    up = iota
    dn
    rt
    lf
)

func (m *maze) g2(r, c int) {
    m.c2[r][c] = ' '
    for _, dir := range rand.Perm(4) {
        switch dir {
        case up:
            if r > 0 && m.c2[r-1][c] == 0 {
                m.h2[r][c] = 0
                m.g2(r-1, c)
            }
        case lf:
            if c > 0 && m.c2[r][c-1] == 0 {
                m.v2[r][c] = 0
                m.g2(r, c-1)
            }
        case dn:
            if r < len(m.c2)-1 && m.c2[r+1][c] == 0 {
                m.h2[r+1][c] = 0
                m.g2(r+1, c)
            }
        case rt:
            if c < len(m.c2[0])-1 && m.c2[r][c+1] == 0 {
                m.v2[r][c+1] = 0
                m.g2(r, c+1)
            }
        }
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    const height = 4
    const width = 7
    m := newMaze(height, width)
    m.gen()
    m.solve(
        rand.Intn(height), rand.Intn(width),
        rand.Intn(height), rand.Intn(width))
    fmt.Print(m)
}

func (m *maze) solve(ra, ca, rz, cz int) {
    var rSolve func(ra, ca, dir int) bool
    rSolve = func(r, c, dir int) bool {
        if r == rz && c == cz {
            m.c2[r][c] = 'F'
            return true
        }
        if dir != dn && m.h2[r][c] == 0 {
            if rSolve(r-1, c, up) {
                m.c2[r][c] = '^'
                m.h2[r][c] = '^'
                return true
            }
        }
        if dir != up && r+1 < len(m.h2) && m.h2[r+1][c] == 0 {
            if rSolve(r+1, c, dn) {
                m.c2[r][c] = 'v'
                m.h2[r+1][c] = 'v'
                return true
            }
        }
        if dir != lf && c+1 < len(m.v2[0]) && m.v2[r][c+1] == 0 {
            if rSolve(r, c+1, rt) {
                m.c2[r][c] = '>'
                m.v2[r][c+1] = '>'
                return true
            }
        }
        if dir != rt && m.v2[r][c] == 0 {
            if rSolve(r, c-1, lf) {
                m.c2[r][c] = '<'
                m.v2[r][c] = '<'
                return true
            }
        }
        return false
    }
    rSolve(ra, ca, -1)
    m.c2[ra][ca] = 'S'
}


#!/usr/bin/runhaskell

import Data.Maybe (fromMaybe)

-- given two points, returns the average of them
average :: (Int, Int) -> (Int, Int) -> (Int, Int)
average (x, y) (x_, y_) = ((x + x_) `div` 2, (y + y_) `div` 2)

-- given a maze and a tuple of position and wall position, returns
-- true if the wall position is not blocked (first position is unused)
notBlocked :: [String] -> ((Int, Int), (Int, Int)) -> Bool
notBlocked maze (_, (x, y)) = ' ' == (maze !! y) !! x

-- given a list, a position, and an element, returns a new list
-- with the new element substituted at the position
-- (it seems such a function should exist in the standard library;
-- I must be missing it)
substitute :: [a] -> Int -> a -> [a]
substitute orig pos el =
  let (before, after) = splitAt pos orig
  in before ++ [el] ++ tail after

-- given a maze and a position, draw a '*' at that position in the maze
draw :: [String] -> (Int, Int) -> [String]
draw maze (x, y) =
  let row = maze !! y
  in substitute maze y $ substitute row x '*'

-- given a maze, a previous position, and a list of tuples of potential
-- new positions and their wall positions, returns the solved maze, or
-- None if it cannot be solved
tryMoves :: [String]
         -> (Int, Int)
         -> [((Int, Int), (Int, Int))]
         -> Maybe [String]
tryMoves _ _ [] = Nothing
tryMoves maze prevPos ((newPos, wallPos):more) =
  case solve_ maze newPos prevPos of
    Nothing -> tryMoves maze prevPos more
    Just maze_ -> Just $ foldl draw maze_ [newPos, wallPos]

-- given a maze, a new position, and a previous position, returns
-- the solved maze, or None if it cannot be solved
-- (assumes goal is upper-left corner of maze)
solve_ :: [String] -> (Int, Int) -> (Int, Int) -> Maybe [String]
solve_ maze (2, 1) _ = Just maze
solve_ maze pos@(x, y) prevPos =
  let newPositions = [(x, y - 2), (x + 4, y), (x, y + 2), (x - 4, y)]
      notPrev pos_ = pos_ /= prevPos
      newPositions_ = filter notPrev newPositions
      wallPositions = map (average pos) newPositions_
      zipped = zip newPositions_ wallPositions
      legalMoves = filter (notBlocked maze) zipped
  in tryMoves maze pos legalMoves

-- given a maze, returns a solved maze, or None if it cannot be solved
-- (starts at lower right corner and goes to upper left corner)
solve :: [String] -> Maybe [String]
solve maze = solve_ (draw maze start) start (-1, -1)
  where
    startx = length (head maze) - 3
    starty = length maze - 2
    start = (startx, starty)

-- takes unsolved maze on standard input, prints solved maze on standard output
main =
  let main_ = unlines . fromMaybe ["can_t solve"] . solve . lines
  in interact main_


procedure main(A)
   /mh := \A[1] | 12
   /mw := \A[2] | 16
   mz := DisplayMaze(GenerateMaze(mh,mw))
   WriteImage(mz.filename)              # save file
   WAttrib(mz.window,"canvas=normal")   # show it
   until Event() == &lpress # wait for left mouse press
   Solver(mz.maze)
   DisplayMazeSolution(mz)
   WriteImage(mz.filename ?:= (="maze-", "maze-solved-" || tab(0)))
   until Event() == &lpress # wait
   close(mz.window)
end


maze=:4 :0
  assert.0<:n=.<:x*y
  horiz=. 0$~x,y-1
  verti=. 0$~(x-1),y
  path=.,:here=. ?x,y
  unvisited=.0 (<here+1)} 0,0,~|:0,0,~1$~y,x
  while.n do.
    neighbors=. here+"1 (,-)=0 1
    neighbors=. neighbors #~ (<"1 neighbors+1) {unvisited
    if.#neighbors do.
      n=.n-1
      next=. ({~ [email protected]#) neighbors
      unvisited=.0 (<next+1)} unvisited
      if.{.next=here
      do. horiz=.1 (<-:here+next-0 1)} horiz
      else. verti=. 1 (<-:here+next-1 0)} verti end.
      path=.path,here=.next
    else.
      here=.{:path
      path=.}:path
    end.
  end.
  horiz;verti
)

NB. source Dijkstra_equal_weights graph
NB.
NB.        +   +---+---+
NB.        | 0   1   2 |  (sample cell numbers)
NB.        +---+   +   +
NB.        | 3   4 | 5
NB.        +---+---+---+
NB.
NB. graph =: 1;0 2 4;1 5;4;1 3;2
NB. The graph is a vector of boxed vectors of neighbors.

Dijkstra_equal_weights =: 4 : 0
 dist =. previous =. #&_ n =. # graph =. y [ source =. x
 dist =. 0 source } dist
 Q =. 0
 while. #Q do.
   u =. {.Q
   Q =. }.Q
   if. _ = u{dist do. break. end.
   for_v. >u{graph do.
     if. -. v e. previous do.
       alt =. >: u { dist
       if. alt < v { dist do.
         dist =. alt v } dist
         previous =. u v } previous
         if. v e. Q do.
           echo 'belch'
         else.
           Q =. Q,v
         end.
       end.
     end.
   end.
 end.
 dist;previous
)

path =: 3 : 0
  p =. <:#y
  while. _ > {:p do.
    p =. p,y{~{:p
  end.
  |.}:p
)

solve=:3 :0
  NB. convert walls to graph
  shape =. }[email protected][email protected]:>
  ew =. (,.&0 ,: 0&,.)@>@{.  NB. east west doors
  ns =. (, &0 ,: 0&, )@>@{:
  cell_offsets =. 1 _1 1 _1 * 2 # 1 , {:@shape
  cell_numbers =. [email protected]
  neighbors =. (cell_numbers +"_ _1 cell_offsets *"_1 (ew , ns))y
  graph =. (|:@(,/"_1) <@-."1 0 ,@[email protected])neighbors NB. list of boxed neighbors
  NB. solve it
  path , > {: 0 Dijkstra_equal_weights graph
)

display=:3 :0
  size=. >.&$&>/y
  text=. (}:1 3$~2*1+{:size)#"1":size$<' '
  'hdoor vdoor'=. 2 4&*&.>&.> (#&,{@;&i./@$)&.> y
  ' ' (a:-.~0 1;0 2; 0 3;(2 1-~$text);(1 4&+&.> hdoor),,vdoor+&.>"0/2 1;2 2;2 3)} text
:
  a=. display y
  size=. >.&$&>/y
  columns=. {: size
  cells =. <"1(1 2&[email protected]<[email protected](%&columns) ,.  2 4&[email protected](columns&|))x
  'o' cells } a  NB. exercise, replace cells with a gerund to draw arrows on the path.
)


import java.io.*;
import java.util.*;

public class MazeSolver
{
    /**
     * Reads a file into an array of strings, one per line.
     */
    private static String[] readLines (InputStream f) throws IOException
    {
        BufferedReader r =
            new BufferedReader (new InputStreamReader (f, "US-ASCII"));
        ArrayList<String> lines = new ArrayList<String>();
        String line;
        while ((line = r.readLine()) != null)
            lines.add (line);
        return lines.toArray(new String[0]);
    }

    /**
     * Makes the maze half as wide (i. e. "+---+" becomes "+-+"), so that
     * each cell in the maze is the same size horizontally as vertically.
     * (Versus the expanded version, which looks better visually.)
     * Also, converts each line of the maze from a String to a
     * char[], because we'll want mutability when drawing the solution later.
     */
    private static char[][] decimateHorizontally (String[] lines)
    {
        final int width = (lines[0].length() + 1) / 2;
        char[][] c = new char[lines.length][width];
        for (int i = 0  ;  i < lines.length  ;  i++)
            for (int j = 0  ;  j < width  ;  j++)
                c[i][j] = lines[i].charAt (j * 2);
        return c;
    }

    /**
     * Given the maze, the x and y coordinates (which must be odd),
     * and the direction we came from, return true if the maze is
     * solvable, and draw the solution if so.
     */
    private static boolean solveMazeRecursively (char[][] maze,
                                                 int x, int y, int d)
    {
        boolean ok = false;
        for (int i = 0  ;  i < 4  &&  !ok  ;  i++)
            if (i != d)
                switch (i)
                    {
                        // 0 = up, 1 = right, 2 = down, 3 = left
                    case 0:
                        if (maze[y-1][x] == ' ')
                            ok = solveMazeRecursively (maze, x, y - 2, 2);
                        break;
                    case 1:
                        if (maze[y][x+1] == ' ')
                            ok = solveMazeRecursively (maze, x + 2, y, 3);
                        break;
                    case 2:
                        if (maze[y+1][x] == ' ')
                            ok = solveMazeRecursively (maze, x, y + 2, 0);
                        break;
                    case 3:
                        if (maze[y][x-1] == ' ')
                            ok = solveMazeRecursively (maze, x - 2, y, 1);
                        break;
                    }
        // check for end condition
        if (x == 1  &&  y == 1)
            ok = true;
        // once we have found a solution, draw it as we unwind the recursion
        if (ok)
            {
                maze[y][x] = '*';
                switch (d)
                    {
                    case 0:
                        maze[y-1][x] = '*';
                        break;
                    case 1:
                        maze[y][x+1] = '*';
                        break;
                    case 2:
                        maze[y+1][x] = '*';
                        break;
                    case 3:
                        maze[y][x-1] = '*';
                        break;
                    }
            }
        return ok;
    }

    /**
     * Solve the maze and draw the solution.  For simplicity,
     * assumes the starting point is the lower right, and the
     * ending point is the upper left.
     */
    private static void solveMaze (char[][] maze)
    {
        solveMazeRecursively (maze, maze[0].length - 2, maze.length - 2, -1);
    }

    /**
     * Opposite of decimateHorizontally().  Adds extra characters to make
     * the maze "look right", and converts each line from char[] to
     * String at the same time.
     */
    private static String[] expandHorizontally (char[][] maze)
    {
        char[] tmp = new char[3];
        String[] lines = new String[maze.length];
        for (int i = 0  ;  i < maze.length  ;  i++)
            {
                StringBuilder sb = new StringBuilder(maze[i].length * 2);
                for (int j = 0  ;  j < maze[i].length  ;  j++)
                    if (j % 2 == 0)
                        sb.append (maze[i][j]);
                    else
                        {
                            tmp[0] = tmp[1] = tmp[2] = maze[i][j];
                            if (tmp[1] == '*')
                                tmp[0] = tmp[2] = ' ';
                            sb.append (tmp);
                        }
                lines[i] = sb.toString();
            }
        return lines;
    }

    /**
     * Accepts a maze as generated by:
     * http://rosettacode.org/wiki/Maze_generation#Java
     * in a file whose name is specified as a command-line argument,
     * or on standard input if no argument is specified.
     */
    public static void main (String[] args) throws IOException
    {
        InputStream f = (args.length > 0
                         ?  new FileInputStream (args[0])
                         :  System.in);
        String[] lines = readLines (f);
        char[][] maze = decimateHorizontally (lines);
        solveMaze (maze);
        String[] solvedLines = expandHorizontally (maze);
        for (int i = 0  ;  i < solvedLines.length  ;  i++)
            System.out.println (solvedLines[i]);
    }
}


var ctx, wid, hei, cols, rows, maze, stack = [], start = {x:-1, y:-1}, end = {x:-1, y:-1}, grid = 8;
function drawMaze() {
    for( var i = 0; i < cols; i++ ) {
        for( var j = 0; j < rows; j++ ) {
            switch( maze[i][j] ) {
                case 0: ctx.fillStyle = "black"; break;
                case 1: ctx.fillStyle = "green"; break;
                case 2: ctx.fillStyle = "red"; break;
                case 3: ctx.fillStyle = "yellow"; break;
                case 4: ctx.fillStyle = "#500000"; break;
            }
            ctx.fillRect( grid * i, grid * j, grid, grid  );
        }
    }
}
function getFNeighbours( sx, sy, a ) {
    var n = [];
    if( sx - 1 > 0 && maze[sx - 1][sy] == a ) {
        n.push( { x:sx - 1, y:sy } );
    }
    if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a ) {
        n.push( { x:sx + 1, y:sy } );
    }
    if( sy - 1 > 0 && maze[sx][sy - 1] == a ) {
        n.push( { x:sx, y:sy - 1 } );
    }
    if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a ) {
        n.push( { x:sx, y:sy + 1 } );
    }
    return n;
}
function solveMaze() {
    if( start.x == end.x && start.y == end.y ) {
        for( var i = 0; i < cols; i++ ) {
            for( var j = 0; j < rows; j++ ) {
                switch( maze[i][j] ) {
                    case 2: maze[i][j] = 3; break;
                    case 4: maze[i][j] = 0; break;
                }
            }
        }
        drawMaze();
        return;
    }
    var neighbours = getFNeighbours( start.x, start.y, 0 );
    if( neighbours.length ) {
        stack.push( start );
        start = neighbours[0];
        maze[start.x][start.y] = 2;
    } else {
        maze[start.x][start.y] = 4;
        start = stack.pop();
    }

    drawMaze();
    requestAnimationFrame( solveMaze );
}
function getCursorPos( event ) {
    var rect = this.getBoundingClientRect();
    var x = Math.floor( ( event.clientX - rect.left ) / grid ),
        y = Math.floor( ( event.clientY - rect.top  ) / grid );
    if( maze[x][y] ) return;
    if( start.x == -1 ) {
        start = { x: x, y: y };
    } else {
        end = { x: x, y: y };
        maze[start.x][start.y] = 2;
        solveMaze();
    }
}
function getNeighbours( sx, sy, a ) {
    var n = [];
    if( sx - 1 > 0 && maze[sx - 1][sy] == a && sx - 2 > 0 && maze[sx - 2][sy] == a ) {
        n.push( { x:sx - 1, y:sy } ); n.push( { x:sx - 2, y:sy } );
    }
    if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a && sx + 2 < cols - 1 && maze[sx + 2][sy] == a ) {
        n.push( { x:sx + 1, y:sy } ); n.push( { x:sx + 2, y:sy } );
    }
    if( sy - 1 > 0 && maze[sx][sy - 1] == a && sy - 2 > 0 && maze[sx][sy - 2] == a ) {
        n.push( { x:sx, y:sy - 1 } ); n.push( { x:sx, y:sy - 2 } );
    }
    if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a && sy + 2 < rows - 1 && maze[sx][sy + 2] == a ) {
        n.push( { x:sx, y:sy + 1 } ); n.push( { x:sx, y:sy + 2 } );
    }
    return n;
}
function createArray( c, r ) {
    var m = new Array( c );
    for( var i = 0; i < c; i++ ) {
        m[i] = new Array( r );
        for( var j = 0; j < r; j++ ) {
            m[i][j] = 1;
        }
    }
    return m;
}
function createMaze() {
    var neighbours = getNeighbours( start.x, start.y, 1 ), l;
    if( neighbours.length < 1 ) {
        if( stack.length < 1 ) {
            drawMaze(); stack = [];
            start.x = start.y = -1;
            document.getElementById( "canvas" ).addEventListener( "mousedown", getCursorPos, false );
            return;
        }
        start = stack.pop();
    } else {
        var i = 2 * Math.floor( Math.random() * ( neighbours.length / 2 ) )
        l = neighbours[i]; maze[l.x][l.y] = 0;
        l = neighbours[i + 1]; maze[l.x][l.y] = 0;
        start = l
        stack.push( start )
    }
    drawMaze();
    requestAnimationFrame( createMaze );
}
function createCanvas( w, h ) {
    var canvas = document.createElement( "canvas" );
    wid = w; hei = h;
    canvas.width = wid; canvas.height = hei;
    canvas.id = "canvas";
    ctx = canvas.getContext( "2d" );
    ctx.fillStyle = "black"; ctx.fillRect( 0, 0, wid, hei );
    document.body.appendChild( canvas );
}
function init() {
    cols = 73; rows = 53;
    createCanvas( grid * cols, grid * rows );
    maze = createArray( cols, rows );
    start.x = Math.floor( Math.random() * ( cols / 2 ) );
    start.y = Math.floor( Math.random() * ( rows / 2 ) );
    if( !( start.x & 1 ) ) start.x++; if( !( start.y & 1 ) ) start.y++;
    maze[start.x][start.y] = 0;
    createMaze();
}


"""
    +   +---+---+
    | 1   2   3 |
    +---+   +   +
    | 4   5 | 6
    +---+---+---+

    julia> const graph = [
            0 1 0 0 0 0;
            1 0 1 0 1 0;
            0 1 0 0 0 1;
            0 0 0 0 1 0;
            0 1 0 1 0 0;
            0 0 1 0 0 0]

    julia> dist, path = dijkstra(graph, 1)
    (Dict(4=>3,2=>1,3=>2,5=>2,6=>3,1=>0), Dict(4=>5,2=>1,3=>2,5=>2,6=>3,1=>0))

    julia> printpath(path, 6) # Display solution of the maze
    1 -> 2 -> 3 -> 6

"""
function dijkstra(graph, source::Int=1)
    # ensure that the adjacency matrix is squared
    @assert size(graph, 1) == size(graph, 2)
    inf = typemax(Int64)
    n   = size(graph, 1)

    Q    = IntSet(1:n)                  # Set of unvisited nodes
    dist = Dict(n => inf for n in Q)    # Unknown distance function from source to v
    prev = Dict(n => 0   for n in Q)    # Previous node in optimal path from source
    dist[source] = 0                    # Distance from source to source

    function _minimumdist(nodes) # Find the less distant node among nodes
        kmin, vmin = nothing, inf
        for (k, v) in dist
            if k ∈ nodes && v ≤ vmin
                kmin, vmin = k, v
            end
        end
        return kmin
    end
    # Until all nodes are visited...
    while !isempty(Q)
        u = _minimumdist(Q)         # Vertex in Q with smallest dist[]
        pop!(Q, u)
        if dist[u] == inf break end # All remaining vertices are inaccessible from source
        for v in 1:n                # Each neighbor v of u
            if graph[u, v] != 0 && v ∈ Q # where v has not yet been visited
                alt = dist[u] + graph[u, v]
                if alt < dist[v]    # Relax (u, v, a)
                    dist[v] = alt
                    prev[v] = u
                end
            end
        end
    end

    return dist, prev
end

function printpath(prev::Dict, target::Int)
    path = "$target"
    while prev[target] != 0
        target = prev[target]
        path = "$target -> " * path
    end
    println(path)
end

const graph = [
    0 1 0 0 0 0;
    1 0 1 0 1 0;
    0 1 0 0 0 1;
    0 0 0 0 1 0;
    0 1 0 1 0 0;
    0 0 1 0 0 0]

dist, path = dijkstra(graph)
printpath(path, 6)