dim name$(9)
dim wgt(9)
dim price(9)
dim tak$(100)

name$(1) = "beef"      : wgt(1) = 3.8 : price(1) = 36
name$(2) = "pork"      : wgt(2) = 5.4 : price(2) = 43
name$(3) = "ham"       : wgt(3) = 3.6 : price(3) = 90
name$(4) = "greaves"   : wgt(4) = 2.4 : price(4) = 45
name$(5) = "flitch"    : wgt(5) = 4.0 : price(5) = 30
name$(6) = "brawn"     : wgt(6) = 2.5 : price(6) = 56
name$(7) = "welt"      : wgt(7) = 3.7 : price(7) = 67
name$(8) = "salami"    : wgt(8) = 3.0 : price(8) = 95
name$(9) = "sausage"   : wgt(9) = 5.9 : price(9) = 98

for beef    =         0 to 15 step 3.8
 for pork    =        0 to 15 step 5.4
  for ham     =       0 to 15 step 3.6
   for greaves =      0 to 15 step 2.4
    for flitch  =     0 to 15 step 4.0
     for brawn   =    0 to 15 step 2.5
      for welt    =   0 to 15 step 3.7
       for salami  =  0 to 15 step 3.0
        for sausage = 0 to 15 step 5.9
          if beef + pork + ham + greaves + flitch + brawn + welt + salami + sausage <= 15 then
             totPrice = beef     / 3.8 * 36 + _
                        pork     / 5.4 * 43 + _
                        ham      / 3.6 * 90 + _
                        greaves  / 2.4 * 45 + _
                        flitch   / 4.0 * 30 + _
                        brawn    / 2.5 * 56 + _
                        welt     / 3.7 * 67 + _
                        salami   / 3.0 * 95 + _
                        sausage  / 5.9 * 98
            if totPrice >= maxPrice then
              maxPrice = totPrice
              theMax   = max(totPrice,maxPrice)
              t        = t + 1
              tak$(t)  = str$(maxPrice);",";beef;",";pork;",";ham;",";greaves;",";flitch;",";brawn;",";welt;",";salami;",";sausage
            end if
          end if
next:next :next :next :next :next :next :next :next

print "Best 2 Options":print
for i = t-1 to t
 totTake = val(word$(tak$(i),1,","))
 if totTake > 0 then
   totWgt  = 0
   for j   = 2 to 10
    wgt    = val(word$(tak$(i),j,","))
    totWgt = totWgt + wgt
    value  = wgt / wgt(j - 1) * price(j - 1)
    if wgt <> 0 then print name$(j-1);chr$(9);"Value: ";using("###.#",value);chr$(9);"Weight: ";using("##.#",wgt)
   next j
    print "-------- Total ";using("###.#",totTake);chr$(9);"Weight: ";totWgt
 end if
next i


fn main() {
    let items: [(&str, f32, u8); 9] = [
        ("beef", 3.8, 36),
        ("pork", 5.4, 43),
        ("ham", 3.6, 90),
        ("greaves", 2.4, 45),
        ("flitch", 4.0, 30),
        ("brawn", 2.5, 56),
        ("welt", 3.7, 67),
        ("salami", 3.0, 95),
        ("sausage", 5.9, 98),
    ];
    let mut weight: f32 = 15.0;
    let mut values: Vec<(&str, f32, f32)> = Vec::new();
    for item in &items {
        values.push((item.0, f32::from(item.2) / item.1, item.1));
    }

    values.sort_by(|a, b| (a.1).partial_cmp(&b.1).unwrap());
    values.reverse();

    for choice in values {
        if choice.2 <= weight {
            println!("Grab {:.1} kgs of {}", choice.2, choice.0);
            weight -= choice.2;
            if (choice.2 - weight).abs() < std::f32::EPSILON {
                return;
            }
        } else {
            println!("Grab {:.1} kgs of {}", weight, choice.0);
            return;
        }
    }
}


/* create SAS data set */
data mydata;
   input item $ weight value;
   datalines;
beef    3.8  36
pork    5.4  43
ham     3.6  90
greaves 2.4  45
flitch  4.0  30
brawn   2.5  56
welt    3.7  67
salami  3.0  95
sausage 5.9  98
;

/* call OPTMODEL procedure in SAS/OR */
proc optmodel;
   /* declare sets and parameters, and read input data */
   set <str> ITEMS;
   num weight {ITEMS};
   num value {ITEMS};
   read data mydata into ITEMS=[item] weight value;

   /* declare variables, objective, and constraints */
   var WeightSelected {i in ITEMS} >= 0 <= weight[i];
   max TotalValue = sum {i in ITEMS} (value[i]/weight[i]) * WeightSelected[i];
   con WeightCon:
      sum {i in ITEMS} WeightSelected[i] <= 15;

   /* call linear programming (LP) solver */
   solve;

   /* print optimal solution */
   print TotalValue;
   print {i in ITEMS: WeightSelected[i].sol > 1e-3} WeightSelected;
quit;


import scala.annotation.tailrec

object ContinousKnapsackForRobber extends App {
  val MaxWeight = 15.0
  val items = Seq(
    Item("Beef",    3.8, 3600),
    Item("Pork",    5.4, 4300),
    Item("Ham",     3.6, 9000),
    Item("Greaves", 2.4, 4500),
    Item("Flitch",  4.0, 3000),
    Item("Brawn",   2.5, 5600),
    Item("Welt",    3.7, 6700),
    Item("Salami",  3.0, 9500),
    Item("Sausage", 5.9, 9800))

  // sort items by value per unit weight in descending order
  def sortedItems = items.sortBy(it => -it.value / it.weight)

  @tailrec
  def packer(notPacked: Seq[Item], packed: Lootsack): Lootsack = {

    if (!packed.isNotFull || notPacked.isEmpty) packed
    else {
      val try2fit = packed.copy(bagged = notPacked.head +: packed.bagged)
      if (try2fit.isNotFull) packer(notPacked.tail, try2fit)
      else {
        try2fit.copy(lastPiece = packed.weightLeft / notPacked.head.weight)
      }
    }
  }

  case class Item(name: String, weight: Double, value: Int)

  case class Lootsack(bagged: Seq[Item], lastPiece: Double = 1.0) {
    private val totWeight = if (bagged.isEmpty) 0.0
    else bagged.tail.map(_.weight).sum + bagged.head.weight * lastPiece

    def isNotFull: Boolean = weightLeft > 0

    def weightLeft: Double = MaxWeight - totWeight

    override def toString = f"${show(bagged, lastPiece)}Totals: weight: $totWeight%4.1f, value: $totValue%6.2f"

    private def totValue: BigDecimal = if (bagged.isEmpty) 0.0
    else (bagged.tail.map(_.value).sum + bagged.head.value * lastPiece) / 100

    private def show(is: Seq[Item], percentage: Double) = {
      def toStr(is: Seq[Item], percentage: Double = 1): String =
        is.map(it => f"${percentage * 100}%6.2f%% ${it.name}%-7s ${
          it.weight * percentage}%4.1f ${it.value * percentage / 100}%6.2f\n").mkString

      toStr(is.tail.reverse) + toStr(Seq(is.head), percentage)
    }
  }

  println(packer(sortedItems, Lootsack(Nil)))
}


var items =
[
        [:beef,    3.8, 36],
        [:pork,    5.4, 43],
        [:ham,     3.6, 90],
        [:greaves, 2.4, 45],
        [:flitch,  4.0, 30],
        [:brawn,   2.5, 56],
        [:welt,    3.7, 67],
        [:salami,  3.0, 95],
        [:sausage, 5.9, 98],
].sort {|a,b| b[2]/b[1] <=> a[2]/a[1] }

var (limit, value) = (15, 0);
print "Item   Fraction Weight Value\n";

items.each { |item|
    var ratio = (item[1] > limit ? limit/item[1] : 1);
    value += item[2]*ratio;
    limit -= item[1];
    if (ratio == 1) {
        printf("%-8s %4s %7.2f %6.2f\n", item[0], 'all', item[1], item[2]);
    }
    else {
        printf("%-8s %-4.2f %7.2f %6.2f\n", item[0], ratio, item[1]*ratio, item[2]*ratio);
        break;
    }
}

say "#{'-'*28}\ntotal value: #{'%.14g' % value }"


package require Tcl 8.5

# Uses the trivial greedy algorithm
proc continuousKnapsack {items massLimit} {
    # Add in the unit prices
    set idx -1
    foreach item $items {
	lassign $item name mass value
	lappend item [expr {$value / $mass}]
	lset items [incr idx] $item
    }

    # Sort by unit prices
    set items [lsort -decreasing -real -index 3 $items]

    # Add items, using most valuable-per-unit first
    set result {}
    set total 0.0
    set totalValue 0
    foreach item $items {
	lassign $item name mass value unit
	if {$total + $mass < $massLimit} {
	    lappend result [list $name $mass $value]
	    set total [expr {$total + $mass}]
	    set totalValue [expr {$totalValue + $value}]
	} else {
	    set mass [expr {$massLimit - $total}]
	    set value [expr {$unit * $mass}]
	    lappend result [list $name $mass $value]
	    set totalValue [expr {$totalValue + $value}]
	    break
	}
    }

    # We return the total value too, purely for convenience
    return [list $result $totalValue]
}


#import flo
#import lin

items = # name: (weight,price)

<
   'beef   ': (3.8,36.0),
   'pork   ': (5.4,43.0),
   'ham    ': (3.6,90.0),
   'greaves': (2.4,45.0),
   'flitch ': (4.0,30.0),
   'brawn  ': (2.5,56.0),
   'welt   ': (3.7,67.0),
   'salami ': (3.0,95.0),
   'sausage': (5.9,98.0)>

system = # a function to transform the item list to the data structure needed by the solver

linear_system$[
   lower_bounds: *nS ~&\0.,         # all zeros because we can't steal less than zero
   upper_bounds: ~&nmlPXS,          # can't steal more than what's in the shop
   costs: * ^|/~& negative+ vid,    # prices divided by weights, negated so as to maximize
   equations: ~&iNC\15.+ 1.-*@nS]   # 1 equation constraining the total weight to 15

#cast %em

main = solution system items


struct Item {
    item string
    weight f64
    price f64
}

fn main(){
    mut left := 15.0
    mut items := [
        Item{'beef', 3.8, 36},
        Item{'pork', 5.4, 43},
        Item{'ham', 3.6, 90},
        Item{'greaves', 2.4, 45},
        Item{'flitch', 4.0, 30},
        Item{'brawn', 2.5, 56},
        Item{'welt', 3.7, 67},
        Item{'salami', 3.0, 95},
        Item{'sausage', 5.9, 98}
    ]
    items.sort_with_compare(fn (a &Item, b &Item) int {
        if a.weight/a.price < b.weight/b.price {
            return -1
        } else if a.weight/a.price > b.weight/b.price {
            return 1
        } else {
            return 0
        }
    })
    for item in items {
        if item.weight <= left {
            println('Take all the $item.item')
            if item.weight == left {
                return
            }
            left -= item.weight
        } else {
            println('Take ${left:.1}kg $item.item')
            return
        }
    }
    //println(items)
}


import "/fmt" for Fmt
import "/math" for Math
import "/sort" for Sort

class Item {
    construct new(name, weight, value) {
        _name   = name
        _weight = weight
        _value  = value
    }

    name   { _name   }
    weight { _weight }
    value  { _value  }
}

var items = [
    Item.new("beef", 3.8, 36),
    Item.new("pork", 5.4, 43),
    Item.new("ham", 3.6, 90),
    Item.new("greaves", 2.4, 45),
    Item.new("flitch", 4, 30),
    Item.new("brawn", 2.5, 56),
    Item.new("welt", 3.7, 67),
    Item.new("salami", 3.0, 95),
    Item.new("sausage", 5.9, 98)
]

