Task and concurrent access in Julia
I would like to implement in Julia the management of virtual keyboards which are each associated o a dedicated task (or process,thread ...).
In Ada this is managed through the use of protected type objects for these virtual keyboards and of a task which scans the keyboard of the computer,as summarized in the following code example.
How could this be implemented in Julia ? Documentation is apparently poor on concurrent access control in Julia.
with Unchecked_Deallocation;
package Buffer is
N : constant := 128;
type Index is mod N;
type Char_Array is array (Index) of Character;
protected type Keyboard is
entry Put (X : in Character);
entry Get (X : out Character);
private
A : Char_Array;
In_Ptr, Out_Ptr : Index := 0;
Count : Integer range 0 .. N := 0;
end Keyboard;
type Keyboard_Ptr is access all Keyboard;
procedure Free is new Unchecked_Deallocation (Keyboard, Keyboard_Ptr);
end Buffer;
package body Buffer is
protected body Keyboard is
entry Put (X : in Character) when Count < N is
begin
A (In_Ptr) := X;
In_Ptr := In_Ptr + 1;
Count := Count + 1;
end Put;
entry Get (X : out Character) when Count > 0 is
begin
X := A (Out_Ptr);
Out_Ptr := Out_Ptr + 1;
Count := Count - 1;
end Get;
end Keyboard;
end Buffer;
task Keyboard_Handler;
task body Keyboard_Handler is
K0 : Character;
Available : Boolean := False;
-- Keyboard_Current : Keyboard_Ptr is defined at upper level
begin
loop
Get_Immediate (K0, Available);
if Available and then Character'Pos (K0) /= 0 then
Keyboard_Current.Put (K0);
end if;
delay 0.06;
end loop;
end Keyboard_Handler;
One first step is to show how to intercept specific keystokes (for example : arrows, w, v) and how to feed a channel with them. The following works fine on Windows to feed the main process with keyboard informations:
ch1 = Channel{String}(128)
function run(ch1::Channel)
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
put!(ch1, "w")
elseif c1 == Int32('v')
put!(ch1, "v")
end
end
end
buffer = Channel(run)
for x in buffer
println(x)
end
Now I would like to feed a task of my choice with the keyboard inputs. May be with something like :
using Distributed
addprocs(3)
function tache1(ch::Channel)
for x in ch
println("TACHE 1 :",x)
end
end
function tache2(ch::Channel)
for x in ch
println("TACHE 2 :",x)
end
end
buffer1 = Channel(tache1)
buffer2 = Channel(tache2)
ch1 = buffer1
function run()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
ch1 = Channel(tache1)
elseif c1 == Int32('v')
ch1 = Channel(tache2)
end
end
end
f = #spawnat 1 run()
function t1()
for x in buffer1
println("11111 ",x)
end
end
function t2()
for x in buffer2
println("22222 ",x)
end
end
h1 = #spawnat 2 t1()
h2 = #spawnat 3 t2()
for x in buffer1
println(x)
end
But it does not work ! May be Julia is not able to do what Ada can do quite easily ... ?? Or more probably I have a very bad understanding of the multitask aspects of Julia.
You added some code to the question, so I added the code here.
The original example is below this.
# This works and perhaps is what you wanted to do?
# I am unsure of some of the tasks you set up in the question's code.
CHAN1 = Channel{String}(0)
CHAN2 = Channel{String}(0)
function tache1()
while true
x = take!(CHAN1)
println("TACHE 1 :", x)
end
end
function tache2()
while true
x = take!(CHAN2)
println("TACHE 2 :", x)
end
end
function run()
try
println("Esc to exit.")
chan = CHAN1
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(chan, "KEY UP")
elseif c2 == 80
put!(chan, "KEY DOWN")
elseif c2 == 77
put!(chan, "KEY RIGHT")
elseif c2 == 75
put!(chan, "KEY LEFT")
elseif c2 == 81
put!(chan, "ALT KEY DOWN")
elseif c2 == 73
put!(chan, "ALT KEY UP")
end
elseif c1 == Int32('w')
chan = CHAN1
elseif c1 == Int32('v')
chan = CHAN2
elseif(c1 == 27)
close(CHAN1)
close(CHAN2)
exit(0)
else
println(Char(c1))
end
end
catch y
println("Exception caught: ", y)
exit(1)
end
end
#async run()
#async tache1()
#async tache2()
while true
sleep(0.05)
end
CUT ---------------------------------------------------------------------
Here is an example (Julia 1.0) of using the Gtk library to intercept keystrokes in 3 different windows. You could use the Channel functions with Windows C calls to _getch as well.
#(note: revised to show Channel usage)
using Gtk.ShortNames
function keypresswindow(chan)
# This code creates the Gtk widgets on the screen.
txt = "Type Y or N"
win = Window("Keypress Test", 250, 30) |> (Frame() |>
((vbox = Box(:v)) |> (lab = Label(txt))))
# this is the keystroke processing code, a function and a callback for the function.
function keycall(w, event)
ch = Char(event.keyval)
put!(chan, ch)
set_gtk_property!(lab,:label, ch in('n','N','y','Y') ? "You hit the $ch key." : txt)
end
Gtk.signal_connect(keycall, win, "key-press-event")
# this code sets up a proper exit when the widow is closed.
c = Condition()
endit(w) = notify(c)
Gtk.signal_connect(endit, win, :destroy)
Gtk.showall(win)
wait(c)
end
function reader(chan)
while true
try
c = take!(chan)
print(c)
catch
return
end
end
end
function inputwindows(chan, numwindows)
#async reader(chan)
println("starting input windows")
#sync(
for i in 1:numwindows
#async keypresswindow(chan)
end
)
println("finished")
end
const chan = Channel(1020)
inputwindows(chan, 3)
In fact the solution to my question does not need Channel. The simple fact that Tasks in Julia are mere coroutines, guarantes that there will be no confict on keyboard access. On Windows platform a demonstration of a solution for 2 Tasks chosen and driven through keyboard interaction is :
function run1()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP1")
elseif c2 == 80
println("KEY DOWN1")
elseif c2 == 77
println("KEY RIGHT1")
elseif c2 == 75
println("KEY LEFT1")
elseif c2 == 81
println("ALT KEY DOWN1")
elseif c2 == 73
println("ALT KEY UP1")
end
elseif c1 == Int32('w')
yieldto(tb)
end
end
end
function run2()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP2")
elseif c2 == 80
println("KEY DOWN2")
elseif c2 == 77
println("KEY RIGHT2")
elseif c2 == 75
println("KEY LEFT2")
elseif c2 == 81
println("ALT KEY DOWN2")
elseif c2 == 73
println("ALT KEY UP2")
end
elseif c1 == Int32('w')
yieldto(ta)
end
end
end
ta = Task(run1)
tb = Task(run2)
yieldto(tb)
Related
I'm new to pinescript and I can't figure out what's wrong with my if syntax. Please help
//#version=4
strategy(title="Weighted Moving ATR", shorttitle="WMATR Stra Test", overlay = true)
//Changing inputs based on ticker
if (syminfo.ticker == "AAPL")
LenWATR = 43
MultWATR = 1
else if (syminfo.ticker == "AAL")
LenWATR = 21
MultWATR = 1
I keep getting line 13: Mismatched input 'LenWATR' expecting 'end of line without line continuation'.
The reason you're getting the error is because the indentation is wrong.
You're indenting with 5 whitespaces, but indententations should be a multiple of 4 whitespaces.
You could also write it like this:
//#version=4
strategy(title="Weighted Moving ATR", shorttitle="WMATR Stra Test", overlay = true)
var int LenWATR = na
var int MultWATR = na
//Changing inputs based on ticker
LenWATR := if syminfo.ticker == "AAPL"
43
else if syminfo.ticker == "AAL"
1
else
99 // default value
MultWATR := if syminfo.ticker == "AAL"
1
else if syminfo.ticker == "AAL"
1
else
77 // default value
//Changing inputs based on ticker: short version
LenWATR := syminfo.ticker == "AAPL" ? 43 : syminfo.ticker == "AAL" ? 1 : 99
MultWATR := syminfo.ticker == "AAPL" ? 1 : syminfo.ticker == "AAL" ? 1 : 77
plot(na)
You don't need parenthesis. Also if you are using = in your if statement blocks you are initializing variables in a local scope. If the variables exist elsewhere value assignment should use :=
I have this warning and I would like to know why he wait an expression of type Unix.file_descr list * Unix.file_descr list * Unix.file_descr list
Here is the function, if you need more code, just ask me.
let rec run()=
let a = create_bloc() in
trace_bloc(a);
let b : char ref = ref 'f' in
while true do
b := 'f';
if !(a.s) = 1 then run() else
let c = get_move() in
if c = Some 'z' then b:= 'z'
else if c = Some 'q' then b:= 'q'
else if c = Some 's' then b:= 's'
else if c = Some 'd' then b:= 'd';
if !b = 'z' || !b = 's' then
if !(a.o) = 4 && !b = 'z' then begin erase_bloc(a) ;a.o := 1; trace_bloc(a); end
else if !b = 'z' && !(a.o) <> 4 then begin erase_bloc(a); a.o := !(a.o)+1; end;
if !b = 's' && !(a.o)=1 then begin erase_bloc(a);a.o := 4;trace_bloc(a);end else
if !b = 's' && !(a.o) <> 1 then begin erase_bloc(a); a.o := !(a.o)-1;trace_bloc(a);end
else if !b = 'd' || !b = 'q' then
decal(a,!b);
dep_bas(a);
Unix.select [] [] [] 0.35;
done;
;;
The Unix.file_descr list * Unix.file_descr list * Unix.file_descr list type is the type of a value that is retuned by the expression Unix.select [] [] [] 0.35;
OCaml doesn't allow you to ignore a value returned by a function that has a type other than unit. You can, however, use the ignore function to tell explicitly to the compiler that you don't need the result of the select function,
ignore (Unix.select [] [] [] 0.35);
You can also use Unix.sleepf function to implement sleeping that supports fractions of seconds, e.g., you can substitute the above expression with just,
Unix.sleepf 0.35
This will as well pause your program for 350 milliseconds.
I have a VB 5.0 code that does what I need, but I need to implement it in Visual Studio C++ (2013), the thing is that I'm not getting there, and I have no idea what I'm doing wrong, so I'll show you some code (VB vs C++ - mine) and hope someone is able to help.
For now, thank you for reading this.
I've tried to send the string in very different formats and I think that I finally got it, in how to send, the problem still is reading the answer, I have no idea what I'm doing wrong.
The machine returns (I think 2 bytes) and they are START OF HEADING and ?, I can see it by printing in the console the numbers 1 and 63.
I'll just leave some code.
For asking the current temperature the VB program is:
Private Sub cmdGetTemperaturePV_Click()
If MSComm.PortOpen Then
MSComm.Output = Chr(1) & Chr(0) & Chr(0) & Chr(1) & Chr(13) & Chr(10)
txtMsg(1).Text = "1,0,0,1,13,10"
txtPVTemperature.Text = ""
Else
txtMsg(1).Text = "COM Port OFF"
Beep
End If
End Sub
And mine(C++) is:
String^ a1 = "\x1";
String^ a2 = "\x0";
String^ a3 = "\x0";
String^ a4 = "\x1";
String^ a5 = "\xD";
String^ a6 = "\xA";
String^ enviar = a1 + a2 + a3 + a4 + a5 + a6;
this->serialPort1->Write(enviar);
By using the program "Hercules" I can simulate the reception of the machine and I can see that I'm sending exactly the same thing as the VB program.
Now I think that the problem is receiving, so about that, there's this:
Private Sub tmrRun_Timer()
Dim i As Integer
Dim apt As Byte, B1 As Byte, B2 As Byte
Dim stx As String
If MSComm.PortOpen Then
If MSComm.InBufferCount >= 6 Then
stx = MSComm.Input
stx = Right(stx, 6)
txtMsg(2).Text = ""
For i = 1 To Len(stx)
txtMsg(2).Text = txtMsg(2).Text & Asc(Mid(stx, i, 1)) & ","
Next i
txtMsg(2).Text = Left(txtMsg(2).Text, Len(txtMsg(2).Text) - 1)
apt = Asc(Left(stx, 1))
B1 = Asc(Mid(stx, 2, 1))
B2 = Asc(Mid(stx, 3, 1))
Select Case apt
Case 1:
txtPVTemperature.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 2:
txtSPTemperature.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 3:
Case 4:
txtPVHumidity.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 5:
txtSPHumidity.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 6:
Case 7:
Case 8:
Case 9:
If Asc(Mid(stx, 2, 1)) > 0 Then
txtChamber.Text = "ON"
Else
txtChamber.Text = "OFF"
End If
Case 10:
txtEvents.Text = GetInt(B1, B2)
Case 11:
Case 12:
txtInputs.Text = "1..8 = " & B1 & " 9..16 = " & B2
Case 13:
txtAlarms1.Text = " 1.. 8 = " & B1 & " 9..16 = " & B2
Case 14:
txtAlarms2.Text = "17..24 = " & B1 & " 25..32 = " & B2
End Select
End If
End If
End Sub
And I'm trying many different things, the best I got (the one that led me to 1 and 63) is this:
{
String^ rec;
if (this->serialPort1->IsOpen)
{
this->textBox1->Text = String::Empty;
try
{
rec = this->serialPort1->ReadExisting();
}
catch (TimeoutException^)
{
this->textBox2->Text = "Timeout";
}
}
this->textBox1->Text = rec;
char aux[100];
if (rec == String::Empty)
this->textBox2->Text = "String Empty";
else
{
std::string rec1 = marshal_as<std::string>(rec);
strcpy(aux, rec1.c_str());
int a, b, c, d, e1, f;
printf("String received: ");
for (int i = 0; i < 6; i++)
{
if (aux[i] == 0)
break;
printf("%ld ", aux[i]);
if (i == 0)
a = aux[i];
if (i == 1)
b = aux[i];
if (i == 2)
c = aux[i];
if (i == 3)
d = aux[i];
if (i == 4)
e1 = aux[i];
if (i == 5)
f = aux[i];
}
}
}
I'm expecting to receive a 6 byte string and It's not happening.
I'm so sorry for the long post, but I think this way I can be more specific.
Again, thank you very much!
We get data from another company in the following formats
374-KH-ON-PEAK|807-KH-OFF-PEAK
82.5-KH-TOTAL|8-K1-CURRENT
44.5-KH-TOTAL
65-KH-ON-PEAK|2.1-K1-ON-PEAK|164-KH-OFF-PEAK|27-K1
These values go into a SQL Server table. The numbers represent electricity usages. I'm working on finding a way to extract the numbers and sum them together.
There is only one condition: the number must be followed by "-KH". If it is followed by "-K1" we don't need to do anything with it.
Upon inputting "65-KH-ON-PEAK|2.1-K1-ON-PEAK|164-KH-OFF-PEAK|27-K1", I need to output 229 which stands for 65 + 164
I'd prefer to find a solution using VBA for Access(For reasons related to the business's current software solutions), but I'm open to other solutions as well.
Using [Excel] can be done like this:
code:
Sub test()
Dim cl As Range, z!, x As Variant, x2 As Variant
For Each cl In [A1:A4]
z = 0
For Each x In Split(cl.Value2, "|")
If x Like "*-KH-*" Then
For Each x2 In Split(x, "-")
If IsNumeric(x2) Then z = z + x2
Next x2
End If
Next x
cl.Offset(, 1).Value = z
Next cl
End Sub
another variant, without second loop (using #shawnt00 comment below OP)
Sub test()
Dim cl As Range, z!, x As Variant
For Each cl In [A1:A4]
z = 0
For Each x In Split(cl.Value2, "|")
If x Like "*-KH-*" Then z = z + Left(x, InStr(1, x, "-") - 1)
Next x
cl.Offset(, 1).Value = z
Next cl
End Sub
output:
Using [Access] can be something like this:
Sub test2()
Dim z!, x As Variant
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Table1")
Do Until rs.EOF = True
z = 0
For Each x In Split(rs!Field1, "|")
If x Like "*-KH-*" Then z = z + Left(x, InStr(1, x, "-") - 1)
Next x
Debug.Print rs!Field1, z
rs.MoveNext
Loop
End Sub
test:
You would do a single bulk insert into an SQL Server table using | as the field terminator, so you would have fields like f1,f2,f3,f4. Then you can use an expression like:
WITH numerics
AS ( SELECT CASE
WHEN PATINDEX('%-KH-%', f1) > 0
THEN CAST(SUBSTRING(f1, 1, PATINDEX('%-KH-%', f1) - 1) AS INT)
ELSE 0
END AS f1,
CASE
WHEN PATINDEX('%-KH-%', f2) > 0
THEN CAST(SUBSTRING(f2, 1, PATINDEX('%-KH-%', f2) - 1) AS INT)
ELSE 0
END AS f2,
CASE
WHEN PATINDEX('%-KH-%', f3) > 0
THEN CAST(SUBSTRING(f3, 1, PATINDEX('%-KH-%', f3) - 1) AS INT)
ELSE 0
END AS f3,
CASE
WHEN PATINDEX('%-KH-%', f4) > 0
THEN CAST(SUBSTRING(f4, 1, PATINDEX('%-KH-%', f4) - 1) AS INT)
ELSE 0
END AS f4
FROM myTable )
SELECT f1 + f2 + f3 + f4 AS rowTotal;
You could do it with a Powershell script, that would give the power of regex to extract and sum the numbers. Something like the example below (I have tested the extracting from the file part but not the Access parts so they may need some tweaking):
$conn = New-Object -ComObject ADODB.Connection
$recordset = New-Object -ComObject ADODB.Recordset
$conn.Open()
$cmd = $conn.CreateCommand()
$ado.open("Provider = Microsoft.ACE.OLEDB.12.0;Data Source=\\path_to\database.accdb")
# Microsoft.Jet.OLEDB.4.0 for older versions of Access
(Select-String file.txt -Pattern '[\d.]+(?=-KH)' -AllMatches) | % {
($_.Matches | % {
[double]$_.Value
} | Measure-Object -Sum).Sum
} | % {
$cmd.CommandText = "INSERT INTO TABLE VALUES($($_))"
Write-Output $cmd.ExecuteNonQuery()
}
$conn.Close()
I have written the below mentioned code but its not functional. Can anyone help?
Explanation:
A 7 or 8 digit number is set. If the number is 8 digits, the first 2 numbers are removed, if the number is 7 digits, the first number is removed. A 6 digit number is left whereby every digit can be repeated without any constraints. So one can have a number between 000001 and 999999. (Zeros on the left are counted).
The code is functional on the first 3 digits but does not function properly later on though i'm using the same logic. The function of the code is to Generate all possible patterns by translating the numbers into characters.
The constraints:
Letters used are only a, b, c, d, e, and f.
Characters should run systematic order
Under this logic:
The pattern can range between aaaaaa and abcdef.
The first character is always "a" and the last character could be "f" in case all digits are different from one another.
So, the number 454657 is translated to abacbd or 123456 is translated to abcdef. (c Can't exist if there is no b and d can't exist if there is no b and c).
Private Sub CommandButton1_Click()
Dim GSM_Counter, GSM, GSM_Range, a, b, c, d, e, f As String
Dim GSM_length, Num1, Num2, Num3, Num4, Num5, Num6, a1, b1, c1, d1, e1, f1 As integer
GSM_Counter = Application.WorksheetFunction.CountA(Range("A:A"))
For i = 2 To GSM_Counter
GSM_length = Len(Range("A" & i))
Select Case GSM_length
Case Is = 8
Range("B" & i) = Left(Range("A" & i), 2)
Num1 = Right(Left(Range("A" & i), 3), 1)
Num2 = Right(Left(Range("A" & i), 4), 1)
Num3 = Right(Left(Range("A" & i), 5), 1)
Num4 = Right(Left(Range("A" & i), 6), 1)
Num5 = Right(Left(Range("A" & i), 7), 1)
Num6 = Right(Left(Range("A" & i), 8), 1)
Case Is = 7
Range("B" & i) = Left(Range("A" & i), 1)
Num1 = Right(Left(Range("A" & i), 2), 1)
Num2 = Right(Left(Range("A" & i), 3), 1)
Num3 = Right(Left(Range("A" & i), 4), 1)
Num4 = Right(Left(Range("A" & i), 5), 1)
Num5 = Right(Left(Range("A" & i), 6), 1)
Num6 = Right(Left(Range("A" & i), 7), 1)
End Select
Range("C" & i) = Num1
Range("D" & i) = Num2
Range("E" & i) = Num3
Range("F" & i) = Num4
Range("G" & i) = Num5
Range("H" & i) = Num6
Next i
For k = 2 To GSM_Counter
a1 = Range("C" & k)
b1 = Range("D" & k)
c1 = Range("E" & k)
d1 = Range("F" & k)
e1 = Range("G" & k)
f1 = Range("H" & k)
a = "a"
Range("K" & k) = a
If b1 = a1 Then
b = "a"
Else
b = "b"
End If
Range("L" & k) = b
If c1 = a1 Then
c = "a"
ElseIf c1 = b1 Then
c = "b"
Else
c = "c"
End If
Range("M" & k) = c
If d1 = a1 Then
d = "a"
ElseIf d1 = b1 Then
d = "b"
ElseIf d1 = c1 Then
d = "c"
Else
d = "d"
End If
Range("N" & k) = d
If e1 = a1 Then
e = "a"
ElseIf e1 = b1 Then
e = "b"
ElseIf e1 = c1 Then
e = "c"
ElseIf e1 = d1 Then
e = "d"
Else
e = "e"
End If
Range("O" & k) = e
If f1 = a1 Then
f = "a"
ElseIf f1 = b1 Then
f = "b"
ElseIf f1 = c1 Then
f = "c"
ElseIf f1 = d1 Then
f = "d"
ElseIf f1 = e1 Then
f = "e"
Else
f = "f"
End If
Range("P" & k) = f
Next k
End Sub
Here is another way..
'~~> Test Data
Sub Sample()
Dim TestArray(1 To 6) As Long
Dim i As Long
TestArray(1) = 468013: TestArray(2) = 12234455: TestArray(3) = 234523
TestArray(4) = 44444444: TestArray(5) = 123: TestArray(6) = 111222
For i = 1 To 6
Debug.Print TestArray(i) & " --> " & Encrypt(TestArray(i))
Next i
End Sub
'~~> Actual Function
Function Encrypt(n As Long) As String
Dim j As Long, k As Long, sNum As String
sNum = Format(CLng(Right(n, 6)), "000000")
j = 97
For k = 1 To 6
If IsNumeric(Mid(sNum, k, 1)) Then
sNum = Replace(sNum, Mid(sNum, k, 1), Chr(j))
j = j + 1
End If
Next k
Encrypt = sNum
End Function
Output
468013 --> abcdef
12234455 --> abccdd
234523 --> abcdab
44444444 --> aaaaaa
123 --> aaabcd
111222 --> aaabbb
EDIT:
If you are planning to use it as a worksheet function and you are not sure what kind of input will be there then change
Function Encrypt(n As Long) As String
to
Function Encrypt(n As Variant) As String
I would suggest getting to know the Chr() and possibly the Asc() VBA functions along with a general knowledge of how digits and alphabetic characters translate to ASCII code characters. I may be reading things wrong but I thought I saw some contradictions between the examples, your description and the actual code provided. Here is one method putting the pattern generation into a User Defined Function or UDF.
Function num_2_alpha(sNUM As String)
'ASCII 0-9 = 46-57, a-z = 97-122
Dim tmp As String, i As Long, c As Long
sNUM = Right(sNUM, 6)
tmp = Chr(97) ' =a
For i = 2 To 6
If CBool(InStr(1, Left(sNUM, i - 1), Mid(sNUM, i, 1))) Then
tmp = tmp & Mid(tmp, InStr(1, Left(sNUM, i - 1), Mid(sNUM, i, 1)), 1)
Else
'tmp = tmp & Chr(i + 96)
c = c + 1
tmp = tmp & Chr(c + 97) 'alternate (code) method
End If
Next i
num_2_alpha = tmp
End Function
Note that I've offered an alternate method that is commented out. Either that line or the one above it should be active; never both at one time. These were the results generated.
Addendum: I believe my recent edit should help conform to the examples you left in comments. Code and image updated.