with javascript_semantics
--requires("1.0.2") -- (builtin E renamed as EULER)
--enum A,B,C,D,E,F
constant A=1, B=2, C=3, D=4, E=5, F=6 -- (or use this)
constant edges = {{A,B,7},
                  {A,C,9},
                  {A,F,14},
                  {B,C,10},
                  {B,D,15},
                  {C,D,11},
                  {C,F,2},
                  {D,E,6},
                  {E,F,9}}

sequence visited,
         cost,
         from

procedure reset()
    visited = repeat(0,6)
    cost = repeat(0,6)
    from = repeat(0,6)
end procedure

function backtrack(integer finish,start)
    sequence res = {finish}
    while finish!=start do
        finish = from[finish]
        res = prepend(res,finish)
    end while
    return res
end function

function shortest_path(integer start, integer finish)
    integer estart, eend, ecost, ncost, mincost
    while 1 do
        visited[start] = 1
        for i=1 to length(edges) do
            {estart,eend,ecost} = edges[i]
            if estart=start then
                ncost = cost[start]+ecost
                if visited[eend]=0 then
                    if from[eend]=0
                    or cost[eend]>ncost then
                        cost[eend] = ncost
                        from[eend] = start
                    end if
                elsif cost[eend]>ncost then
                    ?9/0    -- sanity check
                end if
            end if
        end for
        mincost = 0
        for i=1 to length(visited) do
            if visited[i]=0
            and from[i]!=0 then
                if mincost=0
                or cost[i]<mincost then
                    start = i
                    mincost = cost[start]
                end if
            end if
        end for
        if visited[start] then return -1 end if
        if start=finish then return cost[finish] end if
    end while
end function

function AFi(integer i)     -- output helper
    return 'A'+i-1
end function

procedure test(sequence testset)
    integer start, finish, ecost, len
    string epath, path
    for i=1 to length(testset) do
        {start,finish,ecost,epath} = testset[i]
        reset()
        len = shortest_path(start,finish)
        path = iff(len=-1?"no path found":join(apply(backtrack(finish,start),AFi),""))
        printf(1,"%c->%c: length %d:%s (expected %d:%s)\n",{AFi(start),AFi(finish),len,path,ecost,epath})
    end for
end procedure

test({{A,E,26,"ACDE"},{A,F,11,"ACF"},{F,A,-1,"none"}})


fcn sum(n,b){ n.split(b).sum(0) }
fcn droot(n,b=10,X=0) // -->(digital root, additive persistence)
   { if(n<b)return(n,X); return(self.fcn(sum(n,b),b,X+1)) }


module Main;
type
	longint = integer{64};

type {public,ref}
	Response = object (dr,p: longint)
	var {public,immutable}
		digitalRoot,persistence: longint;

	procedure {public} Writeln;
	begin
		writeln("digital root: ",digitalRoot:2," persistence: ",persistence:2)
	end Writeln;

	begin
		self.digitalRoot := dr;
		self.persistence := p;
	end Response;

	procedure DigitalRoot(n:longint):Response;
	var
		sum,p: longint;
	begin
		p := 0;
		loop
			inc(p);sum := 0;
			while (n > 0) do
				inc(sum,n mod 10);
				n := n div 10;
			end;
			if sum < 10 then return new Response(sum,p) else n := sum end
		end
	end DigitalRoot;

begin
	write(627615:22,":> ");DigitalRoot(627615).Writeln;
	write(39390:22,":> ");DigitalRoot(39390).Writeln;
	write(588225:22,":> ");DigitalRoot(588225).Writeln;
	write(max(integer{64}):22,":> ");DigitalRoot(max(integer{64})).Writeln;
end Main.


10 DATA 4,627615,39390,588225,9992
20 READ j: LET b=10
30 FOR i=1 TO j
40 READ n
50 PRINT "Digital root of ";n;" is"
60 GO SUB 1000
70 NEXT i
80 STOP
1000 REM Digital Root
1010 LET c=0
1020 IF n>=b THEN LET c=c+1: GO SUB 2000: GO TO 1020
1030 PRINT n;" persistance is ";c''
1040 RETURN
2000 REM Digit sum
2010 LET s=0
2020 IF n<>0 THEN LET q=INT (n/b): LET s=s+n-q*b: LET n=q: GO TO 2020
2030 LET n=s
2040 RETURN