var maxWeight = 15
// sort items by value per unit weight in descending order
var cmp = Fn.new { |i, j| (j.value/j.weight - i.value/i.weight).sign }
Sort.insertion(items, cmp)
System.print("Item Chosen   Weight  Value  Percentage")
System.print("-----------   ------ ------  ----------")
var w = maxWeight
var itemCount = 0
var sumValue = 0
for (item in items) {
    itemCount = itemCount + 1
    if (item.weight <= w) {
       sumValue = sumValue + item.value
       Fmt.print("$-11s     $3.1f   $5.2f    100.00", item.name, item.weight, item.value)
    } else {
       var value  = Math.toPlaces(w / item.weight * item.value, 2)
       var percentage = Math.toPlaces(w / item.weight * 100, 2)
       sumValue = sumValue + value
       Fmt.print("$-11s     $3.1f   $5.2f    $6.2f", item.name, w, value, percentage)
       break
    }
    w = w - item.weight
    if (w == 0) break
}
System.print("-----------   ------ ------")
Fmt.print("$d items        15.0  $6.2f", itemCount, sumValue)


int  Name, Price, I, BestItem;
real    Weight, Best, ItemWt, TotalWt;
def     Items = 9;
real    PricePerWt(Items);
int     Taken(Items);
include c:\cxpl\codes;

[Name:=  ["beef","pork","ham","greaves","flitch","brawn","welt","salami","sausage"];
Weight:= [ 3.8,   5.4,   3.6,  2.4,      4.0,     2.5,    3.7,   3.0,     5.9];
Price:=  [ 36,    43,    90,   45,       30,      56,     67,    95,      98];

for I:= 0 to Items-1 do
        [PricePerWt(I):= float(Price(I)) / Weight(I);
        Taken(I):= false;
        ];
Format(2,1);
TotalWt:= 0.0;
repeat  Best:= 0.0;
        for I:= 0 to Items-1 do
            if not Taken(I) and PricePerWt(I) > Best then
                [Best:= PricePerWt(I);  BestItem:= I];
        Taken(BestItem):= true;                 \take item
        ItemWt:= Weight(BestItem);              \get its weight
        TotalWt:= TotalWt + ItemWt;             \add to total weight
        if TotalWt > 15.0 then                  \if total is too much, reduce
            ItemWt:= ItemWt - (TotalWt-15.0);   \item weight by amount it's over
        RlOut(0, ItemWt);  Text(0, " kg of ");  \show weight and item
        Text(0, Name(BestItem));  CrLf(0);
until   TotalWt >= 15.0;                        \all we can steal
]


items:=List( T(3.8, 36.0, "beef"),  T(5.4, 43.0, "pork"),  // weight, value, name
	     T(3.6, 90.0, "ham"),   T(2.4, 45.0, "greaves"),
	     T(4.0, 30.0, "flitch"),T(2.5, 56.0, "brawn"),
	     T(3.7, 67.0, "welt"),  T(3.0, 95.0, "salami"),
	     T(5.9, 98.0, "sausage"),
);
fcn item_cmp(a,b){ a[1]/a[0] > b[1]/b[0] }

items.sort(item_cmp);
space := 15.0;
foreach it in (items){ w,_,nm:=it;
   if (space >= w){ println("take all ",nm); space-=w }
   else{ println("take %gkg of %gkg of %s".fmt(space,w,nm)); break }
}


mov ax,0C00h ;equivalent of "mov ah,0Ch mov al,0"
int 21h


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program keyboardInput64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ IOCTL,     0x1D  // Linux syscall
.equ SIGACTION, 0x86  // Linux syscall
.equ SYSPOLL,   0x16  // Linux syscall
.equ CREATPOLL, 0x14  // Linux syscall
.equ CTLPOLL,   0x15  // Linux syscall
.equ TCGETS,    0x5401
.equ TCSETS,    0x5402
.equ ICANON,    2
.equ ECHO,     10
.equ POLLIN,    1
.equ EPOLL_CTL_ADD,    1

.equ SIGINT,   2    // Issued if the user sends an interrupt signal (Ctrl + C)
.equ SIGQUIT,  3    // Issued if the user sends a quit signal (Ctrl + D)
.equ SIGTERM, 15    // Software termination signal (sent by kill by default)
.equ SIGTTOU, 22    //

.equ BUFSIZE,   80

/*******************************************/
/* Structures                               */
/********************************************/
/* structure termios see doc linux*/
    .struct  0
term_c_iflag:                    // input modes
    .struct  term_c_iflag + 4
term_c_oflag:                    // output modes
    .struct  term_c_oflag + 4
term_c_cflag:                    // control modes
    .struct  term_c_cflag + 4
term_c_lflag:                    // local modes
    .struct  term_c_lflag + 4
term_c_cc:                       // special characters
    .struct  term_c_cc + 20      // see length if necessary
term_fin:

/* structure sigaction see doc linux */
    .struct  0
sa_handler:
    .struct  sa_handler + 8
sa_mask:
    .struct  sa_mask + 8
sa_flags:
    .struct  sa_flags + 8
sa_sigaction:
    .struct  sa_sigaction + 8
sa_fin:

/* structure poll see doc linux */
    .struct  0
poll_event:
    .struct  poll_event + 8
poll_fd:                            //   File Descriptor
    .struct  poll_fd + 8
poll_fin:

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessPgmOk:        .asciz "End program OK.\n"
szMessErreur:       .asciz "Error detected.\n"
szCarriageReturn:   .asciz "\n"
szMessCodeErr:      .asciz "Error code décimal :  @ \n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
iEnd:           .skip 8                          // 0 loop  1 = end loop
iTouche:        .skip BUFSIZE                    // value key pressed
stOldtio:       .skip term_fin                   // old terminal state
stCurtio:       .skip term_fin                   // current terminal state
stSigAction:    .skip sa_fin                     // area signal structure
stSigAction1:   .skip sa_fin
stSigAction2:   .skip sa_fin
stSigAction3:   .skip sa_fin
stevents:       .skip 16
sZoneConv:      .skip 24
szBuffer:       .skip BUFSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                     // entry of program
    bl initTerm                           // terminal init
    cmp x0,0                              // error ?
    blt 100f
    bl initPoll                           // epoll instance init
    cmp x0,0
    blt 100f
    mov x22,x0                            // save epfd
    mov x20,0                             // indice
    ldr x21,qAdrszBuffer
1:
    mov x0,x22                            // epfd
    bl waitKey
    cmp x0,0
    beq 1b                                // no ket pressed -> loop
    blt 3f                                // error ?

    bl readKey                            // read one key
    cmp x0,3                              // ctrl-C
    beq 3f
    cmp x0,113                            // saisie q (quit) ?
    beq 3f
    cmp x0,81                             // saisie Q  (Quit)?
    beq 3f
    cmp x0,0xD                            // <enter> ?
    beq 2f
    strb w0,[x21,x20]                     // store byte in buffer
    add x20,x20,1                         // increment indice
    b 1b                                  // and loop
2:                                        // display buffer
    mov x0,0                              // store 0 final
    strb w0,[x21,x20]
    mov x0,x21                            // display buffer
    bl affichageMess
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
    mov x20,0
    b 1b                                  // and loop for other entry
3:
    bl restauTerm                         // terminal restaur
    ldr x0,qAdrszMessPgmOk                // display end message
    bl affichageMess
100:                                      // standard end of the program
    mov x0,0                              // return code
    mov x8,EXIT                           // request to exit program
    svc 0                                 // perform the system call