(lib 'tasks)

(define names #(Aristotle Kant Spinoza Marx Russell))
(define abouts #("Wittgenstein" "the nature of the World" "Kant"  "starving"
    "spaghettis" "the essence of things" "Ω" "📞" "⚽" "🍅" "🌿"
    "philosophy" "💔"  "👠" "rosetta code" "his to-do list" ))
(define (about) (format "thinking about %a." (vector-ref abouts (random (vector-length abouts)))))

;; statistics
(define rounds (make-vector 5 0))
(define (eat i) (vector-set! rounds i (1+ (vector-ref rounds i))))

;; forks are resources = semaphores
(define (left i) i)
(define (right i) (modulo (1+ i) 5))
(define forks (for/vector ((i 5)) (make-semaphore 1)))
(define (fork i) (vector-ref forks i))

(define laquais (make-semaphore 4))

;; philosophers tasks
(define (philo i)
;; thinking
       (writeln (vector-ref names i) (about))
    (sleep (+ 2000 (random 1000)))
    (wait laquais)
;; get forks
       (writeln (vector-ref names i) 'sitting)
    (wait (fork (left i)))
    (wait (fork (right i)))
       (writeln (vector-ref names i) 'eating)
       (eat i)
       (sleep (+ 6000 (random 1000)))
;; put-forks
    (signal (fork (left i)))
    (signal (fork (right i)))
    (signal laquais)
  i)
(define tasks (for/vector ((i 5)) (make-task philo i)))


<?php
function dijkstra($graph_array, $source, $target) {
    $vertices = array();
    $neighbours = array();
    foreach ($graph_array as $edge) {
        array_push($vertices, $edge[0], $edge[1]);
        $neighbours[$edge[0]][] = array("end" => $edge[1], "cost" => $edge[2]);
        $neighbours[$edge[1]][] = array("end" => $edge[0], "cost" => $edge[2]);
    }
    $vertices = array_unique($vertices);

    foreach ($vertices as $vertex) {
        $dist[$vertex] = INF;
        $previous[$vertex] = NULL;
    }

    $dist[$source] = 0;
    $Q = $vertices;
    while (count($Q) > 0) {

        // TODO - Find faster way to get minimum
        $min = INF;
        foreach ($Q as $vertex){
            if ($dist[$vertex] < $min) {
                $min = $dist[$vertex];
                $u = $vertex;
            }
        }

        $Q = array_diff($Q, array($u));
        if ($dist[$u] == INF or $u == $target) {
            break;
        }

        if (isset($neighbours[$u])) {
            foreach ($neighbours[$u] as $arr) {
                $alt = $dist[$u] + $arr["cost"];
                if ($alt < $dist[$arr["end"]]) {
                    $dist[$arr["end"]] = $alt;
                    $previous[$arr["end"]] = $u;
                }
            }
        }
    }
    $path = array();
    $u = $target;
    while (isset($previous[$u])) {
        array_unshift($path, $u);
        $u = $previous[$u];
    }
    array_unshift($path, $u);
    return $path;
}

$graph_array = array(
                    array("a", "b", 7),
                    array("a", "c", 9),
                    array("a", "f", 14),
                    array("b", "c", 10),
                    array("b", "d", 15),
                    array("c", "d", 11),
                    array("c", "f", 2),
                    array("d", "e", 6),
                    array("e", "f", 9)
               );

$path = dijkstra($graph_array, "a", "e");

echo "path is: ".implode(", ", $path)."\n";


(de neighbor (X Y Cost)
   (push (prop X 'neighbors) (cons Y Cost))
   (push (prop Y 'neighbors) (cons X Cost)) )

(de dijkstra (Curr Dest)
   (let Cost 0
      (until (== Curr Dest)
         (let (Min T  Next)
            (for N (; Curr neighbors)
               (with (car N)
                  (let D (+ Cost (cdr N))
                     (unless (and (: distance) (>= D @))
                        (=: distance D) ) )
                  (when (> Min (: distance))
                     (setq Min (: distance)  Next This) )
                  (del (asoq Curr (: neighbors)) (:: neighbors)) ) )
            (setq Curr Next  Cost Min) ) )
      Cost ) )


class
    DINING_PHILOSOPHERS

create
    make

feature -- Initialization

    make
            -- Create philosophers and forks.
        local
            first_fork: separate FORK
            left_fork: separate FORK
            right_fork: separate FORK
            philosopher: separate PHILOSOPHER
            i: INTEGER
        do
            print ("Dining Philosophers%N" + philosopher_count.out + " philosophers, " + round_count.out + " rounds%N%N")
            create philosophers.make
            from
                i := 1
                create first_fork.make (philosopher_count, 1)
                left_fork := first_fork
            until
                i > philosopher_count
            loop
                if i < philosopher_count then
                    create right_fork.make (i, i + 1)
                else
                    right_fork := first_fork
                end
                create philosopher.make (i, left_fork, right_fork, round_count)
                philosophers.extend (philosopher)
                left_fork := right_fork
                i := i + 1
            end
            philosophers.do_all (agent launch_philosopher)
            print ("Make Done!%N")
        end

feature {NONE} -- Implementation

    philosopher_count: INTEGER = 5
            -- Number of philosophers.

    round_count: INTEGER = 30
            -- Number of times each philosopher should eat.

    philosophers: LINKED_LIST [separate PHILOSOPHER]
            -- List of philosophers.

    launch_philosopher (a_philosopher: separate PHILOSOPHER)
            -- Launch a_philosopher.
        do
            a_philosopher.live
        end

end -- class DINING_PHILOSOPHERS


from collections import namedtuple, deque
from pprint import pprint as pp

inf = float('inf')
Edge = namedtuple('Edge', ['start', 'end', 'cost'])

class Graph():
    def __init__(self, edges):
        self.edges = [Edge(*edge) for edge in edges]
        # print(dir(self.edges[0]))
        self.vertices = {e.start for e in self.edges} | {e.end for e in self.edges}

    def dijkstra(self, source, dest):
        assert source in self.vertices
        dist = {vertex: inf for vertex in self.vertices}
        previous = {vertex: None for vertex in self.vertices}
        dist[source] = 0
        q = self.vertices.copy()
        neighbours = {vertex: set() for vertex in self.vertices}
        for start, end, cost in self.edges:
            neighbours[start].add((end, cost))
            neighbours[end].add((start, cost))

        #pp(neighbours)

        while q:
            # pp(q)
            u = min(q, key=lambda vertex: dist[vertex])
            q.remove(u)
            if dist[u] == inf or u == dest:
                break
            for v, cost in neighbours[u]:
                alt = dist[u] + cost
                if alt < dist[v]:                                  # Relax (u,v,a)
                    dist[v] = alt
                    previous[v] = u
        #pp(previous)
        s, u = deque(), dest
        while previous[u]:
            s.appendleft(u)
            u = previous[u]
        s.appendleft(u)
        return s

graph = Graph([("a", "b", 7),  ("a", "c", 9),  ("a", "f", 14), ("b", "c", 10),
               ("b", "d", 15), ("c", "d", 11), ("c", "f", 2),  ("d", "e", 6),
               ("e", "f", 9)])
pp(graph.dijkstra("a", "e"))


defmodule Philosopher do

  defstruct missing: [], clean: [], promised: []

  def run_demo do
    pid1 = spawn(__MODULE__, :init, ["Russell"])
    pid2 = spawn(__MODULE__, :init, ["Marx"])
    pid3 = spawn(__MODULE__, :init, ["Spinoza"])
    pid4 = spawn(__MODULE__, :init, ["Kant"])
    pid5 = spawn(__MODULE__, :init, ["Aristotle"])

    # a chopstick is simply represented by the pid of the neighbour that shares it.

    send(pid1, {:run, %Philosopher{}})
    send(pid2, {:run, %Philosopher{missing: [pid1]}})
    send(pid3, {:run, %Philosopher{missing: [pid2]}})
    send(pid4, {:run, %Philosopher{missing: [pid3]}})
    send(pid5, {:run, %Philosopher{missing: [pid1, pid4]}})
  end

  def init(philosopher_name) do
    receive do
      {:run, state} ->
        spawn(__MODULE__, :change_state, [self()])
        case flip_coin() do
          :heads -> thinking(philosopher_name, state)
          :tails -> hungry(philosopher_name, state)
        end
    end
  end

  defp thinking(philosopher_name, state) do
    receive do
      {:change_state} ->
        hungry(philosopher_name, state)
      {:chopstick_request, pid} ->
        if clean?(pid, state) do
          thinking(philosopher_name, promise_chopstick(philosopher_name, pid, state))
        else
          give_chopstick(philosopher_name, self(), pid)
          %{missing: missing} = state
          thinking(philosopher_name, %{state | missing: [pid | missing]})
        end
    end
  end

  defp hungry(philosopher_name, state) do
    IO.puts "#{philosopher_name} is hungry."
    %{missing: missing} = state
    for pid <- missing, do: request_chopstick(philosopher_name, self(), pid)
    wait_for_chopsticks(philosopher_name, state)
  end

  defp wait_for_chopsticks(philosopher_name, state) do
    if has_chopsticks?(state) do
      eating(philosopher_name, state)
    end
    receive do
      {:chopstick_request, pid} ->
        if clean?(pid, state) do
          wait_for_chopsticks(philosopher_name, promise_chopstick(philosopher_name, pid, state))
        else
          give_chopstick(philosopher_name, self(), pid)
          request_chopstick(philosopher_name, self(), pid)
          %{missing: missing} = state
          wait_for_chopsticks(philosopher_name, %{state | missing: [pid | missing]})
        end
      {:chopstick_response, pid} ->
        %{missing: missing, clean: clean} = state
        wait_for_chopsticks(philosopher_name, %{state | missing: List.delete(missing, pid), clean: [pid | clean]})
    end
  end

  defp eating(philosopher_name, state) do
    IO.puts "*** #{philosopher_name} is eating."
    receive do
      {:change_state} ->
        %{promised: promised} = state
        for pid <- promised, do: give_chopstick(philosopher_name, self(), pid)
        thinking(philosopher_name, %Philosopher{missing: promised})
    end
  end

  defp clean?(pid, state) do
    %{clean: clean} = state
    Enum.member?(clean, pid)
  end

  defp has_chopsticks?(state) do
    %{missing: missing} = state
    Enum.empty?(missing)
  end

  defp promise_chopstick(philosopher_name, pid, state) do
    IO.puts "#{philosopher_name} promises a chopstick."
    %{promised: promised} = state
    %{state | promised: [pid | promised]}
  end

  defp request_chopstick(philosopher_name, snd_pid, recv_pid) do
    IO.puts "#{philosopher_name} requests a chopstick."
    send(recv_pid, {:chopstick_request, snd_pid})
  end

  defp give_chopstick(philosopher_name, snd_pid, recv_pid) do
    IO.puts "#{philosopher_name} gives a chopstick."
    send(recv_pid, {:chopstick_response, snd_pid})
  end

  defp flip_coin do
    case Enum.random(0..1) do
      0 -> :heads
      1 -> :tails
    end
  end

  def change_state(pid) do
    Process.sleep(Enum.random(1..10) * 1000)
    send(pid, {:change_state})
    change_state(pid)
  end


%%%
%%% to compile and run:
%%% $ erl
%%%   > c(rosetta).
%%% {ok,rosetta}
%%%   > rosetta:dining().
%%%
%%% contributor: bksteele
%%%
-module(rosetta).
-export([dining/0]).

sleep(T) ->
    receive
        after T ->
    true
    end.

doForks(ForkList) ->
    receive
        {grabforks, {Left, Right}} ->
            doForks(ForkList -- [Left, Right]);
        {releaseforks, {Left, Right}} ->
            doForks([Left, Right| ForkList]);
        {available, {Left, Right}, Sender} ->
            Sender ! {areAvailable,
                lists:member(Left, ForkList)
                andalso lists:member(Right, ForkList)},
            doForks(ForkList);
        {die} -> io:format("Forks put away.~n")
    end.

areAvailable(Forks) ->
    forks ! {available, Forks, self()},
    receive
        {areAvailable, false} -> false;
        {areAvailable, true} -> true
    end.

processWaitList([]) -> false;
processWaitList([H|T]) ->
    {Client, Forks} = H,
    case areAvailable(Forks) of
        true -> Client ! {served},
                true;
        false -> processWaitList(T)
    end.

doWaiter([], 0, 0, false) ->
    forks ! {die},
    io:format("Waiter is leaving.~n"),
    diningRoom ! {allgone};
doWaiter(WaitList, ClientCount, EatingCount, Busy) ->
    receive
        {waiting, Client} ->
            WaitList1 = [Client|WaitList],
            % add to waiting list
            case (not Busy) and (EatingCount<2) of
            true ->
                Busy1 = processWaitList(WaitList1);
            false -> Busy1 = Busy
            end,
            doWaiter(WaitList1, ClientCount, EatingCount, Busy1);

        {eating, Client} ->
          doWaiter(WaitList -- [Client], ClientCount, EatingCount+1, false);

        {finished} ->
            doWaiter(WaitList, ClientCount, EatingCount-1,
            processWaitList(WaitList));
        {leaving} ->
            doWaiter(WaitList, ClientCount-1, EatingCount, Busy)
    end.

philosopher(Name, _Forks, 0) ->
    io:format("~s is leaving.~n", [Name]),
    waiter ! {leaving};
philosopher(Name, Forks, Cycle) ->
    io:format("~s is thinking.~n", [Name]),
    sleep(rand:uniform(1000)),
    io:format("~s is hungry.~n", [Name]),
    % sit at table
    waiter ! {waiting, {self(), Forks}},

    receive
        {served} -> forks ! {grabforks, Forks},
            % grab forks
            waiter ! {eating, {self(), Forks}},
            % start eating
            io:format("~s is eating.~n", [Name])
    end,

    sleep(rand:uniform(1000)),
    % put forks down
    forks ! {releaseforks, Forks},
    waiter ! {finished},

    philosopher(Name, Forks, Cycle-1).

dining() ->    AllForks = [1, 2, 3, 4, 5],
    Clients = 5,
    register(diningRoom, self()),

    register(forks,
        spawn(fun() -> doForks(AllForks) end)),
    register(waiter,
        spawn(fun() -> doWaiter([], Clients, 0, false) end)),
    % run for 7 cycles
    Life_span = 7,
    spawn(fun() -> philosopher('Aristotle', {5, 1}, Life_span) end),
    spawn(fun() -> philosopher('Kant', {1, 2}, Life_span) end),
    spawn(fun() -> philosopher('Spinoza', {2, 3}, Life_span) end),
    spawn(fun() -> philosopher('Marx', {3, 4}, Life_span) end),
    spawn(fun() -> philosopher('Russell', {4, 5}, Life_span) end),

    receive
        {allgone} -> io:format("Dining room closed.~n")

    end,
    unregister(diningRoom).


#lang racket
(require (planet jaymccarthy/dijkstra:1:2))

(define edges
  '([a . ((b 7)(c 9)(f 14))]
    [b . ((c 10)(d 15))]
    [c . ((d 11)(f 2))]
    [d . ((e 6))]
    [e . ((f 9))]))

(define (node-edges n)
  (cond [(assoc n edges) => rest] ['()]))
(define edge-weight second)
(define edge-end first)

(match/values (shortest-path node-edges edge-weight edge-end 'a (λ(n) (eq? n 'e)))
 [(dists prevs)
  (displayln (~a "Distances from a: " (for/list ([(n d) dists]) (list n d))))
  (displayln (~a "Shortest path: "
             (let loop ([path '(e)])
               (cond [(eq? (first path) 'a) path]
                     [(loop (cons (hash-ref prevs (first path)) path))]))))])


class Graph {
  has (%.edges, %.nodes);

  method new(*@args){
    my (%edges, %nodes);
    for @args {
      %edges{.[0] ~ .[1]} = $_;
      %nodes{.[0]}.push( .[0] ~ .[1] );
      %nodes{.[1]}.push( .[0] ~ .[1] );
    }
    self.bless(edges => %edges, nodes => %nodes);
  }

  method neighbours ($source) {
    my (%neighbours, $edges);
    $edges = self.nodes{$source};
    for @$edges -> $x {
      for self.edges{$x}[0..1] -> $y {
        if $y ne $source {
          %neighbours{$y} = self.edges{$x}
        }
      }
    }
    return %neighbours
  }

  method dijkstra ($source, $dest) {
    my (%node_data, $v, $u);
    my @q = self.nodes.keys;

    for self.nodes.keys {
      %node_data{$_}{'dist'} = Inf;
      %node_data{$_}{'prev'} = '';
    }
    %node_data{$source}{'dist'} = 0;

    while @q {
      # %node_data.perl.say;
      my ($mindist, $idx) =
        @((map {[%node_data{@q[$_]}{'dist'},$_]},^@q).min(*[0]));
      $u = @q[$idx];

      if $mindist eq Inf {
        return ()
      }
      elsif $u eq $dest {
        my @s;
        while %node_data{$u}{'prev'} {
          @s.unshift($u);
          $u = %node_data{$u}{'prev'}
        }
        @s.unshift($source);
        return @s;
      }
      else {
        @q.splice($idx,1);
      }

      for self.neighbours($u).kv -> $v, $edge {
        my $alt = %node_data{$u}{'dist'} + $edge[2];
        if $alt < %node_data{$v}{'dist'} {
          %node_data{$v}{'dist'} = $alt;
          %node_data{$v}{'prev'} = $u
        }
      }
    }
  }
}

my $a = Graph.new([
  ["a", "b",  7],
  ["a", "c",  9],
  ["a", "f", 14],
  ["b", "c", 10],
  ["b", "d", 15],
  ["c", "d", 11],
  ["c", "f",  2],
  ["d", "e",  6],
  ["e", "f",  9]
]).dijkstra('a', 'e').say;


constant FREE = 0, LOCKED = 1
sequence forks
forks = repeat(FREE,5)

procedure person(sequence name, integer left_fork, integer right_fork)
    while 1 do
        while forks[left_fork] = LOCKED or forks[right_fork] = LOCKED do
            if forks[left_fork] = FREE then
                puts(1, name & " hasn't right fork.\n")
            elsif forks[right_fork] = FREE then
                puts(1, name & " hasn't left fork.\n")
            else
                puts(1, name & " hasn't both forks.\n")
            end if
            puts(1, name & " is waiting.\n")
            task_yield()
        end while

        puts(1, name & " grabs forks.\n")
        forks[left_fork] = LOCKED
        forks[right_fork] = LOCKED
        for i = 1 to rand(10) do
            puts(1, name & " is eating.\n")
            task_yield()
        end for
        puts(1, name & " puts forks down and leaves the dinning room.\n")
        forks[left_fork] = FREE
        forks[right_fork] = FREE

        for i = 1 to rand(10) do
            puts(1, name & " is thinking.\n")
            task_yield()
        end for
        puts(1, name & " becomes hungry.\n")
    end while
end procedure

integer rid
atom taskid
rid = routine_id("person")
taskid = task_create(rid,{"Aristotle",1,2})
task_schedule(taskid,{1,2})
taskid = task_create(rid,{"Kant",2,3})
task_schedule(taskid,{1,2})
taskid = task_create(rid,{"Spinoza",3,4})
task_schedule(taskid,{1,2})
taskid = task_create(rid,{"Marx",4,5})
task_schedule(taskid,{1,2})
taskid = task_create(rid,{"Russell",5,1})
task_schedule(taskid,{1,2})

while get_key() = -1 do
    task_yield()
end while


/*REXX program determines the  least costly path  between  two vertices  given a list.  */
$.= copies(9, digits() )                         /*edge cost:  indicates doesn't exist. */
xList= '!. @. $. beg fin bestP best$ xx yy'      /*common  EXPOSEd  variables for subs. */
@abc=  'abcdefghijklmnopqrstuvwxyz'              /*list of all the possible vertices.   */
verts= 0;  edges= 0                              /*the number of vertices and also edges*/
                      do #=1  for length(@abc);              _= substr(@abc, #, 1)
                      call value translate(_), #;      @@.#= _
                      end   /*#*/
call def$  a  b   7                              /*define an  edge  and  its  cost.     */
call def$  a  c   9                              /*   "    "    "    "    "     "       */
call def$  a  f  14                              /*   "    "    "    "    "     "       */
call def$  b  c  10                              /*   "    "    "    "    "     "       */
call def$  b  d  15                              /*   "    "    "    "    "     "       */
call def$  c  d  11                              /*   "    "    "    "    "     "       */
call def$  c  f   2                              /*   "    "    "    "    "     "       */
call def$  d  e   6                              /*   "    "    "    "    "     "       */
call def$  e  f   9                              /*   "    "    "    "    "     "       */
beg= a;    fin= e                                /*the  BEGin  and  FINish  vertexes.   */
say;       say 'number of    edges = '   edges
           say 'number of vertices = '   verts                 "    ["left(@abc, verts)"]"
best$= $.;    bestP=
say;                         do jv=2  to verts;    call paths verts, jv;       end  /*jv*/
@costIs= right('cost =', 16)
if bestP==$.  then say 'no path found.'
              else say 'best path ='   translate(bestP, @abc, 123456789)   @costIs   best$
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
apath: parse arg pathx 1 p1 2 p2 3;             Lp= length(pathx);              $= $.p1.p2
       if $>=best$  then return
       pv= p2;                      do ka=3  to Lp;   _= substr(pathx, ka, 1)
                                    if $.pv._>=best$  then return
                                    $= $ + $.pv._;    if $>=best$  then return;      pv= _
                                    end   /*ka*/
       best$= $;    bestP= pathx
       return
/*──────────────────────────────────────────────────────────────────────────────────────*/
def$:  parse arg xx yy $ .;         if $.xx.yy<$  &  $.yy.xx<$  |  xx==yy  then return
       edges= edges + 1;            verts= verts  +  ($.xx\==0)  +  ($.yy\==0)
       $.xx= 0;        $.yy= 0;     $.xx.yy= $
       say left('', 40)     "cost of    "     @@.xx     '───►'     @@.yy     "   is "    $
       return
/*──────────────────────────────────────────────────────────────────────────────────────*/
paths: procedure expose (xList);    parse arg xx, yy, @.
                     do kp=1  for xx;     _= kp;   !.kp= _;   end   /*build a path list.*/
       call .path 1
       return
/*──────────────────────────────────────────────────────────────────────────────────────*/
.path: procedure expose (xList);    parse arg ?, _
       if ?>yy  then do;            if @.1\==beg | @.yy\==fin  then return
                       do #=1  for yy;  _= _ || @.#;  end  /*#*/;             call apath _
                     end
                else do qq=1  for xx                    /*build vertex paths recursively*/
                       do kp=1  for ?-1;  if @.kp==!.qq  then iterate qq;  end  /*kp*/
                     @.?= !.qq;     call .path ?+1      /*recursive call for next path. */
                     end   /*qq*/
       return


open System

let flip f x y = f y x

let rec cycle s = seq { yield! s; yield! cycle s }

type Agent<'T> = MailboxProcessor<'T>

type Message = Waiting of (Set<int> * AsyncReplyChannel<unit>) | Done of Set<int>

let reply (c: AsyncReplyChannel<_>) = c.Reply()

let strategy forks waiting =
    let aux, waiting = List.partition (fst >> flip Set.isSubset forks) waiting
    let forks = aux |> List.map fst |> List.fold (-) forks
    List.iter (snd >> reply) aux
    forks, waiting

let waiter strategy forkCount =
  Agent<_>.Start(fun inbox ->
    let rec loop forks waiting =
      async { let forks, waiting = strategy forks waiting
              let! msg = inbox.Receive()
              match msg with
                | Waiting r -> return! loop forks (waiting @ [r])
                | Done f -> return! loop (forks + f) waiting }
    loop (Set.ofList (List.init forkCount id)) [])

let philosopher (waiter: Agent<_>) name forks =
  let rng = new Random()
  let forks = Set.ofArray forks
  Agent<_>.Start(fun inbox ->
    let rec loop () =
      async { printfn "%s is thinking" name
              do! Async.Sleep(rng.Next(100, 500))
              printfn "%s is hungry" name
              do! waiter.PostAndAsyncReply(fun c -> Waiting (forks, c))
              printfn "%s is eating" name
              do! Async.Sleep(rng.Next(100, 500))
              printfn "%s is done eating" name
              waiter.Post(Done (forks))
              return! loop () }
    loop ())

[<EntryPoint>]
let main args =
  let forks = Seq.init 5 id |> cycle |> Seq.windowed 2 |> Seq.take 5 |> Seq.toList
  let names = ["plato"; "aristotel"; "kant"; "nietzsche"; "russel"]
  let waiter = waiter strategy 5
  List.map2 (philosopher waiter) names forks |> ignore
  Console.ReadLine() |> ignore
  0


# Project : Dijkstra's algorithm

graph = [["a", "b", 7],
              ["a", "c", 9],
              ["a", "f", 14],
              ["b", "c", 10],
              ["b", "d", 15],
              ["c", "d", 11],
              ["c", "f", 2],
              ["d", "e", 6],
              ["e", "f", 9]]

dbegin = "a"
dend = "e"
powlen = pow(2,len(graph)) - 1
dgraph = list(powlen)
dtemp = list(powlen)
lenold = 10
lennew = 0
sumold = 30
sumnew = 0

powerset(graph)

for n = 1 to len(dgraph)
      dtemp[n] = str2list(substr(dgraph[n], " ", nl))
next

for n = 1 to len(dtemp)
     if len(dtemp[n]) > 3 and dtemp[n][1] = dbegin  and dtemp[n][len(dtemp[n])-1] = dend
        flag = 1
        for m = 1 to len(dtemp[n])/3-1
              if dtemp[n][m*3-1] != dtemp[n][m*3+1]
                 flag = 0
              ok
        next
        if flag = 1
           lennew = len(dtemp[n])
           if lennew <= lenold
              lenold = lennew
              sumnew = 0
              for m = 1 to len(dtemp[n])/3
                    sumnew = sumnew + dtemp[n][m*3]
              next
              if sumnew < sumold
                 sumold = sumnew
                 gend = dtemp[n]
              ok
           ok
        ok
     ok
next
str = ""
see dbegin + " " + dend + " : "
for m = 1 to len(gend)/3
     str = str + gend[(m-1)*3 + 1] + " " + gend[(m-1)*3 + 2] + " " + gend[(m-1)*3 + 3] + " -> "
next
str = left(str,len(str)-4)
str = str + " cost : " + sumold + nl
see str + nl

func powerset(list)
        s = "{"
        p = 0
        for i = 2 to (2 << len(list)) - 1 step 2
             s = ""
             for j = 1 to len(list)
                  if i & (1 << j)
                     s = s + list[j][1] + " " + list[j][2] + " " + list[j][3] + " "
                  ok
             next
             if right(s,1) = " "
                s = left(s,len(s)-1)
             ok
             p = p + 1
             dgraph[p] = s
        next


class Graph
  Vertex = Struct.new(:name, :neighbours, :dist, :prev)

  def initialize(graph)
    @vertices = Hash.new{|h,k| h[k]=Vertex.new(k,[],Float::INFINITY)}
    @edges = {}
    graph.each do |(v1, v2, dist)|
      @vertices[v1].neighbours << v2
      @vertices[v2].neighbours << v1
      @edges[[v1, v2]] = @edges[[v2, v1]] = dist
    end
    @dijkstra_source = nil
  end

  def dijkstra(source)
    return  if @dijkstra_source == source
    q = @vertices.values
    q.each do |v|
      v.dist = Float::INFINITY
      v.prev = nil
    end
    @vertices[source].dist = 0
    until q.empty?
      u = q.min_by {|vertex| vertex.dist}
      break if u.dist == Float::INFINITY
      q.delete(u)
      u.neighbours.each do |v|
        vv = @vertices[v]
        if q.include?(vv)
          alt = u.dist + @edges[[u.name, v]]
          if alt < vv.dist
            vv.dist = alt
            vv.prev = u.name
          end
        end
      end
    end
    @dijkstra_source = source
  end

  def shortest_path(source, target)
    dijkstra(source)
    path = []
    u = target
    while u
      path.unshift(u)
      u = @vertices[u].prev
    end
    return path, @vertices[target].dist
  end

  def to_s
    "#<%s vertices=%p edges=%p>" % [self.class.name, @vertices.values, @edges]
  end
end

g = Graph.new([ [:a, :b, 7],
                [:a, :c, 9],
                [:a, :f, 14],
                [:b, :c, 10],
                [:b, :d, 15],
                [:c, :d, 11],
                [:c, :f, 2],
                [:d, :e, 6],
                [:e, :f, 9],
              ])

start, stop = :a, :e
path, dist = g.shortest_path(start, stop)
puts "shortest path from #{start} to #{stop} has cost #{dist}:"
puts path.join(" -> ")


package main

import (
    "hash/fnv"
    "log"
    "math/rand"
    "os"
    "time"
)

// Number of philosophers is simply the length of this list.
// It is not otherwise fixed in the program.
var ph = []string{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"}

const hunger = 3                // number of times each philosopher eats
const think = time.Second / 100 // mean think time
const eat = time.Second / 100   // mean eat time

var fmt = log.New(os.Stdout, "", 0) // for thread-safe output

var done = make(chan bool)

// This solution uses channels to implement synchronization.
// Sent over channels are "forks."
type fork byte

// A fork object in the program models a physical fork in the simulation.
// A separate channel represents each fork place.  Two philosophers
// have access to each fork.  The channels are buffered with capacity = 1,
// representing a place for a single fork.

// Goroutine for philosopher actions.  An instance is run for each
// philosopher.  Instances run concurrently.
func philosopher(phName string,
    dominantHand, otherHand chan fork, done chan bool) {
    fmt.Println(phName, "seated")
    // each philosopher goroutine has a random number generator,
    // seeded with a hash of the philosopher's name.
    h := fnv.New64a()
    h.Write([]byte(phName))
    rg := rand.New(rand.NewSource(int64(h.Sum64())))
    // utility function to sleep for a randomized nominal time
    rSleep := func(t time.Duration) {
        time.Sleep(t/2 + time.Duration(rg.Int63n(int64(t))))
    }
    for h := hunger; h > 0; h-- {
        fmt.Println(phName, "hungry")
        <-dominantHand // pick up forks
        <-otherHand
        fmt.Println(phName, "eating")
        rSleep(eat)
        dominantHand <- 'f' // put down forks
        otherHand <- 'f'
        fmt.Println(phName, "thinking")
        rSleep(think)
    }
    fmt.Println(phName, "satisfied")
    done <- true
    fmt.Println(phName, "left the table")
}

func main() {
    fmt.Println("table empty")
    // Create fork channels and start philosopher goroutines,
    // supplying each goroutine with the appropriate channels
    place0 := make(chan fork, 1)
    place0 <- 'f' // byte in channel represents a fork on the table.
    placeLeft := place0
    for i := 1; i < len(ph); i++ {
        placeRight := make(chan fork, 1)
        placeRight <- 'f'
        go philosopher(ph[i], placeLeft, placeRight, done)
        placeLeft = placeRight
    }
    // Make one philosopher left handed by reversing fork place
    // supplied to philosopher's dominant hand.
    // This makes precedence acyclic, preventing deadlock.
    go philosopher(ph[0], place0, placeLeft, done)
    // they are all now busy eating
    for range ph {
        <-done // wait for philosphers to finish
    }
    fmt.Println("table empty")
}


use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::usize;

struct Grid<T> {
    nodes: Vec<Node<T>>,
}

struct Node<T> {
    data: T,
    edges: Vec<(usize,usize)>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
struct State {
    node: usize,
    cost: usize,
}

// Manually implement Ord so we get a min-heap instead of a max-heap
impl Ord for State {
    fn cmp(&self, other: &Self) -> Ordering {
        other.cost.cmp(&self.cost)
    }
}

impl PartialOrd for State {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

type WeightedEdge = (usize, usize, usize);

impl<T> Grid<T> {
    fn new() -> Self {
        Grid { nodes: Vec::new() }
    }

    fn add_node(&mut self, data: T) -> usize {
        let node = Node {
            edges: Vec::new(),
            data: data,
        };
        self.nodes.push(node);
        self.nodes.len() - 1
    }

    fn create_edges<'a, I>(&mut self, iterator: I) where I: IntoIterator<Item=&'a WeightedEdge> {
        for &(start,end,weight) in iterator.into_iter() {
            self.nodes[start].edges.push((end,weight));
            self.nodes[end].edges.push((start,weight));
        }

    }

    fn find_path(&self, start: usize, end: usize) -> Option<(Vec<usize>, usize)> {
        let mut dist = vec![(usize::MAX, None); self.nodes.len()];

        let mut heap = BinaryHeap::new();
        dist[start] = (0, None);
        heap.push(State {
            node: start,
            cost: 0,
        });

        while let Some(State { node, cost }) = heap.pop() {
            if node == end {
                let mut path = Vec::with_capacity(dist.len() / 2);
                let mut current_dist = dist[end];
                path.push(end);
                while let Some(prev) = current_dist.1 {
                    path.push(prev);
                    current_dist = dist[prev];
                }
                path.reverse();
                return Some((path, cost));
            }

            if cost > dist[node].0 {
                continue;
            }
            for edge in &self.nodes[node].edges {
                let next = State {
                    node: edge.0,
                    cost: cost + edge.1,
                };
                if next.cost < dist[next.node].0 {
                    dist[next.node] = (next.cost, Some(node));
                    heap.push(next);
                }
            }
        }
        None
    }
}

fn main() {
    let mut grid = Grid::new();
    let (a,b,c,d,e,f) = (grid.add_node("a"), grid.add_node("b"),
                         grid.add_node("c"), grid.add_node("d"),
                         grid.add_node("e"), grid.add_node("f"));

    grid.create_edges(&[
        (a,b,7) ,(a,c,9) ,(a,f,14),
        (b,c,10),(b,d,15),(c,d,11),
        (c,f,2) ,(d,e,6) ,(e,f,9) ,
    ]);

    let (path, cost) = grid.find_path(a,e).unwrap();

    print!("{}", grid.nodes[path[0]].data);
    for i in path.iter().skip(1) {
        print!(" -> {}", grid.nodes[*i].data);
    }
    println!("\nCost: {}", cost);

}


/* create SAS data set */
data Edges;
   input Start $ End $ Cost;
   datalines;
a  b  7
a  c  9
a  f  14
b  c  10
b  d  15
c  d  11
c  f  2
d  e  6
e  f  9
;

/* call OPTMODEL procedure in SAS/OR */
proc optmodel;
   /* declare sets and parameters, and read input data */
   set <str,str> LINKS;
   num cost {LINKS};
   read data Edges into LINKS=[start end] cost;
   set NODES = union {<i,j> in LINKS} {i,j};
   set SOURCES = {'a'};
   set SINKS = {'e'};
   /* <source,sink,order,from,to> */
   set <str,str,num,str,str> PATHS;

   /* call network solver */
   solve with network /
      shortpath=(source=SOURCES sink=SINKS) links=(weight=cost) out=(sppaths=PATHS);

   /* write shortest path to SAS data set */
   create data path from [source sink order from to]=PATHS cost[from,to];
quit;

/* print shortest path */
proc print data=path;
run;


import groovy.transform.Canonical

import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock

@Canonical
class Fork {
    String name
    Lock lock = new ReentrantLock()

    void pickUp(String philosopher) {
        lock.lock()
        println "  $philosopher picked up $name"
    }

    void putDown(String philosopher) {
        lock.unlock()
        println "  $philosopher put down $name"
    }
}

@Canonical
class Philosopher extends Thread {
    Fork f1
    Fork f2

    @Override
    void run() {
        def random = new Random()
        (1..20).each { bite ->
            println "$name is hungry"
            f1.pickUp name
            f2.pickUp name
            println "$name is eating bite $bite"
            Thread.sleep random.nextInt(300) + 100
            f2.putDown name
            f1.putDown name
        }
    }
}

void diningPhilosophers(names) {
    def forks = (1..names.size()).collect { new Fork(name: "Fork $it") }
    def philosophers = []
    names.eachWithIndex{ n, i ->
        def (i1, i2) = [i, (i + 1) % 5]
        if (i2 < i1) (i1, i2) = [i2, i]

        def p = new Philosopher(name: n, f1: forks[i1], f2: forks[i2])
        p.start()
        philosophers << p
    }
    philosophers.each { it.join() }
}

diningPhilosophers(['Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell'])


object Dijkstra {

  type Path[Key] = (Double, List[Key])

  def Dijkstra[Key](lookup: Map[Key, List[(Double, Key)]], fringe: List[Path[Key]], dest: Key, visited: Set[Key]): Path[Key] = fringe match {
    case (dist, path) :: fringe_rest => path match {case key :: path_rest =>
      if (key == dest) (dist, path.reverse)
      else {
        val paths = lookup(key).flatMap {case (d, key) => if (!visited.contains(key)) List((dist + d, key :: path)) else Nil}
        val sorted_fringe = (paths ++ fringe_rest).sortWith {case ((d1, _), (d2, _)) => d1 < d2}
        Dijkstra(lookup, sorted_fringe, dest, visited + key)
      }
    }
    case Nil => (0, List())
  }

  def main(x: Array[String]): Unit = {
    val lookup = Map(
      "a" -> List((7.0, "b"), (9.0, "c"), (14.0, "f")),
      "b" -> List((10.0, "c"), (15.0, "d")),
      "c" -> List((11.0, "d"), (2.0, "f")),
      "d" -> List((6.0, "e")),
      "e" -> List((9.0, "f")),
      "f" -> Nil
    )
    val res = Dijkstra[String](lookup, List((0, List("a"))), "e", Set())
    println(res)
  }
}


module Philosophers where

import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import System.Random

-- TMVars are transactional references. They can only be used in transactional actions.
-- They are either empty or contain one value. Taking an empty reference fails and
-- putting a value in a full reference fails. A transactional action only succeeds
-- when all the component actions succeed, else it rolls back and retries until it
-- succeeds.
-- The Int is just for display purposes.
type Fork = TMVar Int

newFork :: Int -> IO Fork
newFork i = newTMVarIO i

-- The basic transactional operations on forks
takeFork :: Fork -> STM Int
takeFork fork = takeTMVar fork

releaseFork :: Int -> Fork -> STM ()
releaseFork i fork = putTMVar fork i

type Name = String

runPhilosopher :: Name -> (Fork, Fork) -> IO ()
runPhilosopher name (left, right) = forever $ do
  putStrLn (name ++ " is hungry.")

  -- Run the transactional action atomically.
  -- The type system ensures this is the only way to run transactional actions.
  (leftNum, rightNum) <- atomically $ do
    leftNum <- takeFork left
    rightNum <- takeFork right
    return (leftNum, rightNum)

  putStrLn (name ++ " got forks " ++ show leftNum ++ " and " ++ show rightNum ++ " and is now eating.")
  delay <- randomRIO (1,10)
  threadDelay (delay * 1000000) -- 1, 10 seconds. threadDelay uses nanoseconds.
  putStrLn (name ++ " is done eating. Going back to thinking.")

  atomically $ do
    releaseFork leftNum left
    releaseFork rightNum right

  delay <- randomRIO (1, 10)
  threadDelay (delay * 1000000)

philosophers :: [String]
philosophers = ["Aristotle", "Kant", "Spinoza", "Marx", "Russel"]

main = do
  forks <- mapM newFork [1..5]
  let namedPhilosophers  = map runPhilosopher philosophers
      forkPairs          = zip forks (tail . cycle $ forks)
      philosophersWithForks = zipWith ($) namedPhilosophers forkPairs

  putStrLn "Running the philosophers. Press enter to quit."

  mapM_ forkIO philosophersWithForks

  -- All threads exit when the main thread exits.
  getLine


class Graph(*args) {

    struct Node {
        String name,
        Array edges = [],
        Number dist = Inf,
        prev = nil,
        Bool visited = false,
    }

    struct Edge {
        Number weight,
        Node vertex,
    }

    has g = Hash()

    method init {
        args.each { |a|
            self.add_edge(a...)
        }
    }

    method get(name) {
        g{name}
    }

    method add_edge(a, b, weight) {
        g{a} ||= Node(name: a)
        g{b} ||= Node(name: b)
        g{a}.edges << Edge(weight, g{b})
    }

    method push_priority(a, v) {
        var i = 0
        var j = a.end
        while (i <= j) {
            var k = ((i + j) // 2)
            if (a[k].dist >= v.dist) {
                j = k-1
            }
            else {
                i = k+1
            }
        }
        a.insert(i, v)
    }

    method dijkstra(a, b) {
        g{a}.dist = 0
        var h = []
        self.push_priority(h, g{a})
        while (!h.is_empty) {
            var v = h.shift
            break if (v.name == b)
            v.visited = true
            v.edges.each { |e|
                var u = e.vertex
                if (!u.visited && (v.dist+e.weight <= u.dist)) {
                    u.prev = v
                    u.dist = (v.dist + e.weight)
                    self.push_priority(h, u)
                }
            }
        }
    }
}

var g = Graph(
    ["a", "b", 7],
    ["a", "c", 9],
    ["a", "f", 14],
    ["b", "c", 10],
    ["b", "d", 15],
    ["c", "d", 11],
    ["c", "f", 2],
    ["d", "e", 6],
    ["e", "f", 9],
)

g.dijkstra('a', 'e')

var v = g.get('e')
var a = []
while (v != nil) {
    a << v.name
    v = v.prev
}

var path = a.reverse.join
say "#{g.get('e').dist} #{path}"


global forks, names

procedure main(A)
    names := ["Aristotle","Kant","Spinoza","Marks","Russell"]
    write("^C to terminate")
    nP := *names
    forks := [: |mutex([])\nP :]
    every p := !nP do thread philosopher(p)
    delay(-1)
end

procedure philosopher(n)
    f1 := forks[min(n, n%*forks+1)]
    f2 := forks[max(n, n%*forks+1)]
    repeat {
        write(names[n]," thinking")
        delay(1000*?5)
        write(names[n]," hungry")
        repeat {
            fork1 := lock(f1)
            if fork2 := trylock(f2) then {
                write(names[n]," eating")
                delay(1000*?5)
                break (unlock(fork2), unlock(fork1))  # full
                }
            unlock(fork1)  # Free first fork and go back to waiting
            }
        }
end


typealias WeightedEdge = (Int, Int, Int)

struct Grid<T> {
  var nodes: [Node<T>]

  mutating func addNode(data: T) -> Int {
    nodes.append(Node(data: data, edges: []))

    return nodes.count - 1
  }

  mutating func createEdges(weights: [WeightedEdge]) {
    for (start, end, weight) in weights {
      nodes[start].edges.append((end, weight))
      nodes[end].edges.append((start, weight))
    }
  }

  func findPath(start: Int, end: Int) -> ([Int], Int)? {
    var dist = Array(repeating: (Int.max, nil as Int?), count: nodes.count)
    var heap = Heap<State>(sort: { $0.cost < $1.cost })

    dist[start] = (0, nil)
    heap.insert(State(node: start, cost: 0))

    while let state = heap.remove(at: 0) {
      if state.node == end {
        var path = [end]
        var currentDist = dist[end]

        while let prev = currentDist.1 {
          path.append(prev)
          currentDist = dist[prev]
        }

        return (path.reversed(), state.cost)
      }

      guard state.cost <= dist[state.node].0 else {
        continue
      }

      for edge in nodes[state.node].edges {
        let next = State(node: edge.0, cost: state.cost + edge.1)

        if next.cost < dist[next.node].0 {
          dist[next.node] = (next.cost, state.node)
          heap.insert(next)
        }
      }
    }

    return nil
  }
}

struct Node<T> {
  var data: T
  var edges: [(Int, Int)]
}

struct State {
  var node: Int
  var cost: Int
}

var grid = Grid<String>(nodes: [])

let (a, b, c, d, e, f) = (
  grid.addNode(data: "a"),
  grid.addNode(data: "b"),
  grid.addNode(data: "c"),
  grid.addNode(data: "d"),
  grid.addNode(data: "e"),
  grid.addNode(data: "f")
)

grid.createEdges(weights: [
  (a, b, 7), (a, c, 9), (a, f, 14),
  (b, c, 10), (b, d, 15), (c, d, 11),
  (c, f, 2), (d, e, 6), (e, f, 9)
])

guard let (path, cost) = grid.findPath(start: a, end: e) else {
  fatalError("Could not find path")
}

print("Cost: \(cost)")
print(path.map({ grid.nodes[$0].data }).joined(separator: " -> "))


data vertex <'a'..'f'>, to <vertex>

templates shortestPaths&{graph:}
  @: [];
  [ {to: $, distance: 0"1", path:[]} ] -> #
  when <[](0)> do [email protected] !
  otherwise
    def closest: $ ... -> ..=Min&{by: :(distance:), select: :()};
    $closest -> ..|@: $;
    def path: [ $closest.path..., $closest.to ];
    [ $... -> \(<?($.to <~=$closest.to>)> $!\),
      $graph... -> \(<?($.edge(1) <=$closest.to>) ?([email protected] <~[<{to: <=$.edge(2)>}>]>)> $!\)
        -> { to: $.edge(2), distance: $.cost + $closest.distance, path: $path} ] -> #
end shortestPaths

def edges: [
  { edge: [vertex´'a', vertex´'b'], cost: 7"1" },
  { edge: [vertex´'a', vertex´'c'], cost: 9"1" },
  { edge: [vertex´'a', vertex´'f'], cost: 14"1" },
  { edge: [vertex´'b', vertex´'c'], cost: 10"1" },
  { edge: [vertex´'b', vertex´'d'], cost: 15"1" },
  { edge: [vertex´'c', vertex´'d'], cost: 11"1" },
  { edge: [vertex´'c', vertex´'f'], cost: 2"1" },
  { edge: [vertex´'d', vertex´'e'], cost: 6"1" },
  { edge: [vertex´'e', vertex´'f'], cost: 9"1" }];

def fromA: vertex´'a' -> shortestPaths&{graph: $edges};

$fromA... -> \(<{to:<=vertex´'e'>}> $!\) -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
' -> !OUT::write

$fromA... -> \(<{to:<=vertex´'f'>}> $!\) -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
' -> !OUT::write


proc dijkstra {graph origin} {
    # Initialize
    dict for {vertex distmap} $graph {
	dict set dist $vertex Inf
	dict set path $vertex {}
    }
    dict set dist $origin 0
    dict set path $origin [list $origin]

    while {[dict size $graph]} {
	# Find unhandled node with least weight
	set d Inf
	dict for {uu -} $graph {
	    if {$d > [set dd [dict get $dist $uu]]} {
		set u $uu
		set d $dd
	    }
	}

	# No such node; graph must be disconnected
	if {$d == Inf} break

	# Update the weights for nodes lead to by the node we've picked
	dict for {v dd} [dict get $graph $u] {
	    if {[dict exists $graph $v]} {
		set alt [expr {$d + $dd}]
		if {$alt < [dict get $dist $v]} {
		    dict set dist $v $alt
		    dict set path $v [list {*}[dict get $path $u] $v]
		}
	    }
	}

	# Remove chosen node from graph still to be handled
	dict unset graph $u
    }
    return [list $dist $path]
}


Class Branch
Public from As Node '[according to Dijkstra the first Node should be closest to P]
Public towards As Node
Public length As Integer '[directed length!]
Public distance As Integer '[from P to farthest node]
Public key As String
Class Node
Public key As String
Public correspondingBranch As Branch
Const INFINITY = 32767
Private Sub Dijkstra(Nodes As Collection, Branches As Collection, P As Node, Optional Q As Node)
    'Dijkstra, E. W. (1959). "A note on two problems in connexion with graphs".
    'Numerische Mathematik. 1: 269–271. doi:10.1007/BF01386390.
    'http://www-m3.ma.tum.de/twiki/pub/MN0506/WebHome/dijkstra.pdf
    'Problem 2. Find the path of minimum total length between two given nodes
    'P and Q.
    'We use the fact that, if R is a node on the minimal path from P to Q, knowledge
    'of the latter implies the knowledge of the minimal path from P to A. In the
    'solution presented, the minimal paths from P to the other nodes are constructed
    'in order of increasing length until Q is reached.
    'In the course of the solution the nodes are subdivided into three sets:
    'A. the nodes for which the path of minimum length from P is known; nodes
    'will be added to this set in order of increasing minimum path length from node P;
    '[comments in square brackets are not by Dijkstra]
    Dim a As New Collection '[of nodes (vertices)]
    'B. the nodes from which the next node to be added to set A will be selected;
    'this set comprises all those nodes that are connected to at least one node of
    'set A but do not yet belong to A themselves;
    Dim b As New Collection '[of nodes (vertices)]
    'C. the remaining nodes.
    Dim c As New Collection '[of nodes (vertices)]
    'The Branches are also subdivided into three sets:
    'I the Branches occurring in the minimal paths from node P to the nodes
    'in set A;
    Dim I As New Collection '[of Branches (edges)]
    'II the Branches from which the next branch to be placed in set I will be
    'selected; one and only one branch of this set will lead to each node in set B;
    Dim II As New Collection '[of Branches (edges)]
    'III. the remaining Branches (rejected or not yet considered).
    Dim III As New Collection '[of Branches (edges)]
    Dim u As Node, R_ As Node, dist As Integer
    'To start with, all nodes are in set C and all Branches are in set III. We now
    'transfer node P to set A and from then onwards repeatedly perform the following
    'steps.
    For Each n In Nodes
        c.Add n, n.key
    Next n
    For Each e In Branches
        III.Add e, e.key
    Next e
    a.Add P, P.key
    c.Remove P.key
    Set u = P
    Do
        'Step 1. Consider all Branches r connecting the node just transferred to set A
        'with nodes R in sets B or C. If node R belongs to set B, we investigate whether
        'the use of branch r gives rise to a shorter path from P to R than the known
        'path that uses the corresponding branch in set II. If this is not so, branch r is
        'rejected; if, however, use of branch r results in a shorter connexion between P
        'and R than hitherto obtained, it replaces the corresponding branch in set II
        'and the latter is rejected. If the node R belongs to set C, it is added to set B and
        'branch r is added to set II.
        For Each r In III
            If r.from Is u Then
                Set R_ = r.towards
                If Belongs(R_, c) Then
                    c.Remove R_.key
                    b.Add R_, R_.key
                    Set R_.correspondingBranch = r
                    If u.correspondingBranch Is Nothing Then
                        R_.correspondingBranch.distance = r.length
                    Else
                        R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length
                    End If
                    III.Remove r.key '[not mentioned by Dijkstra ...]
                    II.Add r, r.key
                Else
                    If Belongs(R_, b) Then '[initially B is empty ...]
                        If R_.correspondingBranch.distance > u.correspondingBranch.distance + r.length Then
                            II.Remove R_.correspondingBranch.key
                            II.Add r, r.key
                            Set R_.correspondingBranch = r '[needed in step 2.]
                            R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length
                        End If
                    End If
                End If
            End If
        Next r
        'Step 2. Every node in set B can be connected to node P in only one way
        'if we restrict ourselves to Branches from set I and one from set II. In this sense
        'each node in set B has a distance from node P: the node with minimum distance
        'from P is transferred from set B to set A, and the corresponding branch is transferred
        'from set II to set I. We then return to step I and repeat the process
        'until node Q is transferred to set A. Then the solution has been found.
        dist = INFINITY
        Set u = Nothing
        For Each n In b
            If dist > n.correspondingBranch.distance Then
                dist = n.correspondingBranch.distance
                Set u = n
            End If
        Next n
        b.Remove u.key
        a.Add u, u.key
        II.Remove u.correspondingBranch.key
        I.Add u.correspondingBranch, u.correspondingBranch.key
    Loop Until IIf(Q Is Nothing, a.Count = Nodes.Count, u Is Q)
    If Not Q Is Nothing Then GetPath Q
End Sub
Private Function Belongs(n As Node, col As Collection) As Boolean
    Dim obj As Node
    On Error GoTo err
        Belongs = True
        Set obj = col(n.key)
        Exit Function
err:
        Belongs = False
End Function
Private Sub GetPath(Target As Node)
    Dim path As String
    If Target.correspondingBranch Is Nothing Then
        path = "no path"
    Else
        path = Target.key
        Set u = Target
        Do While Not u.correspondingBranch Is Nothing
            path = u.correspondingBranch.from.key & " " & path
            Set u = u.correspondingBranch.from
        Loop
        Debug.Print u.key, Target.key, Target.correspondingBranch.distance, path
    End If
End Sub
Public Sub test()
    Dim a As New Node, b As New Node, c As New Node, d As New Node, e As New Node, f As New Node
    Dim ab As New Branch, ac As New Branch, af As New Branch, bc As New Branch, bd As New Branch
    Dim cd As New Branch, cf As New Branch, de As New Branch, ef As New Branch
    Set ab.from = a: Set ab.towards = b: ab.length = 7: ab.key = "ab": ab.distance = INFINITY
    Set ac.from = a: Set ac.towards = c: ac.length = 9: ac.key = "ac": ac.distance = INFINITY
    Set af.from = a: Set af.towards = f: af.length = 14: af.key = "af": af.distance = INFINITY
    Set bc.from = b: Set bc.towards = c: bc.length = 10: bc.key = "bc": bc.distance = INFINITY
    Set bd.from = b: Set bd.towards = d: bd.length = 15: bd.key = "bd": bd.distance = INFINITY
    Set cd.from = c: Set cd.towards = d: cd.length = 11: cd.key = "cd": cd.distance = INFINITY
    Set cf.from = c: Set cf.towards = f: cf.length = 2: cf.key = "cf": cf.distance = INFINITY
    Set de.from = d: Set de.towards = e: de.length = 6: de.key = "de": de.distance = INFINITY
    Set ef.from = e: Set ef.towards = f: ef.length = 9: ef.key = "ef": ef.distance = INFINITY
    a.key = "a"
    b.key = "b"
    c.key = "c"
    d.key = "d"
    e.key = "e"
    f.key = "f"
    Dim testNodes As New Collection
    Dim testBranches As New Collection
    testNodes.Add a, "a"
    testNodes.Add b, "b"
    testNodes.Add c, "c"
    testNodes.Add d, "d"
    testNodes.Add e, "e"
    testNodes.Add f, "f"
    testBranches.Add ab, "ab"
    testBranches.Add ac, "ac"
    testBranches.Add af, "af"
    testBranches.Add bc, "bc"
    testBranches.Add bd, "bd"
    testBranches.Add cd, "cd"
    testBranches.Add cf, "cf"
    testBranches.Add de, "de"
    testBranches.Add ef, "ef"
    Debug.Print "From", "To", "Distance", "Path"
    '[Call Dijkstra with target:]
    Dijkstra testNodes, testBranches, a, e
    '[Call Dijkstra without target computes paths to all reachable nodes:]
    Dijkstra testNodes, testBranches, a
    GetPath f
End Sub


package diningphilosophers;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

enum PhilosopherState { Get, Eat, Pon }

class Fork {
    public static final int ON_TABLE = -1;
    static int instances = 0;
    public int id;
    public AtomicInteger holder = new AtomicInteger(ON_TABLE);

    Fork() { id = instances++; }
}

class Philosopher implements Runnable {
    static final int maxWaitMs = 100;                          //  must be > 0
    static AtomicInteger token = new AtomicInteger(0);
    static int instances = 0;
    static Random rand = new Random();
    AtomicBoolean end = new AtomicBoolean(false);
    int id;
    PhilosopherState state = PhilosopherState.Get;
    Fork left;
    Fork right;
    int timesEaten = 0;

    Philosopher() {
        id = instances++;
        left = Main.forks.get(id);
        right = Main.forks.get((id+1)%Main.philosopherCount);
    }

    void sleep() { try { Thread.sleep(rand.nextInt(maxWaitMs)); }
        catch (InterruptedException ex) {} }

    void waitForFork(Fork fork) {
        do {
            if (fork.holder.get() == Fork.ON_TABLE) {
                fork.holder.set(id);                //  my id shows I hold it
                return;
            } else {                                //  someone still holds it
                sleep();                            //  check again later
            }
        } while (true);
    }

    public void run() {
        do {
            if (state == PhilosopherState.Pon) {    //  all that pondering
                state = PhilosopherState.Get;       //  made me hungry
            } else { // ==PhilosopherState.Get
                if (token.get() == id) {            //  my turn now
                    waitForFork(left);
                    waitForFork(right);             //  Ah needs me some foahks!
                    token.set((id+2)% Main.philosopherCount);
                    state = PhilosopherState.Eat;
                    timesEaten++;
                    sleep();                        //  eat for a while
                    left.holder.set(Fork.ON_TABLE);
                    right.holder.set(Fork.ON_TABLE);
                    state = PhilosopherState.Pon;   //  ponder for a while
                    sleep();
                } else {                    //  token.get() != id, so not my turn
                    sleep();
                }
            }
        } while (!end.get());
    }
}

public class Main {
    static final int philosopherCount = 5; //  token +2 behavior good for odd #s
    static final int runSeconds = 15;
    static ArrayList<Fork> forks = new ArrayList<Fork>();
    static ArrayList<Philosopher> philosophers = new ArrayList<Philosopher>();

    public static void main(String[] args) {
        for (int i = 0 ; i < philosopherCount ; i++) forks.add(new Fork());
        for (int i = 0 ; i < philosopherCount ; i++)
            philosophers.add(new Philosopher());
        for (Philosopher p : philosophers) new Thread(p).start();
        long endTime = System.currentTimeMillis() + (runSeconds * 1000);

        do {                                                    //  print status
            StringBuilder sb = new StringBuilder("|");

            for (Philosopher p : philosophers) {
                sb.append(p.state.toString());
                sb.append("|");            //  This is a snapshot at a particular
            }                              //  instant.  Plenty happens between.

            sb.append("     |");

            for (Fork f : forks) {
                int holder = f.holder.get();
                sb.append(holder==-1?"   ":String.format("P%02d",holder));
                sb.append("|");
            }

            System.out.println(sb.toString());
            try {Thread.sleep(1000);} catch (Exception ex) {}
        } while (System.currentTimeMillis() < endTime);

        for (Philosopher p : philosophers) p.end.set(true);
        for (Philosopher p : philosophers)
            System.out.printf("P%02d: ate %,d times, %,d/sec\n",
                p.id, p.timesEaten, p.timesEaten/runSeconds);
    }
}


import "/dynamic" for Tuple
import "/trait" for Comparable
import "/sort" for Cmp, Sort
import "/set" for Set

var Edge = Tuple.create("Edge", ["v1", "v2", "dist"])

// One vertex of the graph, complete with mappings to neighboring vertices
class Vertex is Comparable {
    static map { __map }  // maps a name to its corresponding Vertex

    construct new(name) {
        _name = name
        _dist = Num.maxSafeInteger  // assumed to be infinity
        _prev = null
        _neighbors = {}
        if (!__map) __map = {}
        __map[name] = this
    }

    name      { _name }
    dist      { _dist }
    dist=(d)  { _dist = d }
    prev      { _prev }
    prev=(v)  { _prev = v  }
    neighbors { _neighbors }

    printPath() {
        if (this == _prev) {
            System.write(_name)
        } else if (!_prev) {
            System.write("%(_name)(unreached)")
        } else {
            _prev.printPath()
            System.write(" -> %(_name)(%(_dist))")
        }
    }

    compare(other) {
        if (_dist == other.dist) return Cmp.string.call(_name, other.name)
        return Cmp.num.call(_dist, other.dist)
    }

    toString { "(%(_name), %(_dist))" }
}

class Graph {
    construct new(edges, directed, showAllPaths) {
        _graph = {}
        // one pass to find all vertices
        for (e in edges) {
            if (!_graph.containsKey(e.v1)) _graph[e.v1] = Vertex.new(e.v1)
            if (!_graph.containsKey(e.v2)) _graph[e.v2] = Vertex.new(e.v2)
        }

        // another pass to set neighboring vertices
        for (e in edges) {
            _graph[e.v1].neighbors[_graph[e.v2].name] = e.dist
            // also do this for an undirected graph if applicable
            if (!directed) _graph[e.v2].neighbors[_graph[e.v1].name] = e.dist
        }
        _showAllPaths = showAllPaths
        _directed = directed
    }

    // Runs dijkstra using a specified source vertex
    dijkstra(startName) {
        if (!_graph.containsKey(startName)) {
            System.print("Graph doesn't contain start vertex '%(startName)'")
            return
        }
        var source = _graph[startName]
        var q = Set.new()

        // set-up vertices
        for (v in _graph.values) {
            v.prev = (v == source) ? source : null
            v.dist = (v == source) ? 0 : Num.maxSafeInteger
            q.add(v.name)
        }
        dijkstra_(q)
    }

    // Implementation of dijkstra's algorithm using a (simulated) tree set
    dijkstra_(q) {
        while (!q.isEmpty) {
            var qq = q.toList
            Sort.heap(qq)
            // vertex with shortest distance (first iteration will return source)
            var u = Vertex.map[qq[0]]
            q.remove(qq[0])
            // if distance is infinite we can ignore 'u'
            // (and any other remaining vertices) since they are unreachable
            if (u.dist == Num.maxSafeInteger) break

            // look at distances to each neighbor
            for (a in u.neighbors) {
                var v = Vertex.map[a.key] // the neighbor in this iteration
                var alternateDist = u.dist + a.value
                if (alternateDist < v.dist) { // shorter path to neighbor found
                    v.dist = alternateDist
                    v.prev = u
                }
            }
        }
    }

    // Prints the path from the source to every vertex
    // (output order is not guaranteed)
    printAllPaths_() {
        for (v in _graph.values) {
            v.printPath()
            System.print()
        }
        System.print()
    }

    // Prints a path from the source to the specified vertex
    printPath(endName) {
        if (!_graph.containsKey(endName)) {
            System.print("Graph doesn't contain end vertex '%(endName)'")
            return
        }
        System.write(_directed ? "Directed   : " : "Undirected : ")
        _graph[endName].printPath()
        System.print()
        if (_showAllPaths) printAllPaths_() else System.print()
    }
}

var GRAPH = [
    Edge.new("a", "b", 7),
    Edge.new("a", "c", 9),
    Edge.new("a", "f", 14),
    Edge.new("b", "c", 10),
    Edge.new("b", "d", 15),
    Edge.new("c", "d", 11),
    Edge.new("c", "f", 2),
    Edge.new("d", "e", 6),
    Edge.new("e", "f", 9)
]

var START = "a"
var END   = "e"

var g = Graph.new(GRAPH, true, false)  // directed
g.dijkstra(START)
g.printPath(END)

g = Graph.new(GRAPH, false, false)     // undirected
g.dijkstra(START)
g.printPath(END)


F squeeze(input, include)
   V s = ‘’
   L(i) 0 .< input.len
      I i == 0 | input[i - 1] != input[i] | (input[i - 1] == input[i] & input[i] != include)
         s ‘’= input[i]
   R s

V testStrings = [
   ‘’,
   ‘"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln ’,
   ‘..1111111111111111111111111111111111111111111111111111111111111117777888’,
   ‘I never give 'em hell, I just tell the truth, and they think it's hell. ’,
   ‘                                                    --- Harry S Truman  ’,
   ‘122333444455555666666777777788888888999999999’,
   ‘The better the 4-wheel drive, the further you'll be from help when ya get stuck!’,
   ‘headmistressship’
]

V testChar = [
   ‘ ’,
   ‘-’,
   ‘7’,
   ‘.’,
   ‘ -r’,
   ‘5’,
   ‘e’,
   ‘s’
]

L(testNum) 0 .< testStrings.len
   V s = testStrings[testNum]
   L(c) testChar[testNum]
      V result = squeeze(s, c)
      print("use: '#.'\nold:  #2 <<<#.>>>\nnew:  #2 <<<#.>>>\n".format(c, s.len, s, result.len, result))


let random_wait n = Unix.sleep (Random.int n);;
let print s m = Printf.printf "philosopher %s is %s\n" s m; flush(stdout);;
let will_eat s = print s "eating"; random_wait 10;;
let will_think s = print s "thinking"; random_wait 20; print s "hungry";;

  (* a,b,c,d,e are thinking philosophers; ah,bh,ch,dh,eh are the same philosophers when hungry;
     fab is the fork located between philosophers a and b; similarly for fbc, fcd, ... *)

def  ah() & fab() & fea() = will_eat "Aristotle"; a() & fab() & fea()
 or  bh() & fab() & fbc() = will_eat "Kant";      b() & fab() & fbc()
 or  ch() & fbc() & fcd() = will_eat "Spinoza";   c() & fbc() & fcd()
 or  dh() & fcd() & fde() = will_eat "Marx";      d() & fcd() & fde()
 or  eh() & fde() & fea() = will_eat "Russell";   e() & fde() & fea()

 and a() = will_think "Aristotle"; ah()
 and b() = will_think "Kant";      bh()
 and c() = will_think "Spinoza";   ch()
 and d() = will_think "Marx";      dh()
 and e() = will_think "Russell";   eh()
;;
spawn fab() & fbc() & fcd() & fde() & fea() & a() & b() & c() & d() & e();;


mutable struct Philosopher
    name::String
    hungry::Bool
    righthanded::Bool
    rightforkheld::Channel
    leftforkheld::Channel
    function Philosopher(name, leftfork, rightfork)
        this = new()
        this.name = name
        this.hungry = rand([false, true]) # not specified so start as either
        this.righthanded   = (name == "Aristotle") ? false : true
        this.leftforkheld  = leftfork
        this.rightforkheld = rightfork
        this
    end
end

mutable struct FiveForkTable
    fork51::Channel
    fork12::Channel
    fork23::Channel
    fork34::Channel
    fork45::Channel
    function FiveForkTable()
        this = new()
        this.fork51 = Channel(1); put!(this.fork51, "fork") # start with one fork per channel
        this.fork12 = Channel(1); put!(this.fork12, "fork")
        this.fork23 = Channel(1); put!(this.fork23, "fork")
        this.fork34 = Channel(1); put!(this.fork34, "fork")
        this.fork45 = Channel(1); put!(this.fork45, "fork")
        this
    end
end

table = FiveForkTable();
tasks = [Philosopher("Aristotle", table.fork12, table.fork51),
         Philosopher("Kant", table.fork23, table.fork12),
         Philosopher("Spinoza", table.fork34, table.fork23),
         Philosopher("Marx", table.fork45, table.fork34),
         Philosopher("Russell", table.fork51, table.fork45)]

function dine(t,p)
    if p.righthanded
       take!(p.rightforkheld); println("$(p.name) takes right fork")
       take!(p.leftforkheld); println("$(p.name) takes left fork")
    else
       take!(p.leftforkheld); println("$(p.name) takes left fork")
       take!(p.rightforkheld); println("$(p.name) takes right fork")
    end
end

function leavetothink(t, p)
    put!(p.rightforkheld, "fork"); println("$(p.name) puts down right fork")
    put!(p.leftforkheld, "fork");  println("$(p.name) puts down left fork")
end

contemplate(t) = sleep(t)

function dophil(p, t, fullaftersecs=2.0, hungryaftersecs=10.0)
    while true
        if p.hungry
            println("$(p.name) is hungry")
            dine(table, p)
            sleep(fullaftersecs)
            p.hungry = false
            leavetothink(t, p)
        else
            println("$(p.name) is out of the dining room for now.")
            contemplate(hungryaftersecs)
            p.hungry = true
        end
    end
end

function runall(tasklist)
    for p in tasklist
        @async dophil(p, table)
    end
    while true begin sleep(5) end end
end

runall(tasks)


const INF=(0).MAX;
fcn dijkstra(graph,start,dst){
   Q   :=graph.copy();
   prev:=graph.keys.pump(Dictionary().add.fp1(Void));
   dist:=graph.keys.pump(Dictionary().add.fp1(INF));
   dist[start]=0;
   while(Q){
      Q.reduce('wrap(min,[(v,_)],ru){
           if((d:=dist[v])<min){ ru.set(v); d } else min },
        INF,ru:=Ref(Void));
      if(not u:=ru.value) return("Can't get there");
      if(u==dst){
         S:=List(); do{ S.append(u); u=prev[u]; }while(u);
	 return(S.reverse());
      }
      Q.del(u);
      foreach v,len in (graph[u]){  // (neighborVertex,len to neighbor)...
	  alt:=dist[u] + len;
	  if(alt<dist[v]){ dist[v]=alt; prev[v]=u; }
      }
   }
}


puts:	equ	9
	org	100h
	jmp	demo
	;;;	Squeeze the string at DE on the character in C.
	;;;	The result is written starting at HL.
squeez:	mvi	b,'$'	; Last character seen
	dcx	d	; Move pointer back one item
sqzlp:	mvi	m,'$'	; Stop on end of string
	inx 	d	; Increment input pointer
	ldax	d	; Grab character from input string
	cmp 	m	; End reached?
	rz		; Then stop
	cmp	c	; Was it equal to the character to squeeze?
	jnz	sqzwr	; If not, then write it to the output
	mov	a,b	; If so, is the previous character?
	cmp	c
	jz	sqzlp	; If so, ignore this one
sqzwr:	ldax	d	; Retrieve the character again
	mov	m,a	; It goes in the output
	mov	b,a	; And it is the last character seen
	inx	h	; Increment output pointer
	jmp	sqzlp
	;;;	Print the string in DE and character in C as specified,
	;;;	squeeze the string and print the output.
prsqz:	push	b	; Save input parameters
	push	d
	mov	a,c	; Store character
	sta	chval
	lxi	d,chstr	; Print character
	mvi	c,puts
	call	5
	pop	h	; Retrieve input string pointer
	push	h
	call	prbrkt	; Print the string in brackets
	pop	d	; Retrieve both input parameters
	pop 	b
	lxi	h,buffer
	call	squeez	; Squeeze the input string
	lxi	h,buffer	; ... fall through to print the result
	;;;	Write the string at HL and its length in brackets
prbrkt:	push	h	; Keep the pointer
	mvi	b,0FFh	; Find the length
	mvi	a,'$'	; End marker
	dcx 	h
lscan:	inr	b	; Scan through the string incrementing B
	inx	h	; and HL until the end is found
	cmp	m
	jnz	lscan
	mov	a,b	; Find high and low digit (assuming < 100)
	mvi	b,'0'-1
pdigit:	inr	b	; B = high digit
	sui	10
	jnc	pdigit
	lxi	h,bstart+1
	adi	'0'+10
	mov	m,a	; Write low digit
	dcx	h
	mov	m,b	; Write high digit
	xchg
	mvi	c,puts	; Print length and brackets
	call 	5
	pop	d	; Retrieve the string pointer
	mvi	c,puts	; Print the string
	call 	5
	lxi	d,bend	; Print the ending brackets
	mvi	c,puts
	jmp	5
	;;;	Squeeze each string by the given character
demo:	lxi	h,list	; Pointer to start of list
loop:	mov	e,m	; Load pointer and character
	inx	h
	mov	d,m
	inx	h
	mov	c,m
	inx	h
	xra	a	; Stop when zero reached
	ora	c
	rz
	push	h	; Keep list pointer
	call	prsqz	; Squeeze and print
	pop 	h	; Restore list pointer
	jmp 	loop
	;;;	Formatting strings
chstr:	db	'Character: "'
chval:	db	'*"',13,10,'$'
bstart:	db	'##<<<$'
bend:	db	'>>>'
nl:	db	13,10,'$'
	;;;	Input strings
str1: 	db	'$'
str2:	db	'"If I were two-faced, would I be wearing'
	db	' this one?" --- Abraham Lincoln $'
str3:	db	'..11111111111111111111111111111111111111'
	db	'11111111111111111111111117777888$'
str4: 	db	'I never give ',39,'em hell, I just tell the t'
	db	'ruth, and they think it',39,'s hell. $'
str5:	db	'                                        '
	db	'            --- Harry S Truman  $'
	;;;	Pairs of string pointers and characters to squeeze
list:	dw 	str1
	db 	' '
	dw	str2
	db 	'-'
	dw	str3
	db 	'7'
	dw	str4
	db 	'.'
	dw	str5
	db 	' '
	dw	str5
	db 	'-'
	dw	str5
	db 	'r'
	dw	0
	db 	0
buffer:	equ	$


PROC Squeeze(CHAR ARRAY in,out CHAR a)
  BYTE i,j
  CHAR c

  j=1 c=0
  FOR i=1 TO in(0)
  DO
    IF in(i)#c OR in(i)#a THEN
      c=in(i)
      out(j)=c
      j==+1
    FI
  OD
  out(0)=j-1
RETURN

PROC Test(CHAR ARRAY s CHAR a)
  CHAR ARRAY c(100)
  BYTE CH=$02FC ;Internal hardware value for last key pressed

  Squeeze(s,c,a)
  PrintF("Character to squeeze: ""%C""%E",a)
  PrintF("<<<%S>>> (len=%B)%E",s,s(0))
  PrintF("<<<%S>>> (len=%B)%E",c,c(0))
  PutE()
  PrintE("Press any key to continue")
  PutE()

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

PROC Main()
  Test("",' )
  Test("""If I were two-faced, would I be wearing this one?"" --- Abraham Lincoln ",'-)
  Test("..1111111111111111111111111111111111111111111111111111111111111117777888",'7)
  Test("I never give 'em hell, I just tell the truth, and they think it's hell. ",'.)
  Test("                                                    --- Harry S Truman  ",' )
  Test("                                                    --- Harry S Truman  ",'-)
  Test("                                                    --- Harry S Truman  ",'r)
RETURN


with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Squeezable is
   procedure Squeeze (S : in String; C : in Character) is
      Res : String (1 .. S'Length);
      Len : Natural := 0;
   begin
      Put_Line ("Character to be squeezed: '" & C & "'");
      Put_Line ("Input  = <<<" & S & ">>>, length =" & S'Length'Image);
      for I in S'Range loop
         if Len = 0 or else (S(I) /= Res(Len) or S(I) /= C) then
            Len := Len + 1;
            Res(Len) := S(I);
         end if;
      end loop;
      Put_Line ("Output = <<<" & Res (1 .. Len) & ">>>, length =" & Len'Image);
   end Squeeze;
begin
   Squeeze ("", ' ');
   Squeeze ("""If I were two-faced, would I be wearing this one?"" --- Abraham Lincoln ", '-');
   Squeeze ("..1111111111111111111111111111111111111111111111111111111111111117777888", '7');
   Squeeze ("I never give 'em hell, I just tell the truth, and they think it's hell. ", '.');
   Squeeze ("                                                    --- Harry S Truman  ", ' ');
   Squeeze ("                                                    --- Harry S Truman  ", '-');
   Squeeze ("                                                    --- Harry S Truman  ", 'r');
end Test_Squeezable;


// Version 1.2.31

import java.util.Random
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock

val rand = Random()

class Fork(val name: String) {
    val lock = ReentrantLock()

    fun pickUp(philosopher: String) {
        lock.lock()
        println("  $philosopher picked up $name")
    }

    fun putDown(philosopher: String) {
        lock.unlock()
        println("  $philosopher put down $name")
    }
}

class Philosopher(val pname: String, val f1: Fork, val f2: Fork) : Thread() {
    override fun run() {
        (1..20).forEach {
            println("$pname is hungry")
            f1.pickUp(pname)
            f2.pickUp(pname)
            println("$pname is eating bite $it")
            Thread.sleep(rand.nextInt(300) + 100L)
            f2.putDown(pname)
            f1.putDown(pname)
        }
    }
}

fun diningPhilosophers(names: List<String>) {
    val size = names.size
    val forks = List(size) { Fork("Fork ${it + 1}") }
    val philosophers = mutableListOf<Philosopher>()
    names.forEachIndexed { i, n ->
        var i1 = i
        var i2 = (i + 1) % size
        if (i2 < i1) {
            i1 = i2
            i2 = i
        }
        val p = Philosopher(n, forks[i1], forks[i2])
        p.start()
        philosophers.add(p)
    }
    philosophers.forEach { it.join() }
}

fun main(args: Array<String>) {
    val names = listOf("Aristotle", "Kant", "Spinoza", "Marx", "Russell")
    diningPhilosophers(names)
}


BEGIN
    # returns a squeezed version of s                                     #
    #         i.e. s with adjacent duplicate c characters removed         #
    PRIO SQUEEZE = 9;
    OP   SQUEEZE = ( STRING s, CHAR c )STRING:
         IF s = ""
         THEN ""   # empty string                                         #
         ELSE      # non-empty string                                     #
            [ LWB s : UPB s ]CHAR result;
            INT     r pos   := LWB result;
            result[ r pos ] := s[ LWB s ];
            FOR s pos FROM LWB s + 1 TO UPB s DO
                IF  result[ r pos ] /= s[ s pos ]
                OR  result[ r pos ] /= c
                THEN
                    r pos +:= 1;
                    result[ r pos ] := s[ s pos ]
                FI
            OD;
            result[ LWB result : r pos ]
         FI # SQUEEZE # ;
    # test the SQUEEZE operator                                           #
    PROC test squeeze = ( STRING s, CHAR c )VOID:
        BEGIN
            STRING z = s SQUEEZE c;
            print( ( "Squeezing """, c, """ in ", "<<<", s, ">>> (length ", whole( ( UPB s + 1 ) - LWB s, 0 ), ")", newline ) );
            print( ( "       ->        ",         "<<<", z, ">>> (length ", whole( ( UPB z + 1 ) - LWB z, 0 ), ")", newline ) )
        END # test squeeze # ;
    # task test cases                                                     #
    test squeeze( "",                                                                           " " );
    test squeeze( """If I were two-faced, would I be wearing this one?"" --- Abraham Lincoln ", "-" );
    test squeeze( "..1111111111111111111111111111111111111111111111111111111111111117777888",   "7" );
    test squeeze( "I never give 'em hell, I just tell the truth, and they think it's hell. ",   "." );
    STRING hst =  "                                                    --- Harry S Truman  ";
    test squeeze( hst, " " );
    test squeeze( hst, "-" );
    test squeeze( hst, "r" )
END


:- category(chopstick).

    % chopstick actions (picking up and putting down) are synchronized using a notification
    % such that a chopstick can only be handled by a single philosopher at a time:

    :- public(pick_up/0).
    pick_up :-
        threaded_wait(available).

    :- public(put_down/0).
    put_down :-
        threaded_notify(available).

:- end_category.

:- object(cs1,
    imports(chopstick)).

    :- threaded.
    :- initialization(threaded_notify(available)).

:- end_object.

:- object(cs2,
    imports(chopstick)).

    :- threaded.
    :- initialization(threaded_notify(available)).

:- end_object.

:- object(cs3,
    imports(chopstick)).

    :- threaded.
    :- initialization(threaded_notify(available)).

:- end_object.

:- object(cs4,
    imports(chopstick)).

    :- threaded.
    :- initialization(threaded_notify(available)).

:- end_object.

:- object(cs5,
    imports(chopstick)).

    :- threaded.
    :- initialization(threaded_notify(available)).

:- end_object.

:- category(philosopher).

    :- public(left_chopstick/1).
    :- public(right_chopstick/1).
    :- public(run/2).

    :- private(message/1).
    :- synchronized(message/1).

    :- uses(random, [random/3]).

    run(0, _) :-
        this(Philosopher),
        message([Philosopher, ' terminated.']).

    run(Count, MaxTime) :-
        Count > 0,
        think(MaxTime),
        eat(MaxTime),
        Count2 is Count - 1,
        run(Count2, MaxTime).

    think(MaxTime):-
        this(Philosopher),
        random(1, MaxTime, ThinkTime),
        message(['Philosopher ', Philosopher, ' thinking for ', ThinkTime, ' seconds.']),
        thread_sleep(ThinkTime).

    eat(MaxTime):-
        this(Philosopher),
        random(1, MaxTime, EatTime),
        ::left_chopstick(LeftStick),
        ::right_chopstick(RightStick),
        LeftStick::pick_up,
        RightStick::pick_up,
        message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
        thread_sleep(EatTime),
        ::LeftStick::put_down,
        ::RightStick::put_down.

    % writing a message needs to be synchronized as it's accomplished
    % using a combination of individual write/1 and nl/0 calls:
    message([]) :-
        nl,
        flush_output.
    message([Atom| Atoms]) :-
        write(Atom),
        message(Atoms).

:- end_category.

:- object(aristotle,
    imports(philosopher)).

    left_chopstick(cs1).
    right_chopstick(cs2).

:- end_object.

:- object(kant,
    imports(philosopher)).

    left_chopstick(cs2).
    right_chopstick(cs3).

:- end_object.

:- object(spinoza,
    imports(philosopher)).

    left_chopstick(cs3).
    right_chopstick(cs4).

:- end_object.

:- object(marx,
    imports(philosopher)).

    left_chopstick(cs4).
    right_chopstick(cs5).

:- end_object.

:- object(russell,
    imports(philosopher)).

    left_chopstick(cs1).    % change order so that the chopsticks are picked
    right_chopstick(cs5).   % in different order from the other philosophers

:- end_object.


task←{
    ⍝ Squeeze a string
    squeeze ← ⊢(/⍨)≠∨1,1↓⊣≠¯1⌽⊢

    ⍝ Display string and length in the manner given in the task
    display ← {(¯2↑⍕≢⍵),' «««',⍵,'»»»'}

    ⍝ Squeeze string and display output
    show ← {
        r←  ⊂'chr: ''',⍺,''''
        r←r,⊂' in: ',display ⍵
        r←r,⊂'out: ',display ⍺ squeeze ⍵
        ↑r,⊂''
    }

    ⍝ Strings from the task
    s1←''
    s2←'"If I were two-faced, would I be wearing this one?"'
    s2←s2,' --- Abraham Lincoln '
    s3←'..1111111111111111111111111111111111111111111111111'
    s3←s3,'111111111111117777888'
    s4←'I never give ''em hell, I just tell the truth, and t'
    s4←s4,'hey think it''s hell. '
    s5←'                                                   '
    s5←s5,' --- Harry S Truman  '

    ⎕←' ' show s1
    ⎕←'-' show s2
    ⎕←'7' show s3
    ⎕←'.' show s4
    {⎕←⍵ show s5}¨' -r'  ⍝⍝ note use of 'show' here in a lambda (dfn)
}


squeezable_string(str, char){
    for i, ch in StrSplit(str){
        if (ch <> prev) || !InStr(ch, char)
            res .= ch
        prev := ch
    }
    result := "
    (ltrim
    Original string:`t" StrLen(str) " characters`t«««" str "»»»
    Squeezable Character «««" char "»»»
    Resultant string:`t" StrLen(res) " characters`t«««" res "»»»
    )"
    return result
}


# syntax: GAWK -f DETERMINE_IF_A_STRING_IS_SQUEEZABLE.AWK
BEGIN {
    arr[++n] = ""                                                                                ; arr2[n] = " "
    arr[++n] = "\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln "       ; arr2[n] = "-"
    arr[++n] = "..1111111111111111111111111111111111111111111111111111111111111117777888"         ; arr2[n] = "7"
    arr[++n] = "I never give 'em hell, I just tell the truth, and they think it's hell. "         ; arr2[n] = "."
    arr[++n] = "                                                    --- Harry S Truman  "         ; arr2[n] = " -r"
    arr[++n] = "The better the 4-wheel drive, the further you'll be from help when ya get stuck!" ; arr2[n] = "e"
    arr[++n] = "headmistressship"                                                                 ; arr2[n] = "s"
    for (i=1; i<=n; i++) {
      for (j=1; j<=length(arr2[i]); j++) {
        main(arr[i],substr(arr2[i],j,1))
      }
    }
    exit(0)
}
function main(str,chr,  c,i,new_str,prev_c) {
    for (i=1; i<=length(str); i++) {
      c = substr(str,i,1)
      if (!(prev_c == c && c == chr)) {
        prev_c = c
        new_str = new_str c
      }
    }
    printf("use: '%s'\n",chr)
    printf("old: %2d <<<%s>>>\n",length(str),str)
    printf("new: %2d <<<%s>>>\n\n",length(new_str),new_str)
}


Module Dining_philosophers (whichplan) {
	Form 80, 32
	Const MayChangePick=Random(True, False)
	dim energy(1 to 5)=50
	Document Doc$
	const nl$={
	}
	Print $(,12),  ' set column width to 12
	Pen 14
	Pen 15	{
		Doc$="Dining Philosophers"+nl$
		\\ we can change thread plan only if no threads defined
		if whichplan=1 then
			Doc$="Sequential threads - to execute exclusive one threads code"+nl$
			thread.plan sequential
			\\ need time_to_think>time_to_eat, but time_to_appear maybe the same for all
			time_to_think=150  ' one or more intervals
			time_to_eat=100 ' one interval to eat only
			time_to_appear=(150,150,150,150,150)
			Return time_to_appear, random(0,3):=300
		else
			Doc$="Concurrent threads  - to execute a statement or a block of code"+nl$
			thread.plan concurrent
			time_to_think=100  ' one or more intervals
			time_to_eat=50 ' one interval to eat only
			time_to_appear=(100,100,100,100,100)
			Return time_to_appear, random(1,4):=200
		end if
		Print #-2,Doc$
		Print @(0,2),"Press left mouse button to exit"
		Print Part $(1), time_to_appear
		Print under
	}
	Pen 13 {Print "Aristotle", "Kant", "Spinoza", "Marx", "Russell"}
	enum philosopher {
		Aristotle, Kant, Spinoza, Marx, Russell
	}
	global enum forks {NoFork, Fork}
	RoundTable =(Fork, Fork, Fork, Fork, Fork)
	Getleft=lambda RoundTable (ph as philosopher) -> {
		where=(ph+4) mod 5
		= RoundTable#val(where)
		Return RoundTable, where:=NoFork
	}
	GetRight=lambda RoundTable (ph as philosopher) -> {
		where=ph mod 5
		=RoundTable#val(where)
		Return RoundTable, where:=NoFork
	}
	PlaceForks=lambda RoundTable (ph as philosopher) -> {
		Return RoundTable,  (ph+4) mod 5:=Fork,ph mod 5:=Fork
	}
	PlaceAnyFork=lambda RoundTable (ph as philosopher, &ForkL, &ForkR) -> {
		If ForkL=Fork then Return RoundTable,  (ph+4) mod 5:=Fork : ForkL=NoFork
		If ForkR=Fork Then  Return RoundTable, ph mod 5:=Fork : ForkR=NoFork
	}
	ShowTable=lambda RoundTable -> {
		m=each(RoundTable)
		while m
			print if$(array(m)=NoFork->"No Fork", "Fork"),
		end while
		Print
	}
	noforks=lambda RoundTable -> {
		k=0
		m=each(RoundTable)
		while m
			if array(m)=NoFork then k++
		end while
		=k=5
	}

	def critical as long, basetick
	Document page$
	m=each(philosopher)
	while m {
		\\ we make 5 threads
		\\ a thread has module scope (except for own static variables, and stack of values)
		thread {
			if  energy(f)<1 then {
					call PlaceAnyFork(f, ForkL, ForkR)
					energy(f)=0
					Page$=format$("{0::-12} - ",tick-basetick)+eval$(f)+" - Die"+nl$
					thread this erase
			} else	{
					Page$=format$("{0::-12} - ",tick-basetick)+eval$(f)
					Page$=if$(ForkL=Nofork or ForkR=Nofork->" thinking",  " eating"+str$(eatcount))
					Page$=if$(R->"- R", " - L")+nl$
			}
			if not think then
				{ \\ a block always run blocking all other threads
					energy(f)++
					eatcount--
					if eatcount>0 then exit
					Call PlaceForks(f) : ForkL=Nofork:ForkR=NoFork
					eatcount=random(4,8)
					if MayChangePick then R=random(-1,0)
					think=true :thread this interval  time_to_think*random(1,5)
				}
			else.if energy(f)>70 or critical>5 then
				{
					call PlaceAnyFork(f, &ForkL, &ForkR)
					if energy(f)>70  then energy(f)=60
				}
			else.if R then
					if ForkR=Nofork then ForkR=GetRight(f)
					if ForkR=fork and ForkL=Nofork then ForkL=GetLeft(f)
					if ForkL=fork then think=false:thread this interval  time_to_eat else energy(f)--
			else
					if ForkL=Nofork then ForkL=GetLeft(f)
					if ForkL=fork and ForkR=Nofork then ForkR=GetRight(f)
					if ForkR=fork then think=false:thread this interval  time_to_eat else energy(f)--
			end if

		} as a interval time_to_appear#val(m^)
		\\ a is a variable which hold the number of thread (as returned from task manager)
		\\ so we can get 5 times a new number.
		\\ for each thread we make some static variables (only for each thread)
		\\ this statement execute a line of code in thread a
		thread a execute {
			\\ this executed on thread execution object
			static f=eval(m), think=true, ForkL=NoFork
			static ForkR=NoFork, eatcount=random(2,5)
			static R=-1
			if MayChangePick then  R=Random(-1,0)
		}
	}
	cls ,5  ' set split screen from fifth row
	\\ Main.Task is a thread also. Normaly exit if no other threads running in background
	\\ also serve a the wait loop for task manager (we can use Every 200 {} but isn't a thread, is a kind of a wait statement)
	\\ tick return the counter from  task manager which used to triger threads
	basetick=tick
	\\ 4hz display results
	MaxCritical=0
	Main.Task 1000/4 {
		{ \\ a block always run blocking all other threads
			cls
			Print Part $(1),$("####;\D\I\E;\D\I\E"),energy()
			Print Under
			Print "Table:"
			Call ShowTable()
			if noforks() then critical++  else critical=0
			MaxCritical=if(MaxCritical<critical->critical,MaxCritical)
			Print "noforks on table counter:";critical, "Max:";MaxCritical
			Print #-2,Page$
			Doc$=Page$
			Clear Page$
		}
		if critical>40 or keypress(1) then exit
	}
	threads erase
	Clipboard Doc$
}
Dining_philosophers Random(1,2)


names = <|1 -> "Aristotle", 2 -> "Kant", 3 -> "Spinoza", 4 -> "Marx", 5 -> "Russell"|>;
n = Length[names];
rp := Pause[RandomReal[4]];
PrintTemporary[Dynamic[Array[forks, n]]];
Clear[forks]; forks[_] := Null;
With[{nf = n},
  ParallelDo[
   With[{i1 = i, i2 = Mod[i + 1, nf, 1]},
    Do[Print[names[i], " thinking"]; rp; Print[names[i], " hungry"];
     CriticalSection[{forks[i1], forks[i2]},
      Print[names[i], " eating"]; rp],
     {2}]],
   {i, nf}]];


10 DEFINT A-Z
20 READ N: DIM S$(N): FOR I=1 TO N: READ S$(I): NEXT
30 READ S,C$: IF S=0 THEN END
40 PRINT "Character: '";C$;"'"
50 O$=S$(S): GOSUB 200
60 I$=S$(S): GOSUB 100: GOSUB 200
70 PRINT
80 GOTO 30
100 REM --
101 REM -- Squeeze I$ on character C$, output in O$
102 REM --
105 O$ = ""
110 X = INSTR(I$,C$)
120 IF X = 0 THEN O$ = O$ + I$: RETURN
130 O$ = O$ + LEFT$(I$,X)
140 FOR X=X TO LEN(I$): IF MID$(I$,X,1) = C$ THEN NEXT
150 I$ = RIGHT$(I$,LEN(I$)-X+1)
160 GOTO 110
200 REM --
201 REM -- Display O$ and its length in brackets
202 REM --
210 PRINT USING "##";LEN(O$);
220 PRINT "<<<";O$;">>>"
230 RETURN
400 REM -- Strings
410 DATA 5
415 DATA""
420 DATA"'If I were two-faced, would I be wearing this one?' --- Abraham Lincoln "
430 DATA"..1111111111111111111111111111111111111111111111111111111111111117777888"
440 DATA"I never give 'em hell, I just tell the truth, and they think it's hell. "
450 DATA"                                                    --- Harry S Truman  "
500 REM -- String index and character to squeeze
510 DATA 1," ", 2,"-", 3,"7", 4,".", 5," ", 5,"-", 5,"r", 0,""


get "libhdr"

// Squeeze a string
let squeeze(in, ch, out) = valof
$(  out%0 := 0
    for i=1 to in%0
        if i=1 | in%i~=ch | in%(i-1)~=ch
        $(  out%0 := out%0 + 1
            out%(out%0) := in%i
        $)
    resultis out
$)

// Print string with brackets and length
let brackets(s) be
    writef("%N: <<<%S>>>*N", s%0, s)

// Print original and collapsed version
let show(s, ch) be
$(  let v = vec 1+255/BYTESPERWORD
    writef("Character: '%C'*N", ch)
    brackets(s)
    brackets(squeeze(s, ch, v))
    wrch('*N')
$)

let start() be
$(  let s1=""
    let s2="*"If I were two-faced, would I be wearing this one?*" --- Abraham Lincoln "
    let s3="..1111111111111111111111111111111111111111111111111111111111111117777888"
    let s4="I never give 'em hell, I just tell the truth, and they think it's hell. "
    let s5="                                                     --- Harry S Truman "

    show(s1, ' ')
    show(s2, '-')
    show(s3, '7')
    show(s4, '.')
    show(s5, ' ')
    show(s5, '-')
    show(s5, 'r')
$)


#include<string.h>
#include<stdlib.h>
#include<stdio.h>

#define COLLAPSE 0
#define SQUEEZE 1

typedef struct charList{
    char c;
    struct charList *next;
} charList;

/*
Implementing strcmpi, the case insensitive string comparator, as it is not part of the C Standard Library.

Comment this out if testing on a compiler where it is already defined.
*/

int strcmpi(char str1[100],char str2[100]){
    int len1 = strlen(str1), len2 = strlen(str2), i;

    if(len1!=len2){
        return 1;
    }

    else{
        for(i=0;i<len1;i++){
            if((str1[i]>='A'&&str1[i]<='Z')&&(str2[i]>='a'&&str2[i]<='z')&&(str2[i]-65!=str1[i]))
                return 1;
            else if((str2[i]>='A'&&str2[i]<='Z')&&(str1[i]>='a'&&str1[i]<='z')&&(str1[i]-65!=str2[i]))
                return 1;
            else if(str1[i]!=str2[i])
                return 1;
        }
    }

    return 0;
}

charList *strToCharList(char* str){
    int len = strlen(str),i;

    charList *list, *iterator, *nextChar;

    list = (charList*)malloc(sizeof(charList));
    list->c = str[0];
    list->next = NULL;

    iterator = list;

    for(i=1;i<len;i++){
        nextChar = (charList*)malloc(sizeof(charList));
        nextChar->c = str[i];
        nextChar->next = NULL;

        iterator->next = nextChar;
        iterator = nextChar;
    }

    return list;
}

char* charListToString(charList* list){
    charList* iterator = list;
    int count = 0,i;
    char* str;

    while(iterator!=NULL){
        count++;
        iterator = iterator->next;
    }

    str = (char*)malloc((count+1)*sizeof(char));
    iterator = list;

    for(i=0;i<count;i++){
        str[i] = iterator->c;
        iterator = iterator->next;
    }

    free(list);
    str[i] = '\0';

    return str;
}

char* processString(char str[100],int operation, char squeezeChar){
    charList *strList = strToCharList(str),*iterator = strList, *scout;

    if(operation==SQUEEZE){
        while(iterator!=NULL){
            if(iterator->c==squeezeChar){
                scout = iterator->next;

                while(scout!=NULL && scout->c==squeezeChar){
                        iterator->next = scout->next;
                        scout->next = NULL;
                        free(scout);
                        scout = iterator->next;
                }
            }
            iterator = iterator->next;
        }
    }

    else{
        while(iterator!=NULL && iterator->next!=NULL){
            if(iterator->c == (iterator->next)->c){
                scout = iterator->next;
                squeezeChar = iterator->c;

                while(scout!=NULL && scout->c==squeezeChar){
                        iterator->next = scout->next;
                        scout->next = NULL;
                        free(scout);
                        scout = iterator->next;
                }
            }
            iterator = iterator->next;
        }
    }

    return charListToString(strList);
}

void printResults(char originalString[100], char finalString[100], int operation, char squeezeChar){
    if(operation==SQUEEZE){
        printf("Specified Operation : SQUEEZE\nTarget Character : %c",squeezeChar);
    }

    else
        printf("Specified Operation : COLLAPSE");

    printf("\nOriginal %c%c%c%s%c%c%c\nLength : %d",174,174,174,originalString,175,175,175,(int)strlen(originalString));
    printf("\nFinal    %c%c%c%s%c%c%c\nLength : %d\n",174,174,174,finalString,175,175,175,(int)strlen(finalString));
}

int main(int argc, char** argv){
    int operation;
    char squeezeChar;

    if(argc<3||argc>4){
        printf("Usage : %s <SQUEEZE|COLLAPSE> <String to be processed> <Character to be squeezed, if operation is SQUEEZE>\n",argv[0]);
        return 0;
    }

    if(strcmpi(argv[1],"SQUEEZE")==0 && argc!=4){
        scanf("Please enter characted to be squeezed : %c",&squeezeChar);
        operation = SQUEEZE;
    }

    else if(argc==4){
        operation = SQUEEZE;
        squeezeChar = argv[3][0];
    }

    else if(strcmpi(argv[1],"COLLAPSE")==0){
        operation = COLLAPSE;
    }

    if(strlen(argv[2])<2){
        printResults(argv[2],argv[2],operation,squeezeChar);
    }

    else{
        printResults(argv[2],processString(argv[2],operation,squeezeChar),operation,squeezeChar);
    }

    return 0;
}