qAdrszBuffer:             .quad szBuffer
qAdrstevents:             .quad stevents
qAdrszMessErreur:         .quad szMessErreur
qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrstOldtio:             .quad stOldtio
qAdrstCurtio:             .quad stCurtio
qAdrstSigAction:          .quad stSigAction
qAdrstSigAction1:         .quad stSigAction1
qAdrszMessPgmOk:          .quad szMessPgmOk
qAdrSIG_IGN:              .quad 1
qAdriEnd:                 .quad iEnd
qAdriTouche:              .quad iTouche
/*********************************/
/* init terminal state            */
/*********************************/
initTerm:
    stp x1,lr,[sp,-16]!            // save  registers
    /* read terminal state */
    mov x0,STDIN                   // input console
    mov x1,TCGETS
    ldr x2,qAdrstOldtio
    mov x8,IOCTL                   // call system Linux
    svc 0
    cbnz x0,98f                    // error ?

    adr x0,sighandler              // adresse routine traitement signal
    ldr x1,qAdrstSigAction         // adresse structure sigaction
    str x0,[x1,sa_handler]         // maj handler
    mov x0,SIGINT                  // signal type
    ldr x1,qAdrstSigAction
    mov x2,0
    mov x3,8
    mov x8,SIGACTION               // call system
    svc 0

    cmp x0,0                       // error ?
    bne 98f
    mov x0,SIGQUIT
    ldr x1,qAdrstSigAction
    mov x2,0                       // NULL
    mov x8,SIGACTION               // call system
    svc 0
    cmp x0,0                       // error ?
    bne 98f
    mov x0,SIGTERM
    ldr x1,qAdrstSigAction
    mov x2,0                       // NULL
    mov x8,SIGACTION               // appel systeme
    svc 0
    cmp x0,0
    bne 98f
    //
    adr x0,qAdrSIG_IGN             // address signal igonre function
    ldr x1,qAdrstSigAction1
    str x0,[x1,sa_handler]
    mov x0,SIGTTOU                 //invalidate other process signal
    ldr x1,qAdrstSigAction1
    mov x2,0                       // NULL
    mov x8,SIGACTION               // call system
    svc 0
    cmp x0,0
    bne 98f
    //
    /* read terminal current state  */
    mov x0,STDIN
    mov x1,TCGETS
    ldr x2,qAdrstCurtio            // address current termio
    mov x8,IOCTL                   // call systeme
    svc 0
    cmp x0,0                       // error ?
    bne 98f
    mov x2,ICANON | ECHO           // no key pressed echo on display
    mvn x2,x2                      // and one key
    ldr x1,qAdrstCurtio
    ldr x3,[x1,#term_c_lflag]
    and x3,x2,x2                   // add flags
    str x3,[x1,#term_c_lflag]      // and store
    mov x0,STDIN                   // maj terminal current state
    mov x1,TCSETS
    ldr x2,qAdrstCurtio
    mov x8,IOCTL                   // call system
    svc 0
    cbz x0,100f
98:                                // error display
    ldr x1,qAdrszMessErreur        // error message
    bl   displayError
    mov x0,-1
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrstSigAction2:    .quad stSigAction2
qAdrstSigAction3:    .quad stSigAction3
/*********************************/
/* init instance epool            */
/*********************************/
initPoll:
    stp x1,lr,[sp,-16]!            // save  registers
    ldr x0,qAdrstevents
    mov x1,STDIN                   // maj structure events
    str x1,[x0,#poll_fd]           // maj FD
    mov x1,POLLIN                  // action code
    str x1,[x0,#poll_event]
    mov x0,0
    mov x8,CREATPOLL               // create epoll instance
    svc 0
    cmp x0,0                       // error ?
    ble 98f
    mov x10,x0                     // return FD epoll instance
    mov x1,EPOLL_CTL_ADD
    mov x2,STDIN                   // Fd to we want add
    ldr x3,qAdrstevents            // structure events address
    mov x8,CTLPOLL                 // call system control epoll
    svc 0
    cmp x0,0                       // error ?
    blt 98f                       // no
    mov x0,x10                     // return FD epoll instance
    b 100f
98:                                               // error display
    ldr x1,qAdrszMessErreur                       // error message
    bl   displayError
    mov x0,-1
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/*********************************/
/* wait key                      */
/*********************************/
/* x0 contains FD poll    */
waitKey:
    stp x1,lr,[sp,-16]!            // save  registers
    ldr x11,qAdriTouche            // key address
    str xzr,[x11]                  // raz key
1:
    ldr x10,qAdriEnd               // if signal ctrl-c  -> end
    ldr x10,[x10]
    cbnz x10,100f

    ldr x1,qAdrstevents
    mov x2,12                      // size events
    mov x3,1                       // timeout = 1  TODO: ??
    mov x4,0
    mov x8,SYSPOLL                 // call system wait POLL
    svc 0
    cmp x0,0                       // key pressed ?
    bge 100f
98:                                // error display
    ldr x1,qAdrszMessErreur        // error message
    bl   displayError
    mov x0,-1
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/*********************************/
/* read key                      */
/*********************************/
/* x0 returns key value */
readKey:
    stp x1,lr,[sp,-16]!            // save  registers
    mov x0,STDIN                   // File Descriptor
    ldr x1,qAdriTouche             // buffer address
    mov x2,BUFSIZE                 // buffer size
    mov x8,READ                    // read key
    svc #0
    cmp x0,0                       // error ?
    ble 98f
    ldr x2,qAdriTouche             // key address
    ldr x0,[x2]
    b 100f
98:                                // error display
    ldr x1,qAdrszMessErreur        // error message
    bl   displayError
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/*********************************/
/* restaur terminal state        */
/*********************************/
restauTerm:
    stp x1,lr,[sp,-16]!            // save  registers
    mov x0,STDIN                   // end then restaur begin state terminal
    mov x1,TCSETS
    ldr x2,qAdrstOldtio
    mov x8,IOCTL                   // call system
    svc 0
    cbz x0,100f
    ldr x1,qAdrszMessErreur        // error message
    bl   displayError
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30

/******************************************************************/
/*     signal processing                                     */
/******************************************************************/
sighandler:
    stp x1,lr,[sp,-16]!            // save  registers
    ldr x0,qAdriEnd
    mov x1,#1                      // maj zone end
    str x1,[x0]
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     display error message                                      */
/******************************************************************/
/* x0 contains error code */
/* x1 contains address error message    */
displayError:
    stp x2,lr,[sp,-16]!            // save  registers
    mov x2,x0                      // save error code
    mov x0,x1                      // display message error
    bl affichageMess
    mov x0,x2
    ldr x1,qAdrsZoneConv           // conversion error code
    bl conversion10S               // decimal conversion
    ldr x0,qAdrszMessCodeErr
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc          // insert result at @ character
    bl affichageMess               // display message final
    ldp x2,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrsZoneConv:        .quad sZoneConv
qAdrszMessCodeErr:    .quad szMessCodeErr
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


PROC Wait(BYTE frames)
  BYTE RTCLOK=$14
  frames==+RTCLOK
  WHILE frames#RTCLOK DO OD
RETURN

PROC Main()
  BYTE CH=$02FC ;Internal hardware value for last key pressed

  PrintE("Program is halted for 200 frames.")
  PrintE("Type character to fill the buffer.")
  Wait(200)
  PutE()

  DO
    IF CH=$FF THEN
      PrintE("The buffer is empty.")
      EXIT
    ELSE
      PrintF("The buffer stores internal key: %B.%E",CH)
      PrintE("Flush the buffer.")
      CH=$FF
    FI
  OD
RETURN


with Ada.Text_IO;
procedure Flushtest is
   use Text_IO;
begin
   Put_Line ("Type anything for 2 s");
   delay 2.0;
Flush_Input:
   declare
      Ch   : Character;
      More : Boolean;
   begin
      loop
         Get_Immediate (Ch, More);
         exit when not More;
      end loop;
   end Flush_Input;
   New_Line;
   Put_Line ("Okay, thanks. Here is some input from you:");
   Put_Line (Get_Line);
end Flushtest;


/* Programme assembleur ARM Raspberry */
/* modèle B 512MO   */

/* REMARK 1 : this program use routines in a include file
   see task Include a file language arm assembly
   for the routine affichageMess conversion10
   see at end of this program the instruction include */

/************************************/
/* Constantes                       */
/************************************/
.equ STDIN,     0     @ Linux input console
.equ STDOUT,    1     @ Linux output console
.equ EXIT,      1     @ Linux syscall
.equ READ,      3     @ Linux syscall
.equ WRITE,     4     @ Linux syscall
.equ IOCTL,     0x36  @ Linux syscall
.equ SIGACTION, 0x43  @ Linux syscall
.equ SYSPOLL,   0xA8  @ Linux syscall

.equ TCGETS,    0x5401
.equ TCSETS,    0x5402
.equ ICANON,    2
.equ ECHO,     10
.equ POLLIN,    1

.equ SIGINT,   2    @ Issued if the user sends an interrupt signal (Ctrl + C)
.equ SIGQUIT,  3    @ Issued if the user sends a quit signal (Ctrl + D)
.equ SIGTERM, 15    @ Software termination signal (sent by kill by default)
.equ SIGTTOU, 22    @

.equ BUFSIZE,   80

/*******************************************/
/* Structures                               */
/********************************************/
/* structure termios see doc linux*/
    .struct  0
term_c_iflag:                    @ input modes
    .struct  term_c_iflag + 4
term_c_oflag:                    @ output modes
    .struct  term_c_oflag + 4
term_c_cflag:                    @ control modes
    .struct  term_c_cflag + 4
term_c_lflag:                    @ local modes
    .struct  term_c_lflag + 4
term_c_cc:                       @ special characters
    .struct  term_c_cc + 20      @ see length if necessary
term_fin:

/* structure sigaction see doc linux */
    .struct  0
sa_handler:
    .struct  sa_handler + 4
sa_mask:
    .struct  sa_mask + 4
sa_flags:
    .struct  sa_flags + 4
sa_sigaction:
    .struct  sa_sigaction + 4
sa_fin:

/* structure poll see doc linux */
    .struct  0
poll_fd:                            @   File Descriptor
    .struct  poll_fd + 4
poll_events:                        @  events mask
    .struct  poll_events + 4
poll_revents:                       @ events returned
    .struct  poll_revents + 4
poll_fin:

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessPgmOk:        .asciz "End program OK.\n"
szMessErreur:       .asciz "Error detected.\n"
sMessResult:        .ascii "Value  : "
sMessValeur:        .fill 11, 1, ' '            @ size => 11
szCarriageReturn:   .asciz "\n"

.align 4

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
iEnd:           .skip 4                          @ 0 loop  1 = end loop
iTouche:        .skip BUFSIZE                    @ value key pressed
stOldtio:       .skip term_fin                   @ old terminal state
stCurtio:       .skip term_fin                   @ current terminal state
stSigAction:    .skip sa_fin                     @ area signal structure
stSigAction1:   .skip sa_fin
stPoll1:        .skip poll_fin                   @ area poll structure
stPoll2:        .skip poll_fin

szBuffer:       .skip BUFSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                            @ entry of program
    bl initTerm                                  @ terminal init
    mov r2,#0
    ldr r3,iAdrszBuffer
1:
    bl getKey                                    @ read one key
    cmp r0,#113                                  @ saisie q ?
    beq 3f
    cmp r0,#81                                   @ saisie Q ?
    beq 3f
    cmp r0,#0xA                                  @ <enter> ?
    beq 2f
    strb r0,[r3,r2]                              @ store byte in buffer
    add r2,#1
    b 1b
2:                                               @ display buffer
    mov r0,#0                                    @ store 0 final
    strb r0,[r3,r2]
    mov r0,r3
    bl affichageMess
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
    mov r2,#0
    b 1b
3:
    bl restauTerm                                 @ terminal restaur
    ldr r0,iAdrszMessPgmOk                        @ display end message
    bl affichageMess
100:                                              @ standard end of the program
    mov r0, #0                                    @ return code
    mov r7, #EXIT                                 @ request to exit program
    svc #0                                        @ perform the system call
iAdrszBuffer:         .int szBuffer
/*********************************/
/* init terminal state            */
/*********************************/
initTerm:
    push {r0,r1,r2,r7,lr}
    /* read terminal state */
    mov r0,#STDIN                                @ input console
    mov r1,#TCGETS
    ldr r2,iAdrstOldtio
    mov r7, #IOCTL                               @ call system Linux
    svc #0
    cmp r0,#0                                    @ error ?
    beq 1f
    ldr r1,iAdrszMessErreur                      @ error message
    bl   displayError
    b 100f
1:
    adr r0,sighandler                            @ adresse routine traitement signal
    ldr r1,iAdrstSigAction                       @ adresse structure sigaction
    str r0,[r1,#sa_handler]                      @ maj handler
    mov r0,#SIGINT                               @ signal type
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ call system
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r0,#SIGQUIT
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ call system
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r0,#SIGTERM
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ appel systeme
    svc #0
    cmp r0,#0
    bne 98f
    @
    adr r0,iAdrSIG_IGN                           @ address signal igonre function
    ldr r1,iAdrstSigAction1
    str r0,[r1,#sa_handler]
    mov r0,#SIGTTOU                              @invalidate other process signal
    ldr r1,iAdrstSigAction1
    mov r2,#0                                    @ NULL
    mov r7,#SIGACTION                            @ call system
    svc #0
    cmp r0,#0
    bne 98f
    @
    /* read terminal current state  */
    mov r0,#STDIN
    mov r1,#TCGETS
    ldr r2,iAdrstCurtio                          @ address current termio
    mov r7,#IOCTL                                @ call systeme
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r2,#ICANON | ECHO                        @ no key pressed echo on display
    mvn r2,r2                                    @ and one key
    ldr r1,iAdrstCurtio
    ldr r3,[r1,#term_c_lflag]
    and r3,r2                                    @ add flags
    str r3,[r1,#term_c_lflag]                    @ and store
    mov r0,#STDIN                                @ maj terminal current state
    mov r1,#TCSETS
    ldr r2,iAdrstCurtio
    mov r7, #IOCTL                               @ call system
    svc #0
    cmp r0,#0
    beq 100f
98:                                               @ error display
    ldr r1,iAdrszMessErreur                       @ error message
    bl   displayError
100:
    pop {r0,r1,r2,r7,lr}
    bx lr

/*********************************/
/* read key                      */
/*********************************/
getKey:
    push {r1,r2,r7,lr}
    ldr r2,iAdriTouche                           @ key address
    mov r0,#0                                    @ raz key
    str r0,[r2]
1:
    ldr r0,iAdriEnd                              @ if signal ctrl-c  -> end
    ldr r0,[r0]
    cmp r0,#0
    bne 100f
    ldr r0,iAdrstPoll1                            @ address structure poll
    mov r1,#STDIN
    str r1,[r0,#poll_fd]                          @ maj FD
    mov r1,#POLLIN                                @ action code
    str r1,[r0,#poll_events]
    mov r1,#1                                     @ items number structure poll
    mov r2,#0                                     @ timeout = 0
    mov r7,#SYSPOLL                               @ call system POLL
    svc #0
    cmp r0,#0                                     @ key pressed ?
    ble 1b                                        @ no key pressed -> loop
                                                  @ read key
    mov r0,#STDIN                                 @ File Descriptor
    ldr r1,iAdriTouche                            @ buffer address
    mov r2,#BUFSIZE                               @ buffer size
    mov r7,#READ                                  @ read key
    svc #0
    cmp r0,#0                                     @ error ?
    ble 98f
    ldr r2,iAdriTouche                            @ key address
    ldr r0,[r2]
    b 100f
98:                                               @ error display
    ldr r1,iAdrszMessErreur                       @ error message
    bl   displayError
100:
    pop {r1,r2,r7,lr}
    bx lr

/*********************************/
/* restaur terminal state        */
/*********************************/
restauTerm:
    push {r0,r1,r7,lr}
    mov r0,#STDIN                                 @ end then restaur begin state terminal
    mov r1,#TCSETS
    ldr r2,iAdrstOldtio
    mov r7,#IOCTL                                 @ call system
    svc #0
    cmp r0,#0
    beq 100f
    ldr r1,iAdrszMessErreur                       @ error message
    bl   displayError
100:
    pop {r1,r2,r7,lr}
    bx lr

iAdrsMessValeur:          .int sMessValeur
iAdrszMessErreur:         .int szMessErreur
iAdrszCarriageReturn:     .int szCarriageReturn
iAdrstOldtio:             .int stOldtio
iAdrstCurtio:             .int stCurtio
iAdrstSigAction:          .int stSigAction
iAdrstSigAction1:         .int stSigAction1
iAdrszMessPgmOk:          .int szMessPgmOk
iAdrsMessResult:          .int sMessResult
iAdrSIG_IGN:              .int 1
iAdriEnd:                 .int iEnd
iAdrstPoll1:              .int stPoll1
iAdriTouche:              .int iTouche

/******************************************************************/
/*     signal processing                                     */
/******************************************************************/
sighandler:
    push {r0,r1}
    ldr r0,iAdriEnd
    mov r1,#1                 @ maj zone end
    str r1,[r0]
    pop {r0,r1}
    bx lr
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


# syntax: TAWK -f KEYBOARD_INPUT_FLUSH_THE_KEYBOARD_BUFFER.AWK
BEGIN {
    while (kbhit()) {
      getkey()
    }
    exit(0)
}


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

int main(int argc, char* argv[])
{
    // Get a chance to make stdin input buffer dirty.
    //
    char text[256];
    getchar();

    // This DOES NOT WORK properly on all modern systems including Linux & W10.
    // Obsolete, don't use this. BTW, there is no fpurge in MSVC libs in 2020.
    //
    // fflush(stdin);

    // Always works. Readed characters may remain somethere in RAM.
    //
    fseek(stdin, 0, SEEK_END);

    // A very dirty solution - an unbuffered stream does not need any flushing.
    //
    // setvbuf(stdin, NULL, _IONBF, 0);

    // Now we are able to check if the buffer is really empty.
    //
    fgets(text, sizeof(text), stdin);
    puts(text);

    return EXIT_SUCCESS;
}


extern (C) {
    void _STI_conio();
    void _STD_conio();
    int kbhit();
    int getch();
}

void main() {
    void flushKB() {
        while (kbhit()) getch();
    }

    _STI_conio();

    flushKB();

    _STD_conio();
}


$ wait 0::10  ! gives us 10 seconds to get keystrokes into the type-ahead buffer
$ on control_y then $ goto clean
$ set terminal /noecho
$ loop: read /prompt="" /time=0 sys$command /error=clean buffer
$ goto loop
$ clean:
$ set terminal /echo


program Flush_the_keyboard_buffer;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows;

var
  StdIn: THandle;

begin
  StdIn := GetStdHandle(STD_INPUT_HANDLE);
  Writeln('Press any key you want, they will be erased:');
  Sleep(5000);
  FlushConsoleInputBuffer(StdIn);
  Writeln('Now press any key you want, they will NOT be erased:');
  readln;
end.


' FB 1.05.0 Win64

' Get characters from the keyboard buffer until there are none left
While Inkey <> "" : Wend
Print "Keyboard buffer flushed"
Sleep


package main

import (
    "log"

    gc "code.google.com/p/goncurses"
)

func main() {
    _, err := gc.Init()
    if err != nil {
        log.Fatal("init:", err)
    }
    defer gc.End()
    gc.FlushInput()
}


import Control.Concurrent (threadDelay)
import Control.Monad (when)
import System.IO (hFlush, stdout)
import System.Posix

-- If the file descriptor is associated with a terminal, then flush its input,
-- otherwise do nothing.
termFlush :: Fd -> IO ()
termFlush fd = do
  isTerm <- queryTerminal fd
  when isTerm $ discardData fd InputQueue

main :: IO ()
main = do
  putStrLn "Type some stuff...\n"
  threadDelay $ 3 * 1000000
  putStrLn "\n\nOk, stop typing!\n"
  threadDelay $ 2 * 1000000

  termFlush stdInput

  putStr "\n\nType a line of text, ending with a newline: "
  hFlush stdout
  line <- getLine
  putStrLn $ "You typed: " ++ line
  termFlush stdInput


procedure flushKB()
    while kbhit() do getch()   # flush input
end


using Gtk

function flush_keyboard()
    win = GtkWindow("", 1, 1)
    keyget(w, event) = Int32(0)
    signal_connect(keyget, win, "key-press-event")
    visible(win, false)
    sleep(0.25)
end


// version 1.0.6

fun main(args: Array<String>) {
    while (System.`in`.available() > 0) System.`in`.read()
    println("Goodbye!")
}


Module Checkit {
      \\ feed keyboard
      Keyboard "abcd"
      \\ Work in Windows not in Linux (no Osk.exe exist)
      \\ no error return in linux
      Keyboard !  'open virtual keyboard
      Wait 3000
      \\ flush keyboard
      \\ we can use Do or Repeat (is the same)
      Repeat {
            a$=inkey$
            if a$="" then Print :exit
            Print a$;
      } Always
}
Checkit


const TCIFLUSH: cint = 0
proc tcflush(fd, queue_selector: cint): cint {.header: "termios.h".}

discard tcflush(cint(getFileHandle(stdin)), TCIFLUSH)


use Term::ReadKey;
ReadMode 'restore';    # Flush the keyboard and returns input stream to initial state
# ReadMode 0;            # Numerical equivalent of keyboard restore (move comment marker to use instead)

# A more complete example for use in keyboard handler programming.
# We should also check we are being used in an interactive context (not done here).

use Term::ReadKey;
ReadMode 'cbreak';

# Flush the keyboard in terminal character break mode
while (defined ReadKey -1) {
  # Do nothing
}

# Don't forget to restore the readmode, when we are finished using the keyboard
ReadMode 'restore';


while ($Host.UI.RawUI.KeyAvailable) {
    $Host.UI.RawUI.ReadKey() | Out-Null
}


def flush_input():
    try:
        import msvcrt
        while msvcrt.kbhit():
            msvcrt.getch()
    except ImportError:
        import sys, termios
        termios.tcflush(sys.stdin, termios.TCIOFLUSH)


#lang racket
(define-syntax-rule (with-raw body ...)
  (let ([saved #f])
    (define (stty x) (system (~a "stty " x)) (void))
    (dynamic-wind (λ() (set! saved (with-output-to-string (λ() (stty "-g"))))
                       (stty "raw -echo opost"))
                  (λ() body ...)
                  (λ() (stty saved)))))

(with-raw
  (printf "Keys pressed from now will be ignored\n")
  (sleep 2)
  (let loop () (when (char-ready?) (read-char) (loop))) ; flush input
  (printf "Now press a key which will not be ignored\n")
  (printf "You pressed ~a\n" (read-char)))


use Term::termios;

constant $saved   = Term::termios.new( :fd($*IN.native-descriptor) ).getattr;
constant $termios = Term::termios.new( :fd($*IN.native-descriptor) ).getattr;

# set some modified input flags
$termios.unset_iflags(<BRKINT ICRNL ISTRIP IXON>);
$termios.unset_lflags(< ECHO ICANON IEXTEN>);
$termios.setattr(:DRAIN);

# reset terminal to original settings on exit
END { $saved.setattr(:NOW) }

# Sleep for a few seconds to give you time to fill the input buffer,
# type a bunch of random characters.
sleep 2;

# ------- The actual task --------
# Flush the input buffer

$termios.setattr(:FLUSH);

# --------------------------------

# Ctrl-C to exit
loop {
    # Read up to 5 bytes from STDIN
    # F5 through F12 are 5 bytes each
    my $keypress = $*IN.read: 5;
    # print the ordinals of the keypress character
    print $keypress.decode.ords;
    print "|";
}


# Project: Keyboard input/Flush the keyboard buffer

Fflush(stdin)


while keypressed(KEYBOARD) do
  ignore(getc(KEYBOARD));
end while;


var k = frequire('Term::ReadKey');

k.ReadMode('restore');    # Flush the keyboard and returns input stream to initial state
# ReadMode 0;             # Numerical equivalent of keyboard restore (move comment marker to use instead)

# A more complete example for use in keyboard handler programming.
# We should also check we are being used in an interactive context (not done here).

k.ReadMode('cbreak');

# Flush the keyboard in terminal character break mode
while (k.ReadKey(-1) != nil) {
   # Do nothing
}

# Don't forget to restore the readmode, when we are finished using the keyboard
k.ReadMode('restore');


# No waiting for input
fconfigure stdin -blocking 0
# Drain the data by not saving it anywhere
read stdin

# Flip back into blocking mode (if necessary)
fconfigure stdin -blocking 1


import "io" for Stdin

System.print("Press some keys followed by enter.")
while (true) {
   var b = Stdin.readByte() // reads and removes a key from the buffer
   System.print("Removed key with code %(b).")
   if (b == 10) break      // buffer will be empty when enter key pressed
}
System.print("Keyboard buffer is now empty.")


define sysLastKey $ff

main:
jsr getKeyPress
;put the rest of your program here.
jsr delay
jmp main

getKeyPress:
lda $ff
sta $00
rts

delay:
nop
nop
dex
bne delay
rts


Proc Main()
 Byte KEY,k=764
 KEY=K
Return


Ch : Character;
Available : Boolean;

Ada.Text_IO.Get_Immediate (Ch, Available);


#include <flow.h>

DEF-MAIN(argv, argc)
   BREAK-ON
   SET(c,0)
   WHILE (1)
       COND( KEY-PRESSED? )
            SCAN-CODE(c)
            BREAK-IF ( c ) IS-ESCAPE
       CEND
       PRNL( "CODE = ", c )
   WEND
   PRNL( "Last key pressed: ", c )
END


/* Programme assembleur ARM Raspberry */
/* Assembleur ARM Raspberry  : Vincent Leboulou */
/* Blog : http://assembleurarmpi.blogspot.fr/  */
/* modèle B 512MO   */

/************************************/
/* Constantes                       */
/************************************/
.equ STDIN,     0     @ Linux input console
.equ STDOUT,    1     @ Linux output console
.equ EXIT,      1     @ Linux syscall
.equ READ,      3     @ Linux syscall
.equ WRITE,     4     @ Linux syscall
.equ IOCTL,     0x36  @ Linux syscall
.equ SIGACTION, 0x43  @ Linux syscall
.equ SYSPOLL,   0xA8  @ Linux syscall

.equ TCGETS,    0x5401
.equ TCSETS,    0x5402
.equ ICANON,    2
.equ ECHO,     10
.equ POLLIN,    1

.equ SIGINT,   2    @ Issued if the user sends an interrupt signal (Ctrl + C)
.equ SIGQUIT,  3    @ Issued if the user sends a quit signal (Ctrl + D)
.equ SIGTERM, 15    @ Software termination signal (sent by kill by default)
.equ SIGTTOU, 22    @

.equ TAILLEBUFFER,   10

/*******************************************/
/* Structures                               */
/********************************************/
/* structure termios see doc linux*/
    .struct  0
term_c_iflag:                    @ input modes
    .struct  term_c_iflag + 4
term_c_oflag:                    @ output modes
    .struct  term_c_oflag + 4
term_c_cflag:                    @ control modes
    .struct  term_c_cflag + 4
term_c_lflag:                    @ local modes
    .struct  term_c_lflag + 4
term_c_cc:                       @ special characters
    .struct  term_c_cc + 20      @ see length if necessary
term_fin:

/* structure sigaction see doc linux */
    .struct  0
sa_handler:
    .struct  sa_handler + 4
sa_mask:
    .struct  sa_mask + 4
sa_flags:
    .struct  sa_flags + 4
sa_sigaction:
    .struct  sa_sigaction + 4
sa_fin:

/* structure poll see doc linux */
    .struct  0
poll_fd:                            @   File Descriptor
    .struct  poll_fd + 4
poll_events:                        @  events mask
    .struct  poll_events + 4
poll_revents:                       @ events returned
    .struct  poll_revents + 4
poll_fin:

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessPgmOk:        .asciz "End program OK.\n"
szMessErreur:       .asciz "Error detected.\n"
sMessResult:        .ascii "Value  : "
sMessValeur:        .fill 11, 1, ' '            @ size => 11
szCarriageReturn:   .asciz "\n"
/*************************************************/
szMessErr: .ascii	"Error code hexa : "
sHexa: .space 9,' '
         .ascii "  decimal :  "
sDeci: .space 15,' '
         .asciz "\n"
szMessKey:             .ascii  "Value key ==>"
sHexaKey: .space 9,' '
        .asciz "\n"
.align 4

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
iEnd:           .skip 4                        @ 0 loop  1 = end loop
iTouche:        .skip 4                        @ value key pressed
stOldtio:       .skip term_fin                 @ old terminal state
stCurtio:       .skip term_fin                 @ current terminal state
stSigAction:    .skip sa_fin                   @ area signal structure
stSigAction1:   .skip sa_fin
stPoll1:        .skip poll_fin                 @ area poll structure
stPoll2:        .skip poll_fin

/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                            @ entry of program

    /* read terminal state */
    mov r0,#STDIN                                @ input console
    mov r1,#TCGETS
    ldr r2,iAdrstOldtio
    mov r7, #IOCTL                               @ call system Linux
    svc #0
    cmp r0,#0                                    @ error ?
    beq 1f
    ldr r1,iAdrszMessErreur                      @ error message
    bl   displayError
    b 100f
1:
    adr r0,sighandler                            @ adresse routine traitement signal
    ldr r1,iAdrstSigAction                       @ adresse structure sigaction
    str r0,[r1,#sa_handler]                      @ maj handler
    mov r0,#SIGINT                               @ signal type
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ call system
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r0,#SIGQUIT
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ call system
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r0,#SIGTERM
    ldr r1,iAdrstSigAction
    mov r2,#0                                    @ NULL
    mov r7, #SIGACTION                           @ appel systeme
    svc #0
    cmp r0,#0
    bne 98f
    @
    adr r0,iAdrSIG_IGN                           @ address signal igonre function
    ldr r1,iAdrstSigAction1
    str r0,[r1,#sa_handler]
    mov r0,#SIGTTOU                              @invalidate other process signal
    ldr r1,iAdrstSigAction1
    mov r2,#0                                    @ NULL
    mov r7,#SIGACTION                            @ call system
    svc #0
    cmp r0,#0
    bne 98f
    @
    /* read terminal current state  */
    mov r0,#STDIN
    mov r1,#TCGETS
    ldr r2,iAdrstCurtio                          @ address current termio
    mov r7,#IOCTL                                @ call systeme
    svc #0
    cmp r0,#0                                    @ error ?
    bne 98f
    mov r2,#ICANON | ECHO                        @ no key pressed echo on display
    mvn r2,r2                                    @ and one key
    ldr r1,iAdrstCurtio
    ldr r3,[r1,#term_c_lflag]
    and r3,r2                                    @ add flags
    str r3,[r1,#term_c_lflag]                    @ and store
    mov r0,#STDIN                                @ maj terminal current state
    mov r1,#TCSETS
    ldr r2,iAdrstCurtio
    mov r7, #IOCTL                               @ call system
    svc #0
    cmp r0,#0
    bne 98f
    @
2:                                               @ loop waiting key
    ldr r0,iAdriEnd                              @ if signal ctrl-c  -> end
    ldr r0,[r0]
    cmp r0,#0
    bne 3f
    ldr r0,iAdrstPoll1                            @ address structure poll
    mov r1,#STDIN
    str r1,[r0,#poll_fd]                          @ maj FD
    mov r1,#POLLIN                                @ action code
    str r1,[r0,#poll_events]
    mov r1,#1                                     @ items number structure poll
    mov r2,#0                                     @ timeout = 0
    mov r7,#SYSPOLL                               @ call system POLL
    svc #0
    cmp r0,#0                                     @ key pressed ?
    ble 2b                                        @ no key pressed -> loop
                                                  @ read key
    mov r0,#STDIN                                 @ File Descriptor
    ldr r1,iAdriTouche                            @ buffer address
    mov r2,#TAILLEBUFFER                          @ buffer size
    mov r7,#READ                                  @ read key
    svc #0
    cmp r0,#0                                     @ error ?
    ble 98f
    ldr r2,iAdriTouche                            @ key address
    ldr r0,[r2]
    ldr r1,iAdrsHexaKey
    bl conversion16                               @ conversion hexa
    ldr r0,iAdrszMessKey                          @ display key value in hexa
    bl affichageMess
    ldrb r0,[r2]                                  @ key value
    cmp r0,#113                                   @ saisie q ?
    beq 3f
    cmp r0,#81                                    @ saisie Q ?
    beq 3f
    mov r0,#0
    str r0,[r2]                                   @ raz key area
    b 2b                                          @ loop

3:                                                @ end loop display Ok message
    ldr r0,iAdrszMessPgmOk
    bl affichageMess
    b 99f
98:                                               @ error display
    ldr r1,iAdrszMessErreur                       @ error message
    bl   displayError
99:                                               @ end then restaur begin state terminal
    mov r0,#STDIN
    mov r1,#TCSETS
    ldr r2,iAdrstOldtio
    mov r7,#IOCTL                                 @ call system
    svc #0
    cmp r0,#0
    beq 100f
    ldr r1,iAdrszMessErreur                       @ error message
    bl   displayError

100:                                              @ standard end of the program
    mov r0, #0                                    @ return code
    mov r7, #EXIT                                 @ request to exit program
    svc #0                                        @ perform the system call

iAdrsMessValeur:          .int sMessValeur
iAdrszMessErreur:         .int szMessErreur
iAdrszCarriageReturn:     .int szCarriageReturn
iAdrstOldtio:             .int stOldtio
iAdrstCurtio:             .int stCurtio
iAdrstSigAction:          .int stSigAction
iAdrstSigAction1:         .int stSigAction1
iAdrszMessPgmOk:          .int szMessPgmOk
iAdrsMessResult:          .int sMessResult
iAdrSIG_IGN:              .int 1
iAdriEnd:                 .int iEnd
iAdrstPoll1:              .int stPoll1
iAdriTouche:              .int iTouche
iAdrszMessKey:            .int szMessKey
iAdrsHexaKey:             .int sHexaKey
/******************************************************************/
/*     traitement du signal                                       */
/******************************************************************/
/* r0 contains  */
sighandler:
    push {r0,r1}
    ldr r0,iAdriEnd
    mov r1,#1                 @ maj zone end
    str r1,[r0]
    pop {r0,r1}
    bx lr
/***************************************************/
/*   display error message                         */
/***************************************************/
/* r0 contains error code  r1 : message address */
displayError:
    push {r0-r2,lr}                            @ save registers
    mov r2,r0                               @ save error code
    mov r0,r1
    bl affichageMess
    mov r0,r2                               @ error code
    ldr r1,iAdrsHexa
    bl conversion16                         @ conversion hexa
    mov r0,r2                               @ error code
    ldr r1,iAdrsDeci                        @ result address
    bl conversion10                         @ conversion decimale
    ldr r0,iAdrszMessErr                    @ display error message
    bl affichageMess
100:
    pop {r0-r2,lr}                             @ restaur registers
    bx lr                                   @ return
iAdrszMessErr:                 .int szMessErr
iAdrsHexa:                     .int sHexa
iAdrsDeci:                     .int sDeci
/******************************************************************/
/*     display text with size calculation                         */
/******************************************************************/
/* r0 contains the address of the message */
affichageMess:
    push {r0,r1,r2,r7,lr}                          @ save  registres
    mov r2,#0                                      @ counter length
1:                                                 @ loop length calculation
    ldrb r1,[r0,r2]                                @ read octet start position + index
    cmp r1,#0                                      @ if 0 its over
    addne r2,r2,#1                                 @ else add 1 in the length
    bne 1b                                         @ and loop
                                                   @ so here r2 contains the length of the message
    mov r1,r0                                      @ address message in r1
    mov r0,#STDOUT                                 @ code to write to the standard output Linux
    mov r7, #WRITE                                 @ code call system "write"
    svc #0                                         @ call systeme
    pop {r0,r1,r2,r7,lr}                           @ restaur registers
    bx lr                                          @ return
/******************************************************************/
/*     Converting a register to a decimal unsigned                */
/******************************************************************/
/* r0 contains value and r1 address area   */
/* r0 return size of result (no zero final in area) */
/* area size => 11 bytes          */
.equ LGZONECAL,   10
conversion10:
    push {r1-r4,lr}                                 @ save registers
    mov r3,r1
    mov r2,#LGZONECAL

1:                                                  @ start loop
    bl divisionpar10U                               @ unsigned  r0 <- dividende. quotient ->r0 reste -> r1
    add r1,#48                                      @ digit
    strb r1,[r3,r2]                                 @ store digit on area
    cmp r0,#0                                       @ stop if quotient = 0
    subne r2,#1                                     @ else previous position
    bne 1b                                          @ and loop
                                                    @ and move digit from left of area
    mov r4,#0
2:
    ldrb r1,[r3,r2]
    strb r1,[r3,r4]
    add r2,#1
    add r4,#1
    cmp r2,#LGZONECAL
    ble 2b
                                                      @ and move spaces in end on area
    mov r0,r4                                         @ result length
    mov r1,#' '                                       @ space
3:
    strb r1,[r3,r4]                                   @ store space in area
    add r4,#1                                         @ next position
    cmp r4,#LGZONECAL
    ble 3b                                            @ loop if r4 <= area size

100:
    pop {r1-r4,lr}                                    @ restaur registres
    bx lr                                             @return

/***************************************************/
/*   division par 10   unsigned                    */
/***************************************************/
/* r0 dividende   */
/* r0 quotient */
/* r1 remainder  */
divisionpar10U:
    push {r2,r3,r4, lr}
    mov r4,r0                                          @ save value
    //mov r3,#0xCCCD                                   @ r3 <- magic_number lower  raspberry 3
    //movt r3,#0xCCCC                                  @ r3 <- magic_number higter raspberry 3
    ldr r3,iMagicNumber                                @ r3 <- magic_number    raspberry 1 2
    umull r1, r2, r3, r0                               @ r1<- Lower32Bits(r1*r0) r2<- Upper32Bits(r1*r0)
    mov r0, r2, LSR #3                                 @ r2 <- r2 >> shift 3
    add r2,r0,r0, lsl #2                               @ r2 <- r0 * 5
    sub r1,r4,r2, lsl #1                               @ r1 <- r4 - (r2 * 2)  = r4 - (r0 * 10)
    pop {r2,r3,r4,lr}
    bx lr                                              @ leave function
iMagicNumber:  	.int 0xCCCCCCCD
/******************************************************************/
/*     Converting a register to hexadecimal                      */
/******************************************************************/
/* r0 contains value and r1 address area   */
conversion16:
    push {r1-r4,lr}                                    @ save registers
    mov r2,#28                                         @ start bit position
    mov r4,#0xF0000000                                 @ mask
    mov r3,r0                                          @ save entry value
1:                                                     @ start loop
    and r0,r3,r4                                       @value register and mask
    lsr r0,r2                                          @ move right
    cmp r0,#10                                         @ compare value
    addlt r0,#48                                       @ <10  ->digit
    addge r0,#55                                       @ >10  ->letter A-F
    strb r0,[r1],#1                                    @ store digit on area and + 1 in area address
    lsr r4,#4                                          @ shift mask 4 positions
    subs r2,#4                                         @  counter bits - 4 <= zero  ?
    bge 1b                                             @  no -> loop

100:
    pop {r1-r4,lr}                                     @ restaur registers
    bx lr                                              @return


; Input [, OutputVar, Options, EndKeys, MatchList]
Input, KeyPressed, L1 T2    ; Length = 1, Timeout = 2 seconds


# syntax: TAWK -f KEYBOARD_INPUT_KEYPRESS_CHECK.AWK
BEGIN {
    arr["\b"] = "BACKSPACE"
    arr["\t"] = "TAB"
    arr["\x0D"] = "ENTER"
    printf("%s  Press any key; ESC to exit\n",ctime())
    while (1) {
      nkeys++
      key = getkey()
      if (key in arr) { key = arr[key] }
      space = ((length(key) > 1 && nkeys > 1) || length(p_key) > 1) ? " " : ""
      keys = keys space key
      if (key == "ESC") { break }
      p_key = key
    }
    printf("%s  %d keys were pressed\n",ctime(),nkeys)
    printf("%s\n",keys)
    exit(0)
}


#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

void set_mode(int want_key)
{
	static struct termios old, new;
	if (!want_key) {
		tcsetattr(STDIN_FILENO, TCSANOW, &old);
		return;
	}

	tcgetattr(STDIN_FILENO, &old);
	new = old;
	new.c_lflag &= ~(ICANON | ECHO);
	tcsetattr(STDIN_FILENO, TCSANOW, &new);
}

int get_key()
{
	int c = 0;
	struct timeval tv;
	fd_set fs;
	tv.tv_usec = tv.tv_sec = 0;

	FD_ZERO(&fs);
	FD_SET(STDIN_FILENO, &fs);
	select(STDIN_FILENO + 1, &fs, 0, 0, &tv);

	if (FD_ISSET(STDIN_FILENO, &fs)) {
		c = getchar();
		set_mode(0);
	}
	return c;
}

int main()
{
	int c;
	while(1) {
		set_mode(1);
		while (!(c = get_key())) usleep(10000);
		printf("key %d\n", c);
	}
}


(defun keypress-check ()
  (with-screen (scr :input-echoing nil :input-blocking nil :input-buffering nil :enable-function-keys t)
    (loop
      ;; Determine if a key has been pressed ...
      (if (key-pressed-p scr)
          ;; ... and store this in a variable.
          (let ((ch (get-char scr)))
            ;; exit the loop by pressing q.
            (if (eql (code-char ch) #\q)
                (return)
                (princ (code-char ch) scr)))
          (progn
            ;; If no key has been pressed, the program should continue without waiting.
            (princ #\. scr)
            (refresh scr)
            ;; we wait anyway to spare the CPU.
            (sleep 0.15))))))


string chr = string.Empty;
if(Console.KeyAvailable)
  chr = Console.ReadKey().Key.ToString();


extern (C) {
    void _STI_conio();
    void _STD_conio();
    int kbhit();
    int getch();
}

void main() {
    _STI_conio();

    char c;
    if (kbhit())
        c = cast(char)getch();

    _STD_conio();
}


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    SavedPressedKey: Char;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  SavedPressedKey := Key;
end;

end.


import extensions;

public program()
{
    auto chr := emptyString;
    if (console.KeyAvailable)
    {
        chr := console.readChar()
    }
}


integer key
key = get_key() -- if key was not pressed get_key() returns -1


open System;

let chr = if Console.KeyAvailable then Console.ReadKey().Key.ToString() else String.Empty


variable last-key
: check   key? if key last-key ! then ;


' FB 1.05.0 Win64

Dim k As String
Do
  k = Inkey
Loop Until k <> ""

If Len(k) = 1 Then
  Print "The key pressed was "; k; " (ascii "; Asc(k); ")"
Else
  Print "An extended key was pressed"
End If

Sleep


Public Sub Form_KeyPress()

'Requires a TextBox or similar on the Form to work
Print Key.Text;

End


package main

import (
    "log"
    "time"

    gc "code.google.com/p/goncurses"
)

func main() {
    s, err := gc.Init()
    if err != nil {
        log.Fatal("init:", err)
    }
    defer gc.End()
    gc.Cursor(0)
    s.Move(20, 0)
    s.Print("Key check in ")
    for i := 3; i >= 1; i-- {
        s.MovePrint(20, 13, i)
        s.Refresh()
        time.Sleep(500 * time.Millisecond)
    }


import Control.Concurrent
import Control.Monad
import Data.Maybe
import System.IO

main = do
    c <- newEmptyMVar
    hSetBuffering stdin NoBuffering
    forkIO $ do
      a <- getChar
      putMVar c a
      putStrLn $ "\nChar '" ++ [a] ++
                 "' read and stored in MVar"
    wait c
  where wait c = do
          a <- tryTakeMVar c
          if isJust a then return ()
          else putStrLn "Awaiting char.." >>
               threadDelay 500000 >> wait c


procedure main()
   delay(1000)                              # give user a chance to input
   if kbhit() then                          # test for input
      write("You entered ",x := getch())    # read w/o echo
   else                                     # use getche for echo
      write("No input waiting")
end


import java.awt.event.*;
import javax.swing.*;

public class Test extends JFrame {

    Test() {
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode();
                System.out.println(keyCode);
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Test f = new Test();
            f.setFocusable(true);
            f.setVisible(true);
        });
    }
}


let thePressedKey;

function handleKey(evt) {
  thePressedKey = evt;
  console.log(thePressedKey);
}

document.addEventListener('keydown', handleKey);


using Gtk

function keypresswindow()
    tcount = 0
    txt = "Press a Key"
    win = GtkWindow("Keypress Test", 500, 30) |> (GtkFrame() |> ((vbox = GtkBox(:v)) |> (lab = GtkLabel(txt))))
    function keycall(w, event)
        ch = Char(event.keyval)
        tcount += 1
        set_gtk_property!(lab, :label, "You have typed $tcount chars including $ch this time")
    end
    signal_connect(keycall, win, "key-press-event")

    cond = Condition()
    endit(w) = notify(cond)
    signal_connect(endit, win, :destroy)
    showall(win)
    wait(cond)
end

keypresswindow()


// version 1.1

import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import javax.swing.JFrame
import javax.swing.SwingUtilities

class Test : JFrame() {
    init {
        println("Press any key to see its code or 'enter' to quit\n")
        addKeyListener(object : KeyAdapter() {
            override fun keyPressed(e: KeyEvent) {
                if (e.keyCode == KeyEvent.VK_ENTER) {
                    isVisible = false
                   dispose()
                   System.exit(0)
                }
                else
                   println(e.keyCode)
            }
        })
    }
}

fun main(args: Array<String>) {
    SwingUtilities.invokeLater {
        val f = Test()
        f.isFocusable = true
        f.isVisible = true
    }
}


-- in some movie script

-- event handler
on keyDown
  pressedKey = _key.key
  put "A key was pressed:" && pressedKey
end


repeat 100 times
-- exit loop if "." or the escapeKey is pressed
    if 46 is in the keysDown or 65307 is in the keysdown then
        answer "exiting"
        exit repeat
    else
        -- do stuff
        wait 200 millisec
    end if
end repeat


i = {};
EventHandler[Panel[Dynamic[i],
  ImageSize -> {300, 300}], {"KeyDown" :>
   AppendTo[i, CurrentValue["EventKey"]]}]


import os, illwill

illwillInit(fullscreen=false)

while true:
  var key = getKey()
  case key
  of Key.None:
    echo "not received a key, I can do other stuff here"
  of Key.Escape, Key.Q:
    break
  else:
    echo "Key pressed: ", $key

  sleep(1000)


import: console

: checkKey
| key |
   System.Console receiveTimeout(2000000) ->key   // Wait a key pressed for 2 seconds
   key ifNotNull: [ System.Out "Key pressed : " << key << cr ]
   "Done" println ;


#!/usr/bin/perl
use strict;
use warnings;
use Term::ReadKey;
ReadMode 4;
my $key;
until(defined($key = ReadKey(-1))){
	# anything
	sleep 1;
}
print "got key '$key'\n";
ReadMode('restore');


integer key = get_key() -- if key was not pressed get_key() returns -1


To run:
Start up.
Handle any events.
Shut down.

To handle any events:
Deque an event.
If the event is nil, exit.
Handle the event.
Repeat.

To handle an event:
If the event's kind is "key down", handle the event (key down).

To handle an event (key down):
Put the event's key into a key.
Write "" then the key to the console.
If the key is the escape key, relinquish control.


if ($Host.UI.RawUI.KeyAvailable) {
    $key = $Host.UI.RawUI.ReadKey()
}


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function

import tty, termios
import sys
if sys.version_info.major < 3:
    import thread as _thread
else:
    import _thread
import time

try:
    from msvcrt import getch  # try to import Windows version
except ImportError:
    def getch():   # define non-Windows version
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

def keypress():
    global char
    char = getch()

def main():
    global char
    char = None
    _thread.start_new_thread(keypress, ())

    while True:
        if char is not None:
            try:
                print("Key pressed is " + char.decode('utf-8'))
            except UnicodeDecodeError:
                print("character can not be decoded, sorry!")
                char = None
            _thread.start_new_thread(keypress, ())
            if char == 'q' or char == '\x1b':  # x1b is ESC
                exit()
            char = None
        print("Program is running")
        time.sleep(1)

if __name__ == "__main__":
    main()


#lang racket
(define-syntax-rule (with-raw body ...)
  (let ([saved #f])
    (define (stty x) (system (~a "stty " x)) (void))
    (dynamic-wind (λ() (set! saved (with-output-to-string (λ() (stty "-g"))))
                       (stty "raw -echo opost"))
                  (λ() body ...)
                  (λ() (stty saved)))))

(with-raw
  (printf "Press a key, or not\n")
  (sleep 2)
  (if (char-ready?)
    (printf "You pressed ~a\n" (read-char))
    (printf "You didn't press a key\n")))


use Term::ReadKey;

react {
    whenever key-pressed(:!echo) {
        given .fc {
            when 'q' { done }
            default { .uniname.say }
        }
    }
}


/*REXX program demonstrates if any key has been presssed.               */

  ∙
  ∙
  ∙
somechar=inkey('nowait')
  ∙
  ∙
  ∙


if getchar() see "A key was pressed" + nl
else see "No key was pressed" + nl ok


: "loop"
if "KEY_PRESSED" != 0 then "#store"
* "Last key pressed: &storedKey&"
goto "loop"

: "#store"
set "storedKey" to "KEY_PRESSED"
goto "#return"


begin
  check = STDIN.read_nonblock(1)
rescue IO::WaitReadable
  check = false
end

puts check if check


import java.awt.event.{KeyAdapter, KeyEvent}

import javax.swing.{JFrame, SwingUtilities}

class KeypressCheck() extends JFrame {

  addKeyListener(new KeyAdapter() {
    override def keyPressed(e: KeyEvent): Unit = {
      val keyCode = e.getKeyCode
      if (keyCode == KeyEvent.VK_ENTER) {
        dispose()
        System.exit(0)
      }
      else
        println(keyCode)
    }
  })
}

object KeypressCheck extends App {
  println("Press any key to see its code or 'enter' to quit\n")
  SwingUtilities.invokeLater(() => {
    def foo() = {
      val f = new KeypressCheck
      f.setFocusable(true)
      f.setVisible(true)
      f.setSize(200, 200)
      f.setEnabled(true)
    }

    foo()
  })
}


if keypressed(KEYBOARD) then
  writeln("A key was pressed");
else
  writeln("No key was pressed");
end if;


fconfigure stdin -blocking 0
set ch [read stdin 1]
fconfigure stdin -blocking 1

if {$ch eq ""} {
    # Nothing was read
} else {
    # Got the character $ch
}


let keycode=0
print 1 "Press any key and its key code will appear."
while keycode=0
let keycode=key()
wend
print 1 keycode
end


import "scheduler" for Scheduler
import "timer" for Timer
import "io" for Stdin, Stdout

Stdin.isRaw = true // no echoing or buffering

var b

Scheduler.add {
    b = Stdin.readByte()
}

System.print("Awaiting keypress..")
Timer.sleep(2000) // allow 2 seconds say
if (b) {
    System.write("The key with code %(b) was pressed")
    System.print((b > 31 && b < 127) ? " namely '%(String.fromByte(b))'." : ".")
} else {
    System.print("No key was pressed, carrying on...")
}

Stdin.isRaw = false


include c:\cxpl\codes;  \intrinsic 'code' declarations
int K, N;
[N:= 0;
repeat  K:= KeyHit;     \counts up until a key is pressed
        IntOut(0, N);  ChOut(0, ^ );
        N:= N+1;
until   K;
]


V items = [
   ‘sandwich’     = (50, 60, 2),
   ‘map’          = (9, 150, 1),
   ‘compass’      = (13, 35, 1),
   ‘water’        = (153, 200, 3),
   ‘glucose’      = (15, 60, 2),
   ‘tin’          = (68, 45, 3),
   ‘banana’       = (27, 60, 3),
   ‘apple’        = (39, 40, 3),
   ‘cheese’       = (23, 30, 1),
   ‘beer’         = (52, 10, 3),
   ‘suntan cream’ = (11, 70, 1),
   ‘camera’       = (32, 30, 1),
   ‘t-shirt’      = (24, 15, 2),
   ‘trousers’     = (48, 10, 2),
   ‘umbrella’     = (73, 40, 1),
   ‘w-trousers’   = (42, 70, 1),
   ‘w-overcoat’   = (43, 75, 1),
   ‘note-case’    = (22, 80, 1),
   ‘sunglasses’   = (7, 20, 1),
   ‘towel’        = (18, 12, 2),
   ‘socks’        = (4, 50, 1),
   ‘book’         = (30, 10, 2)
]

V item_keys = items.keys()

[(Int, Int) = (Int, [(Int, String)])] cache

F choose_item(weight, idx)
   [(Int, String)] best_list
   I idx < 0
      R (0, best_list)
   V k = (weight, idx)
   V? c = :cache.find(k)
   I c != N
      R c
   V name = :item_keys[idx]
   V (w, v, qty) = :items[name]
   V best_v = 0

   L(i) 0..qty
      V wlim = weight - i * w
      I wlim < 0
         L.break
      V (val, taken) = choose_item(wlim, idx - 1)
      I val + i * v > best_v
         best_v = val + i * v
         best_list = copy(taken)
         best_list.append((i, name))
   :cache[k] = (best_v, best_list)
   R (best_v, best_list)

V (v, lst) = choose_item(400, items.len - 1)
V w = 0
L(cnt, name) lst
   I cnt > 0
      print(cnt‘ ’name)
      w += items[name][0] * cnt

print(‘Total weight: ’w‘ Value: ’v)


Item = map,compass,water,sandwich,glucose,tin,banana,apple,cheese,beer,suntan cream
      ,camera,tshirt,trousers,umbrella,waterproof trousers,waterproof overclothes,notecase
      ,sunglasses,towel,socks,book
Weight= 9,13,153,50,15,68,27,39,23,52,11,32,24,48,73,42,43,22,7,18,4,30
Value = 150,35,200,60,60,45,60,40,30,10,70,30,15,10,40,70,75,80,20,12,50,10
Bound = 1,1,2,2,2,3,3,3,1,3,1,1,2,2,1,1,1,1,1,2,1,2

StringSplit I, Item,  `, ; Put input in arrays
StringSplit W, Weight,`,
StringSplit V, Value, `,
StringSplit B, Bound, `,

W := 400, N := I0, I0 := V0 := W0 := 0 ; W = total weight allowed, maximize total value
Loop %W%
   m0_%A_Index% := 0

Loop %N% { ; build achievable value matrix m [ N rows, W columns ]
   j := -1+i := A_Index,  m%j%_0 := 0 ; m[i,P] = max value with items 1..i, weight <=P
   Loop %W% {                         ; m[i,P] = max_k {m[i-1,P-k*Wi]}
      p := A_Index, k := 0, y := m%j%_%p%
      While ++k <= B%i% && (r := p - k*W%i%) >= 0
         y := y < (c:=m%j%_%r%+k*V%i%) ? c : y
      m%i%_%p% := y
   }
}

i := 1+j := N, p := W, s := 0
While --i, --j { ; read out solution from value matrix m
   If (m%i%_%p% = m%j%_%p%)
      Continue
   r := p, m := m%i%_%p%, k := 1
   While 0 <= (r-=W%i%)  &&  m%j%_%r% != (m-=V%i%)
      k++ ; find multiplier
   t := k " " I%i% "`n" t, s += k*W%i%, p -= k*W%i%
}

MsgBox % "Value = " m%N%_%W% "`nWeight = " s "`n`n" t


(knapsack=
  ( things
  =   (map.9.150.1)
      (compass.13.35.1)
      (water.153.200.2)
      (sandwich.50.60.2)
      (glucose.15.60.2)
      (tin.68.45.3)
      (banana.27.60.3)
      (apple.39.40.3)
      (cheese.23.30.1)
      (beer.52.10.3)
      (suntan cream.11.70.1)
      (camera.32.30.1)
      (T-shirt.24.15.2)
      (trousers.48.10.2)
      (umbrella.73.40.1)
      (waterproof trousers.42.70.1)
      (waterproof overclothes.43.75.1)
      (note-case.22.80.1)
      (sunglasses.7.20.1)
      (towel.18.12.2)
      (socks.4.50.1)
      (book.30.10.2)
  )
& 0:?maxvalue
& :?sack
& ( add
  =     cumwght
        cumvalue
        cumsack
        name
        wght
        val
        pcs
        tings
        n
        ncumwght
        ncumvalue
    .     !arg
        : ( ?cumwght
          . ?cumvalue
          . ?cumsack
          . (?name.?wght.?val.?pcs) ?tings
          )
      & -1:?n
      &   whl
        ' ( 1+!n:~>!pcs:?n
          & !cumwght+!n*!wght:~>400:?ncumwght
          & !cumvalue+!n*!val:?ncumvalue
          & (   !tings:
              & (   !ncumvalue:>!maxvalue:?maxvalue
                  &     !cumsack
                        ( !n:0&
                        | (!n.!name)
                        )
                    : ?sack
                |
                )
            |   add
              $ ( !ncumwght
                . !ncumvalue
                .   !cumsack
                    (!n:0&|(!n.!name))
                . !tings
                )
            )
          )
  )
& add$(0.0..!things)
& out$(!maxvalue.!sack)
);

!knapsack;


using System;  // [email protected]
class program
{
    static void Main()
    {
        knapSack(40);
        var sw = System.Diagnostics.Stopwatch.StartNew();
        Console.Write(knapSack(400) + "\n" + sw.Elapsed);  // 51 µs
        Console.Read();
    }

    static string knapSack(uint w1)
    {
        init(); change();
        uint n = (uint)w.Length; var K = new uint[n + 1, w1 + 1];
        for (uint vi, wi, w0, x, i = 0; i < n; i++)
            for (vi = v[i], wi = w[i], w0 = 1; w0 <= w1; w0++)
            {
                x = K[i, w0];
                if (wi <= w0) x = max(vi + K[i, w0 - wi], x);
                K[i + 1, w0] = x;
            }
        string str = "";
        for (uint v1 = K[n, w1]; v1 > 0; n--)
            if (v1 != K[n - 1, w1])
            {
                v1 -= v[n - 1]; w1 -= w[n - 1]; str += items[n - 1] + "\n";
            }
        return str;
    }

    static uint max(uint a, uint b) { return a > b ? a : b; }

    static byte[] w, v; static string[] items;

    static byte[] p = { 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2 };

    static void init()
    {
        w = new byte[] { 9, 13, 153, 50, 15, 68, 27, 39, 23, 52, 11,
                          32, 24, 48, 73, 42, 43, 22, 7, 18, 4, 30 };

        v = new byte[] { 150, 35, 200, 60, 60, 45, 60, 40, 30, 10, 70,
                          30, 15, 10, 40, 70, 75, 80, 20, 12, 50, 10 };

        items = new string[] {"map","compass","water","sandwich","glucose","tin",
                              "banana","apple","cheese","beer","suntan cream",
                              "camera","T-shirt","trousers","umbrella",
                              "waterproof trousers","waterproof overclothes",
                              "note-case","sunglasses","towel","socks","book"};
    }

    static void change()
    {
        int n = w.Length, s = 0, i, j, k; byte xi;
        for (i = 0; i < n; i++) s += p[i];
        {
            byte[] x = new byte[s];
            for (k = i = 0; i < n; i++)
                for (xi = w[i], j = p[i]; j > 0; j--) x[k++] = xi;
            w = x;
        }
        {
            byte[] x = new byte[s];
            for (k = i = 0; i < n; i++)
                for (xi = v[i], j = p[i]; j > 0; j--) x[k++] = xi;
            v = x;
        }
        string[] pItems = new string[s]; string itemI;
        for (k = i = 0; i < n; i++)
            for (itemI = items[i], j = p[i]; j > 0; j--) pItems[k++] = itemI;
        items = pItems;
    }
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <memory>
#include <sys/time.h>

using std::cout;
using std::endl;

class StopTimer
{
public:
    StopTimer(): begin_(getUsec()) {}
    unsigned long long getTime() const { return getUsec() - begin_; }
private:
    static unsigned long long getUsec()
    {//...you might want to use something else under Windows
        timeval tv;
        const int res = ::gettimeofday(&tv, 0);
        if(res)
            return 0;
        return tv.tv_usec + 1000000 * tv.tv_sec;
    }
    unsigned long long begin_;
};

struct KnapsackTask
{
    struct Item
    {
        std::string name;
        unsigned w, v, qty;
        Item(): w(), v(), qty() {}
        Item(const std::string& iname, unsigned iw, unsigned iv, unsigned iqty):
            name(iname), w(iw), v(iv), qty(iqty)
        {}
    };
    typedef std::vector<Item> Items;
    struct Solution
    {
        unsigned v, w;
        unsigned long long iterations, usec;
        std::vector<unsigned> n;
        Solution(): v(), w(), iterations(), usec() {}
    };
    //...
    KnapsackTask(): maxWeight_(), totalWeight_() {}
    void add(const Item& item)
    {
        const unsigned totalItemWeight = item.w * item.qty;
        if(const bool invalidItem = !totalItemWeight)
            throw std::logic_error("Invalid item: " + item.name);
        totalWeight_ += totalItemWeight;
        items_.push_back(item);
    }
    const Items& getItems() const { return items_; }
    void setMaxWeight(unsigned maxWeight) { maxWeight_ = maxWeight; }
    unsigned getMaxWeight() const { return std::min(totalWeight_, maxWeight_); }

private:
    unsigned maxWeight_, totalWeight_;
    Items items_;
};

class BoundedKnapsackRecursiveSolver
{
public:
    typedef KnapsackTask Task;
    typedef Task::Item Item;
    typedef Task::Items Items;
    typedef Task::Solution Solution;

    void solve(const Task& task)
    {
        Impl(task, solution_).solve();
    }
    const Solution& getSolution() const { return solution_; }
private:
    class Impl
    {
        struct Candidate
        {
            unsigned v, n;
            bool visited;
            Candidate(): v(), n(), visited(false) {}
        };
        typedef std::vector<Candidate> Cache;
    public:
        Impl(const Task& task, Solution& solution):
            items_(task.getItems()),
            maxWeight_(task.getMaxWeight()),
            maxColumnIndex_(task.getItems().size() - 1),
            solution_(solution),
            cache_(task.getMaxWeight() * task.getItems().size()),
            iterations_(0)
        {}
        void solve()
        {
            if(const bool nothingToSolve = !maxWeight_ || items_.empty())
                return;
            StopTimer timer;
            Candidate candidate;
            solve(candidate, maxWeight_, items_.size() - 1);
            convertToSolution(candidate);
            solution_.usec = timer.getTime();
        }
    private:
        void solve(Candidate& current, unsigned reminderWeight, const unsigned itemIndex)
        {
            ++iterations_;

            const Item& item(items_[itemIndex]);

            if(const bool firstColumn = !itemIndex)
            {
                const unsigned maxQty = std::min(item.qty, reminderWeight/item.w);
                current.v = item.v * maxQty;
                current.n = maxQty;
                current.visited = true;
            }
            else
            {
                const unsigned nextItemIndex = itemIndex - 1;
                {
                    Candidate& nextItem = cachedItem(reminderWeight, nextItemIndex);
                    if(!nextItem.visited)
                        solve(nextItem, reminderWeight, nextItemIndex);
                    current.visited = true;
                    current.v = nextItem.v;
                    current.n = 0;
                }
                if(reminderWeight >= item.w)
                {
                    for (unsigned numberOfItems = 1; numberOfItems <= item.qty; ++numberOfItems)
                    {
                        reminderWeight -= item.w;
                        Candidate& nextItem = cachedItem(reminderWeight, nextItemIndex);
                        if(!nextItem.visited)
                            solve(nextItem, reminderWeight, nextItemIndex);

                        const unsigned checkValue = nextItem.v + numberOfItems * item.v;
                        if ( checkValue > current.v)
                        {
                            current.v = checkValue;
                            current.n = numberOfItems;
                        }
                        if(!(reminderWeight >= item.w))
                            break;
                    }
                }
            }
        }
        void convertToSolution(const Candidate& candidate)
        {
            solution_.iterations = iterations_;
            solution_.v = candidate.v;
            solution_.n.resize(items_.size());

            const Candidate* iter = &candidate;
            unsigned weight = maxWeight_, itemIndex = items_.size() - 1;
            while(true)
            {
                const unsigned currentWeight = iter->n * items_[itemIndex].w;
                solution_.n[itemIndex] = iter->n;
                weight -= currentWeight;
                if(!itemIndex--)
                    break;
                iter = &cachedItem(weight, itemIndex);
            }
            solution_.w = maxWeight_ - weight;
        }
        Candidate& cachedItem(unsigned weight, unsigned itemIndex)
        {
            return cache_[weight * maxColumnIndex_ + itemIndex];
        }
        const Items& items_;
        const unsigned maxWeight_;
        const unsigned maxColumnIndex_;
        Solution& solution_;
        Cache cache_;
        unsigned long long iterations_;
    };
    Solution solution_;
};

void populateDataset(KnapsackTask& task)
{
    typedef KnapsackTask::Item Item;
    task.setMaxWeight( 400 );
    task.add(Item("map",9,150,1));
    task.add(Item("compass",13,35,1));
    task.add(Item("water",153,200,2));
    task.add(Item("sandwich",50,60,2));
    task.add(Item("glucose",15,60,2));
    task.add(Item("tin",68,45,3));
    task.add(Item("banana",27,60,3));
    task.add(Item("apple",39,40,3));
    task.add(Item("cheese",23,30,1));
    task.add(Item("beer",52,10,3));
    task.add(Item("suntancream",11,70,1));
    task.add(Item("camera",32,30,1));
    task.add(Item("T-shirt",24,15,2));
    task.add(Item("trousers",48,10,2));
    task.add(Item("umbrella",73,40,1));
    task.add(Item("w-trousers",42,70,1));
    task.add(Item("w-overclothes",43,75,1));
    task.add(Item("note-case",22,80,1));
    task.add(Item("sunglasses",7,20,1));
    task.add(Item("towel",18,12,2));
    task.add(Item("socks",4,50,1));
    task.add(Item("book",30,10,2));
}

int main()
{
    KnapsackTask task;
    populateDataset(task);

    BoundedKnapsackRecursiveSolver solver;
    solver.solve(task);
    const KnapsackTask::Solution& solution = solver.getSolution();

    cout << "Iterations to solve: " << solution.iterations << endl;
    cout << "Time to solve: " << solution.usec << " usec" << endl;
    cout << "Solution:" << endl;
    for (unsigned i = 0; i < solution.n.size(); ++i)
    {
        if (const bool itemIsNotInKnapsack = !solution.n[i])
            continue;
        cout << "  " << solution.n[i] << ' ' << task.getItems()[i].name << " ( item weight = " << task.getItems()[i].w << " )" << endl;
    }

    cout << "Weight: " << solution.w << " Value: " << solution.v << endl;
    return 0;
}


(ns knapsack
  (:gen-class))

(def groupeditems [
                   ["map", 9, 150, 1]
                   ["compass", 13, 35, 1]
                   ["water", 153, 200, 3]
                   ["sandwich", 50, 60, 2]
                   ["glucose", 15, 60, 2]
                   ["tin", 68, 45, 3]
                   ["banana", 27, 60, 3]
                   ["apple", 39, 40, 3]
                   ["cheese", 23, 30, 1]
                   ["beer", 52, 10, 3]
                   ["suntan cream", 11, 70, 1]
                   ["camera", 32, 30, 1]
                   ["t-shirt", 24, 15, 2]
                   ["trousers", 48, 10, 2]
                   ["umbrella", 73, 40, 1]
                   ["waterproof trousers", 42, 70, 1]
                   ["waterproof overclothes", 43, 75, 1]
                   ["note-case", 22, 80, 1]
                   ["sunglasses", 7, 20, 1]
                   ["towel", 18, 12, 2]
                   ["socks", 4, 50, 1]
                   ["book", 30, 10, 2]
                  ])

(defstruct item :name :weight :value)

(def items (->> (for [[item wt val n] groupeditems]
                   (repeat n [item wt val]))
                 (mapcat identity)
                 (map #(apply struct item %))
                 (vec)))

(declare mm) ;forward decl for memoization function
(defn m [i w]
  (cond
    (< i 0) [0 []]
    (= w 0) [0 []]
    :else
    (let [{wi :weight vi :value} (get items i)]
      (if (> wi w)
        (mm (dec i) w)
        (let [[vn sn :as no]  (mm (dec i) w)
              [vy sy :as yes] (mm (dec i) (- w wi))]
          (if (> (+ vy vi) vn)
            [(+ vy vi) (conj sy i)]
            no))))))

(def mm (memoize m))

(let [[value indexes] (mm (-> items count dec) 400)
      names (map (comp :name items) indexes)]
  (println "Items to pack:")
  (doseq [[k v] (frequencies names)]
    (println (format "%d %s" v k)))
  (println "Total value:" value)
  (println "Total weight:" (reduce + (map (comp :weight items) indexes))))


;;; memoize
(defmacro mm-set (p v) `(if ,p ,p (setf ,p ,v)))

(defun knapsack (max-weight items)
  (let ((cache (make-array (list (1+ max-weight) (1+ (length items)))
			   :initial-element nil)))

    (labels ((knapsack1 (spc items)
	(if (not items) (return-from knapsack1 (list 0 0 '())))
	 (mm-set (aref cache spc (length items))
	   (let* ((i (first items))
		  (w (second i))
		  (v (third i))
		  (x (knapsack1 spc (cdr items))))
	     (loop for cnt from 1 to (fourth i) do
		   (let ((w (* cnt w)) (v (* cnt v)))
		     (if (>= spc w)
		       (let ((y (knapsack1 (- spc w) (cdr items))))
			 (if (> (+ (first y) v) (first x))
			   (setf x (list (+ (first  y) v)
					 (+ (second y) w)
					 (cons (list (first i) cnt) (third y)))))))))
	     x))))

      (knapsack1 max-weight items))))

(print
  (knapsack 400
	    '((map 9 150 1) (compass 13 35 1) (water 153 200 2) (sandwich 50 60 2)
              (glucose 15 60 2) (tin 68 45 3) (banana 27 60 3) (apple 39 40 3)
	      (cheese 23 30 1) (beer 52 10 3) (cream 11 70 1) (camera 32 30 1)
	      (T-shirt 24 15 2) (trousers 48 10 2) (umbrella 73 40 1)
	      (trousers 42 70 1) (overclothes 43 75 1) (notecase 22 80 1)
	      (glasses 7 20 1) (towel 18 12 2) (socks 4 50 1) (book 30 10 2))))


record Item, name : String, weight : Int32, value : Int32, count : Int32

record Selection, mask : Array(Int32), cur_index : Int32, total_value : Int32

class Knapsack
  @threshold_value = 0
  @threshold_choice : Selection?
  getter checked_nodes = 0

  def knapsack_step(taken, items, remaining_weight)
    if taken.total_value > @threshold_value
      @threshold_value = taken.total_value
      @threshold_choice = taken
    end
    candidate_index = items.index(taken.cur_index) { |item| item.weight <= remaining_weight }
    return nil unless candidate_index
    @checked_nodes += 1
    candidate = items[candidate_index]
    # candidate is a best of available items, so if we fill remaining value with
    # and still don't reach the threshold, the branch is wrong
    return nil if taken.total_value + 1.0 * candidate.value / candidate.weight * remaining_weight < @threshold_value
    # now recursively check all variants (from taking maximum count to taking nothing)
    max_count = {candidate.count, remaining_weight // candidate.weight}.min
    (0..max_count).reverse_each do |n|
      mask = taken.mask.clone
      mask[candidate_index] = n
      knapsack_step Selection.new(mask, candidate_index + 1, taken.total_value + n*candidate.value), items, remaining_weight - n*candidate.weight
    end
  end

  def select(items, max_weight)
    @checked_variants = 0
    # sort by descending relative value
    list = items.sort_by { |item| -1.0 * item.value / item.weight }
    nothing = Selection.new(Array(Int32).new(items.size, 0), 0, 0)
    @threshold_value = 0
    @threshold_choice = nothing
    knapsack_step(nothing, list, max_weight)
    selected = @threshold_choice.not_nil!
    result = Hash(Item, Int32).new(0)
    selected.mask.each_with_index { |v, i| result[list[i]] = v if v > 0 }
    result
  end
end

possible = [
  Item.new("map", 9, 150, 1),
  Item.new("compass", 13, 35, 1),
  Item.new("water", 153, 200, 2),
  Item.new("sandwich", 50, 60, 2),
  Item.new("glucose", 15, 60, 2),
  Item.new("tin", 68, 45, 3),
  Item.new("banana", 27, 60, 3),
  Item.new("apple", 39, 40, 3),
  Item.new("cheese", 23, 30, 1),
  Item.new("beer", 52, 10, 3),
  Item.new("suntan cream", 11, 70, 1),
  Item.new("camera", 32, 30, 1),
  Item.new("T-shirt", 24, 15, 2),
  Item.new("trousers", 48, 10, 2),
  Item.new("umbrella", 73, 40, 1),
  Item.new("waterproof trousers", 42, 70, 1),
  Item.new("waterproof overclothes", 43, 75, 1),
  Item.new("note-case", 22, 80, 1),
  Item.new("sunglasses", 7, 20, 1),
  Item.new("towel", 18, 12, 2),
  Item.new("socks", 4, 50, 1),
  Item.new("book", 30, 10, 2),
]

solver = Knapsack.new
used = solver.select(possible, 400)
puts "optimal choice: #{used.map { |item, count| count == 1 ? item.name : "#{count}x #{item.name}" }.join(", ")}"
puts "total weight #{used.sum { |item, count| item.weight*count }}"
puts "total value #{used.sum { |item, count| item.value*count }}"
puts "checked nodes: #{solver.checked_nodes}"


import std.stdio, std.typecons, std.functional;

immutable struct Item {
    string name;
    int weight, value, quantity;
}

immutable Item[] items = [
    {"map",           9, 150, 1}, {"compass",      13,  35, 1},
    {"water",       153, 200, 3}, {"sandwich",     50,  60, 2},
    {"glucose",      15,  60, 2}, {"tin",          68,  45, 3},
    {"banana",       27,  60, 3}, {"apple",        39,  40, 3},
    {"cheese",       23,  30, 1}, {"beer",         52,  10, 3},
    {"suntan cream", 11,  70, 1}, {"camera",       32,  30, 1},
    {"t-shirt",      24,  15, 2}, {"trousers",     48,  10, 2},
    {"umbrella",     73,  40, 1}, {"w-trousers",   42,  70, 1},
    {"w-overcoat",   43,  75, 1}, {"note-case",    22,  80, 1},
    {"sunglasses",    7,  20, 1}, {"towel",        18,  12, 2},
    {"socks",         4,  50, 1}, {"book",         30,  10, 2}];

Tuple!(int, const(int)[]) chooseItem(in int iWeight, in int idx) nothrow @safe {
    alias memoChooseItem = memoize!chooseItem;
    if (idx < 0)
        return typeof(return)();

    int bestV;
    const(int)[] bestList;
    with (items[idx])
        foreach (immutable i; 0 .. quantity + 1) {
            immutable wlim = iWeight - i * weight;
            if (wlim < 0)
                break;

            //const (val, taken) = memoChooseItem(wlim, idx - 1);
            const val_taken = memoChooseItem(wlim, idx - 1);
            if (val_taken[0] + i * value > bestV) {
                bestV = val_taken[0] + i * value;
                bestList = val_taken[1] ~ i;
            }
        }

    return tuple(bestV, bestList);
}

void main() {
    // const (v, lst) = chooseItem(400, items.length - 1);
    const v_lst = chooseItem(400, items.length - 1);

    int w;
    foreach (immutable i, const cnt; v_lst[1])
        if (cnt > 0) {
            writeln(cnt, " ", items[i].name);
            w += items[i].weight * cnt;
        }

    writeln("Total weight: ", w, " Value: ", v_lst[0]);
}


(lib 'struct)
(lib 'sql)
(lib 'hash)

(define H (make-hash))
(define T (make-table (struct goodies (name poids valeur qty))))
(define IDX (make-vector 0))

;; convert to 0/1 PB
;; transorm vector [1 2 3 4 (n-max 3) 5 (n-max 2) 6 .. ]
;; into vector of repeated indices : [1 2 3 4 4 4 5 5 6 ... ]

(define (make-01 T)
	 (for ((record T) (i (in-naturals)))
		 (for ((j (in-range 0 (goodies-qty record))))
			 (vector-push IDX i)))
	 IDX)

(define-syntax-rule (name i) (table-xref T (vector-ref IDX i) 0))
(define-syntax-rule (poids i) (table-xref T (vector-ref IDX i) 1))
(define-syntax-rule (valeur i) (table-xref T (vector-ref IDX i) 2))

;;
;; code identical to 0/1 problem
;;

;;  make an unique hash-key from (i rest)
(define (t-idx i r)  (string-append i "|" r))
;; retrieve best core for item i, remaining r availbble weight
(define (t-get i r)  (or (hash-ref H (t-idx i r)) 0))

;; compute best score (i), assuming best (i-1 rest) is known
(define (score i restant)
	 (if (< i 0) 0
	 (hash-ref! H (t-idx i restant)
		 (if ( >= restant (poids i))
			 (max
			 (score (1- i) restant)
			 (+ (score (1- i) (- restant (poids i))) (valeur i)))
		    (score (1- i) restant)) ;; else not enough
	)))

;; compute best scores, starting from last item
(define (task W)
        (define restant W)
        (make-01 T)
        (define N (1- (vector-length IDX)))
		 (writeln 'total-value (score N W))
		 (group
		 (for/list  ((i (in-range N -1 -1)))
		 #:continue (= (t-get i restant) (t-get (1- i) restant))
		(set! restant (- restant (poids i)))
		(name i))))