#define PesoMax  400
#define items  22
#define Tabu  Chr(9)

Type Knapsack
    articulo As String*22
    peso As Integer
    valor As Integer
    pieza As Integer
End Type
Dim item(1 To 22) As Knapsack => { _
("map                   ",   9, 150, 0), ("compass               ",  13,  35, 0), _
("water                 ", 153, 200, 0), ("sandwich              ",  50, 160, 0), _
("glucose               ",  15,  60, 0), ("tin                   ",  68,  45, 0), _
("banana                ",  27,  60, 0), ("apple                 ",  39,  40, 0), _
("cheese                ",  23,  30, 0), ("beer                  ",  52,  10, 0), _
("suntan cream          ",  11,  70, 0), ("camera                ",  32,  30, 0), _
("T-shirt               ",  24,  15, 0), ("trousers              ",  48,  10, 0), _
("umbrella              ",  73,  40, 0), ("waterproof trousers   ",  42,  70, 0), _
("waterproof overclothes",  43,  75, 0), ("note-case             ",  22,  80, 0), _
("sunglasses            ",   7,  20, 0), ("towel                 ",  18,  12, 0), _
("socks                 ",   4,  50, 0), ("book                  ",  30,  10, 0)}

Dim As Integer i, tot = 0, TValor = 0
For i =1 To Ubound(item)
    tot += item(i).peso
Next i

Dim As Integer TPeso = tot-PesoMax
Dim As String pr = ""
Dim As Integer c = 0, v, w, k

Do
    v = 1e9 : w = 0 : k = 0

    For i = 1 To items
        If item(i).pieza = 0 Then
            w = 1000 * item(i).valor / item(i).peso
            If w < v Then v = w : k = i
        End If
    Next i

    If k Then
        TPeso -= item(k).peso
        item(k).pieza = 1
        If TPeso <= 0 Then Exit Do
    End If
    c += 1
Loop Until c>= items

Print "Knapsack contents: "
For i = 1 To items
    If item(i).pieza = 0 Then
        Print item(i).articulo & Tabu & item(i).peso & Tabu & item(i).valor
        TValor += item(i).valor
    End If
Next i

Print !"\nTotal value: "; TValor
Print "Total weight: "; PesoMax + TPeso
Sleep


package main

import "fmt"

type Item struct {
	name               string
	weight, value, qty int
}

var items = []Item{
	{"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},
	{"suntancream",		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-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},
}

type Chooser struct {
	Items []Item
	cache map[key]solution
}

type key struct {
	w, p int
}

type solution struct {
	v, w int
	qty  []int
}

func (c Chooser) Choose(limit int) (w, v int, qty []int) {
	c.cache = make(map[key]solution)
	s := c.rchoose(limit, len(c.Items)-1)
	c.cache = nil // allow cache to be garbage collected
	return s.v, s.w, s.qty
}

func (c Chooser) rchoose(limit, pos int) solution {
	if pos < 0 || limit <= 0 {
		return solution{0, 0, nil}
	}

	key := key{limit, pos}
	if s, ok := c.cache[key]; ok {
		return s
	}

	best_i, best := 0, solution{0, 0, nil}
	for i := 0; i*items[pos].weight <= limit && i <= items[pos].qty; i++ {
		sol := c.rchoose(limit-i*items[pos].weight, pos-1)
		sol.v += i * items[pos].value
		if sol.v > best.v {
			best_i, best = i, sol
		}
	}

	if best_i > 0 {
		// best.qty is used in another cache entry,
		// we need to duplicate it before modifying it to
		// store as our cache entry.
		old := best.qty
		best.qty = make([]int, len(items))
		copy(best.qty, old)
		best.qty[pos] = best_i
		best.w += best_i * items[pos].weight
	}
	c.cache[key] = best
	return best
}

func main() {
	v, w, s := Chooser{Items: items}.Choose(400)

	fmt.Println("Taking:")
	for i, t := range s {
		if t > 0 {
			fmt.Printf("  %d of %d %s\n", t, items[i].qty, items[i].name)
		}
	}
	fmt.Printf("Value: %d; weight: %d\n", v, w)
}


def totalWeight = { list -> list.collect{ it.item.weight * it.count }.sum() }
def totalValue = { list -> list.collect{ it.item.value * it.count }.sum() }

def knapsackBounded = { possibleItems ->
    def n = possibleItems.size()
    def m = (0..n).collect{ i -> (0..400).collect{ w -> []} }
    (1..400).each { w ->
        (1..n).each { i ->
            def item = possibleItems[i-1]
            def wi = item.weight, pi = item.pieces
            def bi = [w.intdiv(wi),pi].min()
            m[i][w] = (0..bi).collect{ count ->
                m[i-1][w - wi * count] + [[item:item, count:count]]
            }.max(totalValue).findAll{ it.count }
        }
    }
    m[n][400]
}


inv = 	[("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),
	-- what to do if we end up taking one trouser?
	("tshirt",24,15,2), ("trousers",48,10,2), ("umbrella",73,40,1), ("wtrousers",42,70,1),
	("woverclothes",43,75,1), ("notecase",22,80,1), ("sunglasses",7,20,1), ("towel",18,12,2),
	("socks",4,50,1), ("book",30,10,2)]

knapsack = foldr addItem (repeat (0,[])) where
	addItem (name,w,v,c) old = foldr inc old [1..c] where
		inc i list = left ++ zipWith max right new where
			(left, right) = splitAt (w * i) list
			new = map (\(val,itms)->(val + v * i, (name,i):itms)) old

main = print $ (knapsack inv) !! 400


'names numbers'=:|:".;._2]0 :0
  '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
)

'weights values pieces'=:|:numbers
decode=: (pieces+1)&#:

pickBest=:4 :0
  NB. given a list of options, return the best option(s)
  n=. decode y
  weight=. n+/ .*weights
  value=.  (x >: weight) * n+/ .*values
  (value = >./value)#y
)

bestCombo=:3 :0
   limit=. */pieces+1
   i=. 0
   step=. 1e6
   best=. ''
   while.i<limit do.
      best=. 400 pickBest best,(#~ limit&>)i+i.step
      i=. i+step
   end.
   best
)

   bestCombo''
978832641


package hu.pj.alg.test;

import hu.pj.alg.BoundedKnapsack;
import hu.pj.obj.Item;
import java.util.*;
import java.text.*;

public class BoundedKnapsackForTourists {
    public BoundedKnapsackForTourists() {
        BoundedKnapsack bok = new BoundedKnapsack(400); // 400 dkg = 400 dag = 4 kg

        // making the list of items that you want to bring
        bok.add("map", 9, 150, 1);
        bok.add("compass", 13, 35, 1);
        bok.add("water", 153, 200, 3);
        bok.add("sandwich", 50, 60, 2);
        bok.add("glucose", 15, 60, 2);
        bok.add("tin", 68, 45, 3);
        bok.add("banana", 27, 60, 3);
        bok.add("apple", 39, 40, 3);
        bok.add("cheese", 23, 30, 1);
        bok.add("beer", 52, 10, 3);
        bok.add("suntan cream", 11, 70, 1);
        bok.add("camera", 32, 30, 1);
        bok.add("t-shirt", 24, 15, 2);
        bok.add("trousers", 48, 10, 2);
        bok.add("umbrella", 73, 40, 1);
        bok.add("waterproof trousers", 42, 70, 1);
        bok.add("waterproof overclothes", 43, 75, 1);
        bok.add("note-case", 22, 80, 1);
        bok.add("sunglasses", 7, 20, 1);
        bok.add("towel", 18, 12, 2);
        bok.add("socks", 4, 50, 1);
        bok.add("book", 30, 10, 2);

        // calculate the solution:
        List<Item> itemList = bok.calcSolution();

        // write out the solution in the standard output
        if (bok.isCalculated()) {
            NumberFormat nf  = NumberFormat.getInstance();

            System.out.println(
                "Maximal weight           = " +
                nf.format(bok.getMaxWeight() / 100.0) + " kg"
            );
            System.out.println(
                "Total weight of solution = " +
                nf.format(bok.getSolutionWeight() / 100.0) + " kg"
            );
            System.out.println(
                "Total value              = " +
                bok.getProfit()
            );
            System.out.println();
            System.out.println(
                "You can carry te following materials " +
                "in the knapsack:"
            );
            for (Item item : itemList) {
                if (item.getInKnapsack() > 0) {
                    System.out.format(
                        "%1$-10s %2$-23s %3$-3s %4$-5s %5$-15s \n",
                        item.getInKnapsack() + " unit(s) ",
                        item.getName(),
                        item.getInKnapsack() * item.getWeight(), "dag  ",
                        "(value = " + item.getInKnapsack() * item.getValue() + ")"
                    );
                }
            }
        } else {
            System.out.println(
                "The problem is not solved. " +
                "Maybe you gave wrong data."
            );
        }

    }

    public static void main(String[] args) {
        new BoundedKnapsackForTourists();
    }
} // class


#  Item {name, weight, value, count}

def Item($name; $weight; $value; $count): {$name, $weight, $value, $count};

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

def knapsack($w):
  def list($init): [range(0; .) | $init];
  (items|length) as $n
  | {m: ($n+1 | list( $w + 1 | list(0) )) }
  | reduce range(1; $n+1) as $i (.;
      reduce range (0; $w + 1) as $j (.;
            .m[$i][$j] = .m[$i-1][$j]
	    | label $out
            | foreach (range(1; 1 + ((items[$i - 1].count))), null) as $k (.stop = false;
	          if $k == null then .
		  elif ($k * items[$i - 1].weight > $j) then .stop = true
                  else (.m[$i - 1][$j - ($k * items[$i - 1].weight)] + $k * items[$i - 1].value) as $v
                  | if $v > .m[$i][$j] then .m[$i][$j] = $v else . end
		  end;
		if .stop or ($k == null)  then ., break $out else empty end)
            ) )
  | .s = ($n|list(0))
  | .j = $w
  | reduce range($n; 0; -1) as $i (.;
        .m[$i][.j] as $v
        | .k = 0
        | until ($v == .m[$i - 1][.j] + .k * items[$i - 1].value;
            .s[$i - 1] +=  1
            | .j = .j - items[$i - 1].weight
            | .k += 1 ) )
    | .s;

def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;

def task(maxWeight):
  def f(a;b;c;d): "\(a|lpad(22)) \(b|lpad(6)) \(c|lpad(6)) \(d|lpad(6))";
  def f: . as [$a,$b,$c,$d] | f($a;$b;$c;$d);

  (items|length) as $n
  | knapsack(maxWeight) as $s
  | f("Item Chosen";          "Weight";"Value";"Number"),
    "---------------------- ------  ----- ------",
   ({ itemCount:0,
      sumWeight:0,
      sumValue :0,
      sumNumber:0 }
    | reduce range(0; $n) as $i (.;
        if ($s[$i] != 0)
        then .itemCount += 1
        | .name   = items[$i].name
        | .number = $s[$i]
        | .weight = items[$i].weight * .number
        | .value  = items[$i].value  * .number
        | .sumNumber  += .number
        | .sumWeight  += .weight
        | .sumValue   += .value
	| .emit += [[.name, .weight, .value, .number]]
	else .
	end )
    | (.emit[] | f),
    "---------------------- ------  ----- ------",
     f("Items chosen \(.itemCount|lpad(4))"; .sumWeight; .sumValue; .sumNumber) );

task(400)


using MathProgBase, Cbc

struct KPDSupply{T<:Integer}
    item::String
    weight::T
    value::T
    quant::T
end
Base.show(io::IO, kdps::KPDSupply) = print(io, kdps.quant, " ", kdps.item, " ($(kdps.weight) kg, $(kdps.value) €)")

function solve(gear::Vector{KPDSupply{T}}, capacity::Integer) where T<:Integer
    w = getfield.(gear, :weight)
    v = getfield.(gear, :value)
    q = getfield.(gear, :quant)
    sol = mixintprog(-v, w', '<', capacity, :Int, 0, q, CbcSolver())
    sol.status == :Optimal || error("this problem could not be solved")

    if all(q .== 1) # simpler case
        return gear[sol.sol == 1.0]
    else
        pack = similar(gear, 0)
        s = round.(Int, sol.sol)
        for (i, g) in enumerate(gear)
            iszero(s[i]) && continue
            push!(pack, KPDSupply(g.item, g.weight, g.value, s[i]))
        end
        return pack
    end
end


// version 1.1.2

data class Item(val name: String, val weight: Int, val value: Int, val count: Int)

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

val n = items.size

const val MAX_WEIGHT = 400

fun knapsack(w: Int): IntArray {
    val m  = Array(n + 1) { IntArray(w + 1) }
    for (i in 1..n) {
        for (j in 0..w) {
            m[i][j] = m[i - 1][j]
            for (k in 1..items[i - 1].count) {
                if (k * items[i - 1].weight > j) break
                val v = m[i - 1][j - k * items[i - 1].weight] + k * items[i - 1].value
                if (v > m[i][j]) m[i][j] = v
            }
        }
    }
    val s = IntArray(n)
    var j = w
    for (i in n downTo 1) {
        val v = m[i][j]
        var k = 0
        while (v != m[i - 1][j] + k * items[i - 1].value) {
            s[i - 1]++
            j -= items[i - 1].weight
            k++
        }
    }
    return s
}

fun main(args: Array<String>) {
   val s = knapsack(MAX_WEIGHT)
   println("Item Chosen             Weight Value  Number")
   println("---------------------   ------ -----  ------")
   var itemCount = 0
   var sumWeight = 0
   var sumValue  = 0
   var sumNumber = 0
   for (i in 0 until n) {
       if (s[i] == 0) continue
       itemCount++
       val name   = items[i].name
       val number = s[i]
       val weight = items[i].weight * number
       val value  = items[i].value  * number
       sumNumber += number
       sumWeight += weight
       sumValue  += value
       println("${name.padEnd(22)}    ${"%3d".format(weight)}   ${"%4d".format(value)}    ${"%2d".format(number)}")
   }
   println("---------------------   ------ -----  ------")
   println("Items chosen $itemCount           ${"%3d".format(sumWeight)}   ${"%4d".format(sumValue)}    ${"%2d".format(sumNumber)}")
}


/*Knapsack

  This model finds the integer optimal packing of a knapsack

  Nigel_Galloway
  January 9th., 2012
*/
set Items;
param weight{t in Items};
param value{t in Items};
param quantity{t in Items};

var take{t in Items}, integer, >=0, <=quantity[t];

knap_weight : sum{t in Items} take[t] * weight[t] <= 400;

maximize knap_value: sum{t in Items} take[t] * value[t];

data;

param : Items          : weight   value   quantity :=
         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
         suntancream	  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-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
;

end;


%Solve Knapsack Problem Bounded. Nigel Galloway, Octoer 12th., 2020.
enum Items={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};
array[Items] of int: weight  =[9,13,153,50,15,68,27,39,23,52,11,32,24,48,73,42,43,22,7,18,4,30];
array[Items] of int: value   =[150,35,200,60,60,45,60,40,30,10,70,30,15,10,40,70,75,80,20,12,50,10];
array[Items] of int: quantity=[1,1,2,2,2,3,3,3,1,3,1,1,2,2,1,1,1,1,1,2,1,2];
array[Items] of var 0..max(quantity): take; constraint forall(n in Items)(take[n]<=quantity[n]);
int: maxWeight=400;
var int: wTaken=sum(n in Items)(weight[n]*take[n]);
var int: wValue=sum(n in Items)(value[n]*take[n]);
constraint wTaken <= maxWeight;
solve maximize wValue;
output[concat([let {string: g=show(take[n])} in "Take "++(if g==show(quantity[n]) then "all" else g endif)++" of \(n)\n" | n in Items where show(take[n])!="0"])++"\nTotal Weight=\(wTaken) Total Value="++show_float(4,2,wValue)]


# Knapsack. Recursive solution.

import strformat
import tables

# Description of an item.
type Item = tuple[name: string; weight, value, pieces: int]

# List of available items.
const Items: seq[Item] = @[("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)
                          ]

type

  # Item numbers (used rather than items themselves).
  Number = range[0..Items.high]

  # Description of an expanded item.
  ExpandedItem = tuple[num: Number; weight, value: int]

# Expanded items management.

proc expandedItems(items: seq[Item]): seq[ExpandedItem] =
  ## Expand the list of items.
  for idx, item in Items:
    for _ in 1..item.pieces:
      result.add((idx.Number, item.weight, item.value))

const ItemList = expandedItems(Items)

type

  # Index in the expanded list.
  ExpandedIndex = 0..ItemList.high

  # Chosen items and their total value.
  Choice = tuple[indexes: set[ExpandedIndex]; weight, value: int]

# Cache used to speed up the search.
var cache: Table[tuple[index, weight: int], Choice]

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

proc select(idx, weightLimit: int): Choice =
  ## Find the best choice starting from item at index "idx".

  if idx < 0 or weightLimit == 0:
    return

  if (idx, weightLimit) in cache:
    return cache[(idx, weightLimit)]

  let weight = ItemList[idx].weight
  if weight > weightLimit:
    return select(idx - 1, weightLimit)

  # Try by leaving this item and selecting among remaining items.
  result = select(idx - 1, weightLimit)

  # Try by taking this item and completing with some remaining items.
  var result1 = select(idx - 1, weightLimit - weight)
  inc result1.value, ItemList[idx].value

  # Select the best choice (giving the greater value).
  if result1.value > result.value:
    result = (result1.indexes + {idx.ExpandedIndex}, result1.weight + weight, result1.value)

  cache[(idx, weightLimit)] = result

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

let (indexes, weight, value) = select(ItemList.high, 400)

# Count the number of pieces for each item.
var pieces = newSeq[int](Items.len)
for idx in indexes:
  inc pieces[ItemList[idx].num]

echo "List of items:"
for num in 0..Items.high:
  if pieces[num] > 0:
    echo fmt"– {pieces[num]} of {Items[num].pieces} {Items[num].name}"
echo ""
echo "Total weight: ", weight
echo "Total value: ", value


type KnapSackItem string name,sys dag,value,tag

KnapSackItem it[100]

sys dmax=400
sys items=22

it=>

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

tot=0
for i=1 to items
  tot+=it(i).dag
next
xs=tot-dmax

'REMOVE LOWEST PRIORITY ITEMS TILL XS<=0

cr=chr(13)+chr(10)
tab=chr(9)
pr="remove: " cr
c=0

do
  v=1e9
  w=0
  k=0
  '
  'FIND NEXT LEAST VALUE ITEM
  '
  for i=1 to items
    if it[i].tag=0
      'w=it[i].value               'TEST PRIORITY ONLY
      w=1000*it[i].value/it[i].dag 'TEST PRIORIT/WEIGHT VALUE
      if w<v then v=w : k=i
    end if
  next
  '
  'LOG AND REMOVE FROM LIST
  '
  if k
    xs-=it[k].dag 'deduct from excess weight
    it[k].tag=1
    pr+=it(k).name tab it(k).dag tab it(k).value cr
    if xs<=0 then exit do 'Weight within dmax
  end if
  c++
  if c>=items then exit do
end do
'
pr+=cr "Knapsack contents: " cr
'
for i=1 to items
  if it(i).tag=0
    pr+=it(i).name tab it(i).dag tab it(i).value cr
  end if
next

'TRY FITTING IN LOWER PRIORITY ITEMS

av=-xs

for i=1 to items
  if it[i].tag
    if av-it[i].dag > 0 then
      pr+="Can include: " it(i).name tab it(i).dag tab it(i).value cr
      av-=it[i].dag
    end if
  end if
next
pr+=cr "Weight: " dmax+xs
'putfile "s.txt",pr
print pr
'Knapsack contents:
'map             	9	150
'compass         	13	35
'water           	153	200
'sandwich        	50	160
'glucose         	15	60
'banana          	27	60
'suntan cream     	11	70
'waterproof trousers	42	70
'waterproof overclothes	43	75
'note-case        	22	80
'sunglasses       	7	20
'socks           	4	50
'
'Weight: 396


declare
  %% maps items to tuples of
  %% Weight(hectogram), Value and available Pieces
  Problem = knapsack('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
                    )

  %% item -> Weight
  Weights = {Record.map Problem fun {$ X} X.1 end}
  %% item -> Value
  Values =  {Record.map Problem fun {$ X} X.2 end}

  proc {Knapsack Solution}
     %% a solution maps items to finite domain variables
     %% whose maximum values depend on the item type
     Solution = {Record.map Problem fun {$ _#_#Max} {FD.int 0#Max} end}
     %% no more than 400 hectograms
     {FD.sumC Weights Solution '=<:' 400}
     %% search through valid solutions
     {FD.distribute naive Solution}
  end

  proc {PropagateLargerValue Old New}
     %% propagate that new solutions must yield a higher value
     %% than previously found solutions (essential for performance)
     {FD.sumC Values New '>:' {Value Old}}
  end

  fun {Value Candidate}
     {Record.foldL {Record.zip Candidate Values Number.'*'} Number.'+' 0}
  end

  fun {Weight Candidate}
     {Record.foldL {Record.zip Candidate Weights Number.'*'} Number.'+' 0}
  end

  [Best] = {SearchBest Knapsack PropagateLargerValue}
in
  {System.showInfo "Items: "}
  {Record.forAllInd Best
   proc {$ I V}
      if V > 0 then
	 {System.showInfo I#": "#V}
      end
   end
  }
  {System.printInfo "\n"}
  {System.showInfo "total value: "#{Value Best}}
  {System.showInfo "total weight: "#{Weight Best}}


#!/usr/bin/perl

use strict;

my $raw = <<'TABLE';
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      1
suntancream     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
TABLE

my @items;
for (split "\n", $raw) {
        my @x = split /\s+/;
	push @items, {
		name	=> $x[0],
		weight	=> $x[1],
		value	=> $x[2],
		quant	=> $x[3],
	}
}

my $max_weight = 400;

my %cache;
sub pick {
	my ($weight, $pos) = @_;
	if ($pos < 0 or $weight <= 0) {
		return 0, 0, []
	}

	@{ $cache{$weight, $pos} //= [do{	# odd construct: for caching
		my $item = $items[$pos];
		my ($bv, $bi, $bw, $bp) = (0, 0, 0, []);

		for my $i (0 .. $item->{quant}) {
			last if $i * $item->{weight} > $weight;
			my ($v, $w, $p) = pick($weight - $i * $item->{weight}, $pos - 1);
			next if ($v += $i * $item->{value}) <= $bv;

			($bv, $bi, $bw, $bp) = ($v, $i, $w, $p);
		}

		my @picked = ( @$bp, $bi );
		$bv, $bw + $bi * $item->{weight}, \@picked
	}]}
}

my ($v, $w, $p) = pick($max_weight, $#items);
for (0 .. $#$p) {
	if ($p->[$_] > 0) {
		print "$p->[$_] of $items[$_]{name}\n";
	}
}
print "Value: $v; Weight: $w\n";


with javascript_semantics
atom t0 = time()

constant goodies = {
-- item                     weight value pieces
{"map",                     9,      150,    1},
{"compass",                 13,     35,     1},
{"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},
{"water",                   153,    200,    2},
{"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}}

function knapsack(integer max_weight, integer at)
    integer best_points = 0, points
    sequence best_choices = {}, choices
    atom act_weight = 0, sub_weight
    if at>=1 then
        integer {?,witem,pitem,imax} = goodies[at]
        for i=0 to imax do
            integer wlim = max_weight-i*witem
            if wlim<0 then exit end if
            {points,sub_weight,choices} = knapsack(wlim, at-1)
            points += i*pitem
            if points>best_points then
                best_points = points
                best_choices = deep_copy(choices)&i
                act_weight = sub_weight+i*witem
            end if
        end for
    end if
    return {best_points, act_weight, best_choices}
end function

sequence res = knapsack(400, length(goodies))   -- {points,act_weight,choices}

atom weight = 0, witem
atom points = 0, pitem
string idesc
for i=1 to length(goodies) do
    integer c = res[3][i]
    if c then
        {idesc,witem,pitem} = goodies[i]
        printf(1,"%d %s\n",{c,idesc})
        weight += c*witem
        points += c*pitem
    end if
end for
if points!=res[1] then ?9/0 end if  -- sanity check
printf(1,"Value %d, weight %g [%3.2fs]\n",{points,weight,time()-t0})


import mip,util.

go =>
   data(AllItems,MaxWeight),
   [Items,Weights,Values,Pieces] = transpose(AllItems),

   knapsack_bounded(Weights,Values,Pieces,MaxWeight, X,TotalWeight,TotalValue),

   print_solution(Items,Weights,Values, X,TotalWeight,TotalValue),
   nl.

% Print the solution
print_solution(Items,Weights,Values, X,TotalWeight,TotalValue) ?=>
   println("\nThese are the items to pick:"),
   println("  Item                         Weight Value"),

   foreach(I in 1..Items.len)
       if X[I] > 0 then
           printf("* %d %-29w %3d %3d\n", X[I],Items[I],Weights[I],Values[I])
       end
   end,
   nl,
   printf("Total weight: %d\n", TotalWeight),
   printf("Total value: %d\n", TotalValue),
   nl.

% Solve knapsack problem
knapsack_bounded(Weights,Values,Pieces,MaxWeight, X,TotalWeight,TotalValue) =>
   NumItems = length(Weights),

   % Variables
   MaxPieces = max(Pieces),
   X = new_list(NumItems),
   X :: 0..MaxPieces,

   % Constraints
   SumValues = sum(Values),
   TotalValue :: 0..SumValues,
   TotalWeight :: 0..MaxWeight,

   scalar_product(Weights,X,TotalWeight),
   scalar_product(Values,X,TotalValue),

   TotalWeight #<= MaxWeight,

   % Check number of pieces
   foreach({XVal,Piece} in zip(X,Pieces))
      XVal #=< Piece
   end,

   % Search
   Vars = X ++ [TotalWeight, TotalValue],
   solve($[max(TotalValue),down],Vars).

% data
data(Items,MaxWeight) =>
   Items =
      % Item          Weight   Value  Pieces
      [["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],
       ["suntancream",   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]],
    MaxWeight = 400.


(de *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)                ("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) )

# Dynamic programming solution
(de knapsack (Lst W)
   (when Lst
      (cache '*KnapCache (cons W Lst)
         (let X (knapsack (cdr Lst) W)
            (if (ge0 (- W (cadar Lst)))
               (let Y (cons (car Lst) (knapsack (cdr Lst) @))
                  (if (> (sum caddr X) (sum caddr Y)) X Y) )
               X ) ) ) ) )

(let K
   (knapsack
      (mapcan                                   # Expand multiple items
         '((X) (need (cadddr X) NIL X))
         *Items )
      400 )
   (for I K
      (apply tab I (3 -24 6 6) NIL) )
   (tab (27 6 6) NIL (sum cadr K) (sum caddr K)) )


:- use_module(library(clpfd)).

% tuples (name, weights, value, nb pieces).
knapsack :-
	L = [(   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)],

	% Takes is the list of the numbers of each items
	% these numbers are between 0 and the 4th value of the tuples of the items
        maplist(collect, L, Ws, Vs, Takes),
        scalar_product(Ws, Takes, #=<, 400),
        scalar_product(Vs, Takes, #=, VM),

	% to have statistics on the resolution of the problem.
	time(labeling([max(VM), down], Takes)),
        scalar_product(Ws, Takes, #=, WM),

	%% displayinf of the results.
	compute_lenword(L, 0, Len),
	sformat(A1, '~~w~~t~~~w|', [Len]),
	sformat(A2, '~~t~~w~~~w|', [4]),
	sformat(A3, '~~t~~w~~~w|', [5]),
	print_results(A1,A2,A3, L, Takes, WM, VM).

collect((_, W, V, N), W, V, Take) :-
	Take in 0..N.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
compute_lenword([], N, N).
compute_lenword([(Name, _, _, _)|T], N, NF):-
	atom_length(Name, L),
	(   L > N -> N1 = L; N1 = N),
	compute_lenword(T, N1, NF).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
print_results(A1,A2,A3, [], [], WM, WR) :-
	sformat(W0, '~w ', [' ']),
	sformat(W1, A1, [' ']),
	sformat(W2, A2, [WM]),
	sformat(W3, A3, [WR]),
	format('~w~w~w~w~n', [W0,W1,W2,W3]).

print_results(A1,A2,A3, [_H|T], [0|TR], WM, VM) :-
	!,
	print_results(A1,A2,A3, T, TR, WM, VM).

print_results(A1, A2, A3, [(Name, W, V, _)|T], [N|TR], WM, VM) :-
	sformat(W0, '~w ', [N]),
	sformat(W1, A1, [Name]),
	sformat(W2, A2, [W]),
	sformat(W3, A3, [V]),
	format('~w~w~w~w~n', [W0,W1,W2,W3]),
	print_results(A1, A2, A3, T, TR, WM, VM).


from itertools import groupby
from collections import namedtuple

def anyvalidcomb(items, maxwt, val=0, wt=0):
    ' All combinations below the maxwt '
    if not items:
        yield [], val, wt
    else:
        this, *items = items            # car, cdr
        for n in range(this.number + 1):
            w = wt  + n * this.weight
            if w > maxwt:
                break
            v = val + n * this.value
            this_comb = [this] * n
            for comb, value, weight in anyvalidcomb(items, maxwt, v, w):
                yield this_comb + comb, value, weight

maxwt = 400
COMB, VAL, WT = range(3)
Item  = namedtuple('Items', 'name weight value number')
items = [ Item(*x) for x in
          (
            ("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),
           ) ]

bagged = max( anyvalidcomb(items, maxwt), key=lambda c: (c[VAL], -c[WT])) # max val or min wt if values equal
print("Bagged the following %i items" % len(bagged[COMB]))
print('\n\t'.join('%i off: %s' % (len(list(grp)), item.name) for item, grp in groupby(sorted(bagged[COMB]))))
print("for a total value of %i and a total weight of %i" % bagged[1:])


library(tidyverse)
library(rvest)

task_html= read_html("http://rosettacode.org/wiki/Knapsack_problem/Bounded")
task_table= html_nodes(html, "table")[[1]] %>%
  html_table(table, header= T, trim= T) %>%
  set_names(c("items", "weight", "value", "pieces")) %>%
  filter(items != "knapsack") %>%
  mutate(weight= as.numeric(weight),
         value= as.numeric(value),
         pieces= as.numeric(pieces))


#lang racket
(require net/url html xml xml/path)

(struct item (name mass value count) #:transparent)

;this section is to convert the web page on the problem into the data for the problem
;i don't got time to manually type tables, nevermind that this took longer
(define (group-n n l)
  (let group-n ([l l] [acc '()])
    (if (null? l)
        (reverse acc)
        (let-values ([(takes drops) (split-at l n)])
          (group-n drops (cons takes acc))))))
(define (atom? x) (not (or (pair? x) (null? x))))
;modified from little schemer...finds nested list where regular member would've returned non-#f
(define (member* x t)
  (cond [(null? t) #f]
        [(atom? (car t)) (or (and (equal? (car t) x) t)
                             (member* x (cdr t)))]
        [else (or (member* x (car t))
                  (member* x (cdr t)))]))
(define (addr->xexpr f) (compose xml->xexpr f read-html-as-xml get-pure-port string->url))
(define (read-page) ((addr->xexpr cadr) "http://rosettacode.org/wiki/Knapsack_problem/Bounded"))
(define (get-xml-table xe) (member* 'table xe))
(define (xml-table->item-list xe-table)
  ;all html table datas
  (let* ([strs (se-path*/list '(td) xe-table)]
         ;4 columns per row
         [rows (group-n 4 strs)]
         ;the last two rows belong to the knapsack entry which we don't want
         [rows (take rows (- (length rows) 2))])
    (for/list ([r rows])
      (let ([r (map string-trim r)])
        ;convert the weight, value, and pieces columns to numbers and structify it
        (apply item (car r) (map string->number (cdr r)))))))
;top-level function to take a string representing a URL and gives the table I didn't want to type
(define addr->item-list (compose xml-table->item-list get-xml-table read-page))

;stores best solution
(struct solution (value choices) #:transparent)

;finds best solution in a list of solutions
(define (best sol-list)
  (let best ([l (cdr sol-list)] [bst (car sol-list)])
    (match l
      ['() bst]
      [(cons s l) (if (> (solution-value s) (solution-value bst))
                      (best l s)
                      (best l bst))])))

;stores the choices leading to best solution...item name and # of that item taken
(struct choice (name count) #:transparent)

;algorithm is derived from Haskell's array-based example
;returns vector of solutions for every natural number capacity up to the input max
(define (solution-vector capacity)
  ;find best value and items that gave it, trying all items
  ;first we set up a vector for the best solution found for every capacity
  ;the best solution found at the beginning has 0 value with no items
  (for/fold ([solutions (make-vector (add1 capacity) (solution 0 '()))])
            ([i (addr->item-list)])
    ;the new solutions aren't accumulated until after processing all the way through a particular
    ;capacity, lest capacity c allow capacity c+1 to reuse an item that had been exhausted, i.e.
    ;we have to move on to the next item before we save ANY solutions found for that item, so they
    ;must be saved "in parallel" by overwriting the entire vector at once
    (for/vector ([target-cap (range 0 (add1 capacity))])
      (match-let ([(item name mass value count) i])
        ;find best solution for item out of every number that can be taken of that item
        ;we'll call an "item and count of item" a choice
        (best (for/list ([n (range 0 (add1 count))])
                ;ensure mass of this choice is not greater than target capacity
                (let ([mass-choice (* n mass)])
                  (if (> mass-choice target-cap)
                      (solution 0 '())
                      ;subtract from target capacity the amount taken up by this choice
                      ;use it to get the best solution for THAT capacity
                      (let ([remaining-cap-solution (vector-ref solutions (- target-cap mass-choice))])
                        ;the new solution found adds the value of this choice to the above value and
                        ;adds the choice itself to the list of choices
                        (solution (+ (* n value) (solution-value remaining-cap-solution))
                                  (cons (choice name n) (solution-choices remaining-cap-solution))))))))))))

;top level function to convert solution vector into single best answer
(define (knapsack capacity)
  ;the best solution is not necessarily the one that uses max capacity,
  ;e.g. if max is 5 and you have items of mass 4 and 5, and the 4 is worth more
  (match-let ([(solution value choices) (best (vector->list (solution-vector capacity)))])
    (solution value (filter (compose positive? choice-count) choices))))


my class KnapsackItem { has $.name; has $.weight; has $.unit; }

multi sub pokem ([],           $,  $v = 0) { $v }
multi sub pokem ([$,  *@],     0,  $v = 0) { $v }
multi sub pokem ([$i, *@rest], $w, $v = 0) {
  my $key = "{[email protected]} $w $v";
  (state %cache){$key} or do {
    my @skip = pokem @rest, $w, $v;
    if $w >= $i.weight { # next one fits
      my @put = pokem @rest, $w - $i.weight, $v + $i.unit;
      return (%cache{$key} = |@put, $i.name).list if @put[0] > @skip[0];
    }
    return (%cache{$key} = |@skip).list;
  }
}

my $MAX_WEIGHT = 400;
my @table = flat map -> $name,  $weight,  $unit,     $count {
     KnapsackItem.new( :$name, :$weight, :$unit ) xx $count;
},
        '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
        ;

my ($value, @result) = pokem @table, $MAX_WEIGHT;

(my %hash){$_}++ for @result;

say "Value = $value";
say "Tourist put in the bag:";
say "  # ITEM";
for %hash.sort -> $item {
  say "  {$item.value} {$item.key}";
}


/*REXX program solves a  knapsack problem  (22 items + repeats, with weight restriction.*/
call @gen                                        /*generate items and initializations.  */
call @sort                                       /*sort items by decreasing their weight*/
call build                                       /*build a list of choices (objects).   */
call showOBJ                                     /*display the list of choices (objects)*/
call findBest                                    /*examine and find the possible choices*/
call showBest                                    /*display best choice  (weight, value).*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
@gen: @.=;        @.1  = 'map                       9  150'
                  @.2  = 'compass                  13   35'
                  @.3  = 'water                   153  200   2'
                  @.4  = 'sandwich                 50   60   2'
                  @.5  = 'glucose                  15   60   2'
                  @.6  = 'tin                      68   45   3'
                  @.7  = 'banana                   27   60   3'
                  @.8  = 'apple                    39   40   3'
                  @.9  = 'cheese                   23   30'
                  @.10 = 'beer                     52   10   3'
                  @.11 = 'suntan_cream             11   70'
                  @.12 = 'camera                   32   30'
                  @.13 = 'T-shirt                  24   15   2'
                  @.14 = 'trousers                 48   10   2'
                  @.15 = 'umbrella                 73   40'
                  @.16 = 'waterproof_trousers      42   70'
                  @.17 = 'waterproof_overclothes   43   75'
                  @.18 = 'note-case                22   80'
                  @.19 = 'sunglasses                7   20'
                  @.20 = 'towel                    18   12   2'
                  @.21 = 'socks                     4   50'
                  @.22 = 'book                     30   10   2'
    highQ = 0                                    /*maximum quantity specified (if any). */
     maxL = length('knapsack items')             /* "     "    width for the table names*/
     maxW = length('weight')                     /* "     "      "    "    "   weights. */
     maxV = length('value')                      /* "     "      "    "    "   values.  */
     maxQ = length('pieces')                     /* "     "      "    "    "   quantity.*/
     maxWeight=400                               /*the maximum weight for the knapsack. */
     items= 0;   i.=;    w.=0;    v.=0;   q.=0   /*initialize some stuff and things.    */
        Tw= 0;   Tv=0;   Tq=0;    m=maxWeight    /*     "     more   "    "     "       */
     say;  say 'maximum weight allowed for a knapsack: '   commas(maxWeight);     say
     return
/*──────────────────────────────────────────────────────────────────────────────────────*/
@sort:        do j=1  while @.j\==''             /*process each choice and sort the item*/
              @.j=space(@.j);   _wt=word(@.j, 2) /*choose first item (arbitrary).       */
                  do k=j+1  while @.k\==''       /*find a possible heavier item.        */
                  ?wt=word(@.k, 2)
                  if ?wt>_wt  then do;  [email protected].k;  @.[email protected].j;  @.j=_;  _wt=?wt;  end   /*swap*/
                  end   /*k*/
              end       /*j*/                    /* [↑]  minimizes the # of combinations*/
      obj=j-1                                    /*adjust for the   DO   loop index.    */
      return
/*──────────────────────────────────────────────────────────────────────────────────────*/
build:        do j=1  for obj                    /*build a list of choices (objects).   */
              parse var  @.j  item  w  v  q  .   /*parse the original choice for table. */
              if w>maxWeight  then iterate       /*Is the weight > maximum?  Then ignore*/
              Tw=Tw+w;  Tv=Tv+v;   Tq=Tq+1       /*add the totals up  (for alignment).  */
              maxL=max(maxL, length(item))       /*find the maximum width for an item.  */
              if q==''  then q=1
              highQ=max(highQ, q)
              items=items+1                      /*bump the item counter.               */
              i.items=item;  w.items=w;  v.items=v;  q.items=q
                  do k=2  to q  ;  items=items+1 /*bump the item counter  (each piece). */
                  i.items=item;  w.items=w;  v.items=v;  q.items=q
                                Tw=Tw+w;    Tv=Tv+v;    Tq=Tq+1
                  end   /*k*/
              end       /*j*/
      maxW = max(maxW, length( commas(Tw) ) )    /*find the maximum width for weight.   */
      maxV = max(maxV, length( commas(Tv) ) )    /*  "   "     "      "    "  value.    */
      maxQ = max(maxQ, length( commas(Tq) ) )    /*  "   "     "      "    "  quantity. */
      maxL = maxL + maxL %4 + 4                  /*extend the width of name for table.  */
      return                                     /* [↑]    %  is REXX integer division. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: procedure;  parse arg _;   n=_'.9';   #=123456789;    b=verify(n, #, "M");   x=','
        e=verify(n, #'0', , verify(n, #"0.", 'M') ) - 4     /* [↓]  add commas to number*/
           do j=e  to b  by -3;    _=insert(x, _, j);  end  /*j*/;                return _
/*──────────────────────────────────────────────────────────────────────────────────────*/
hdr:  parse arg _item_, _;         if highq\==1  then _=center('pieces', maxq)
      call show center(_item_,  maxL), center('weight', maxW), center('value',  maxV), ,
                center(_     ,  maxQ);                          call hdr2;        return
/*──────────────────────────────────────────────────────────────────────────────────────*/
hdr2: _=maxQ;   x='═';          if highq==1  then _=0
      call show copies(x, maxL), copies(x, maxW), copies(x, maxV), copies(x, _);  return
/*──────────────────────────────────────────────────────────────────────────────────────*/
j?:   parse arg _,?;  $=value('Z'_);    do k=1  for _;  ?=? value('J'k);  end;    return
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: parse arg _item, _weight, _value, _quant
      say translate(left(_item, maxL,'─'), ,'_')  right(commas(_weight), maxW),
          right(commas(_value ), maxV)            right(commas(_quant ), maxQ);   return
/*──────────────────────────────────────────────────────────────────────────────────────*/
showOBJ: call hdr 'item';     do j=1  for obj             /*show the formatted choices. */
                              parse var  @.j  item weight value q .
                              if highq==1  then  q=
                                           else  if q==''  then q=1
                              call show  item, weight, value, q
                              end   /*j*/
         say;    say  'number of   unique   named items: '    obj
                 say  'number of items (including reps): '  items;    say;        return
/*──────────────────────────────────────────────────────────────────────────────────────*/
showBest:                     do words(?);  ?=strip(space(?), "L", 0);  end   /*words(?)*/
         bestC=?;   bestW=0;   bestV=$;   highQ=0;   totP=words(bestC);   say
         call hdr 'best choice'
                              do j=1  to totP         /*J  is modified within  DO  loop.*/
                              _=word(bestC, j);     _w=w._;     _v=v._;     q=1
                              if _==0  then iterate
                                  do k=j+1  to totP;  __=word(bestC, k)  /*get a choice.*/
                                  if i._\==i.__  then leave              /*not equal ?  */
                                  j=j+1;       w._=w._+_w;       v._=v._+_v;         q=q+1
                                  end   /*k*/
                              call show  i._,  w._,  v._,  q;            bestW=bestw+w._
                              end       /*j*/
         call hdr2;    say
         call show 'best weight'   ,     bestW        /*show a nicely formatted winnerW.*/
         call show 'best value'    , ,   bestV        /*  "  "    "       "     winnerV.*/
         call show 'knapsack items', , , totP         /*  "  "    "       "     pieces. */
         return
/*─────────────────────────────────────────────────────────────────────────────────────────────────────────*/
findBest:      h=items;      $=0
 do j1 =0  for h+1;                                       w1=    w.j1 ; z1=    v.j1 ;if  z1>$ then call j?  1
 do j2 =j1 +(j1 >0) to h;if w.j2 +w1 >m then iterate  j1; w2=w1 +w.j2 ; z2=z1 +v.j2 ;if  z2>$ then call j?  2
 do j3 =j2 +(j2 >0) to h;if w.j3 +w2 >m then iterate  j2; w3=w2 +w.j3 ; z3=z2 +v.j3 ;if  z3>$ then call j?  3
 do j4 =j3 +(j3 >0) to h;if w.j4 +w3 >m then iterate  j3; w4=w3 +w.j4 ; z4=z3 +v.j4 ;if  z4>$ then call j?  4
 do j5 =j4 +(j4 >0) to h;if w.j5 +w4 >m then iterate  j4; w5=w4 +w.j5 ; z5=z4 +v.j5 ;if  z5>$ then call j?  5
 do j6 =j5 +(j5 >0) to h;if w.j6 +w5 >m then iterate  j5; w6=w5 +w.j6 ; z6=z5 +v.j6 ;if  z6>$ then call j?  6
 do j7 =j6 +(j6 >0) to h;if w.j7 +w6 >m then iterate  j6; w7=w6 +w.j7 ; z7=z6 +v.j7 ;if  z7>$ then call j?  7
 do j8 =j7 +(j7 >0) to h;if w.j8 +w7 >m then iterate  j7; w8=w7 +w.j8 ; z8=z7 +v.j8 ;if  z8>$ then call j?  8
 do j9 =j8 +(j8 >0) to h;if w.j9 +w8 >m then iterate  j8; w9=w8 +w.j9 ; z9=z8 +v.j9 ;if  z9>$ then call j?  9
 do j10=j9 +(j9 >0) to h;if w.j10+w9 >m then iterate  j9;w10=w9 +w.j10;z10=z9 +v.j10;if z10>$ then call j? 10
 do j11=j10+(j10>0) to h;if w.j11+w10>m then iterate j10;w11=w10+w.j11;z11=z10+v.j11;if z11>$ then call j? 11
 do j12=j11+(j11>0) to h;if w.j12+w11>m then iterate j11;w12=w11+w.j12;z12=z11+v.j12;if z12>$ then call j? 12
 do j13=j12+(j12>0) to h;if w.j13+w12>m then iterate j12;w13=w12+w.j13;z13=z12+v.j13;if z13>$ then call j? 13
 do j14=j13+(j13>0) to h;if w.j14+w13>m then iterate j13;w14=w13+w.j14;z14=z13+v.j14;if z14>$ then call j? 14
 do j15=j14+(j14>0) to h;if w.j15+w14>m then iterate j14;w15=w14+w.j15;z15=z14+v.j15;if z15>$ then call j? 15
 do j16=j15+(j15>0) to h;if w.j16+w15>m then iterate j15;w16=w15+w.j16;z16=z15+v.j16;if z16>$ then call j? 16
 do j17=j16+(j16>0) to h;if w.j17+w16>m then iterate j16;w17=w16+w.j17;z17=z16+v.j17;if z17>$ then call j? 17
 do j18=j17+(j17>0) to h;if w.j18+w17>m then iterate j17;w18=w17+w.j18;z18=z17+v.j18;if z18>$ then call j? 18
 do j19=j18+(j18>0) to h;if w.j19+w18>m then iterate j18;w19=w18+w.j19;z19=z18+v.j19;if z19>$ then call j? 19
 do j20=j19+(j19>0) to h;if w.j20+w19>m then iterate j19;w20=w19+w.j20;z20=z19+v.j20;if z20>$ then call j? 20
 do j21=j20+(j20>0) to h;if w.j21+w20>m then iterate j20;w21=w20+w.j21;z21=z20+v.j21;if z21>$ then call j? 21
 do j22=j21+(j21>0) to h;if w.j22+w21>m then iterate j21;w22=w21+w.j22;z22=z21+v.j22;if z22>$ then call j? 22
 do j23=j22+(j22>0) to h;if w.j23+w22>m then iterate j22;w23=w22+w.j23;z23=z22+v.j23;if z23>$ then call j? 23
 do j24=j23+(j23>0) to h;if w.j24+w23>m then iterate j23;w24=w23+w.j24;z24=z23+v.j24;if z24>$ then call j? 24
 do j25=j24+(j24>0) to h;if w.j25+w24>m then iterate j24;w25=w24+w.j25;z25=z24+v.j25;if z25>$ then call j? 25
 do j26=j25+(j25>0) to h;if w.j26+w25>m then iterate j25;w26=w25+w.j26;z26=z25+v.j26;if z26>$ then call j? 26
 do j27=j26+(j26>0) to h;if w.j27+w26>m then iterate j26;w27=w26+w.j27;z27=z26+v.j27;if z27>$ then call j? 27
 do j28=j27+(j27>0) to h;if w.j28+w27>m then iterate j27;w28=w27+w.j28;z28=z27+v.j28;if z28>$ then call j? 28
 do j29=j28+(j28>0) to h;if w.j29+w28>m then iterate j28;w29=w28+w.j29;z29=z28+v.j29;if z29>$ then call j? 29
 do j30=j29+(j29>0) to h;if w.j30+w29>m then iterate j29;w30=w29+w.j30;z30=z29+v.j30;if z30>$ then call j? 30
 do j31=j30+(j30>0) to h;if w.j31+w30>m then iterate j30;w31=w30+w.j31;z31=z30+v.j31;if z31>$ then call j? 31
 do j32=j31+(j31>0) to h;if w.j32+w31>m then iterate j31;w32=w31+w.j32;z32=z31+v.j32;if z32>$ then call j? 32
 do j33=j32+(j32>0) to h;if w.j33+w32>m then iterate j32;w33=w32+w.j33;z33=z32+v.j33;if z33>$ then call j? 33
 do j34=j33+(j33>0) to h;if w.j34+w33>m then iterate j33;w34=w33+w.j34;z34=z33+v.j34;if z34>$ then call j? 34
 do j35=j34+(j34>0) to h;if w.j35+w34>m then iterate j34;w35=w34+w.j35;z35=z34+v.j35;if z35>$ then call j? 35
 do j36=j35+(j35>0) to h;if w.j36+w35>m then iterate j35;w36=w35+w.j36;z36=z35+v.j36;if z36>$ then call j? 36
 do j37=j36+(j36>0) to h;if w.j37+w36>m then iterate j36;w37=w36+w.j37;z37=z36+v.j37;if z37>$ then call j? 37
 end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end;end
     end;end;end;end;end;end;end;end;end;end;        return      /* [↑]  there is one END for each DO loop.*/


# Item struct to represent each item in the problem
Struct.new('Item', :name, :weight, :value, :count)

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

def choose_item(weight, id, cache)
  return 0, [] if id < 0

  k = [weight, id]
  return cache[k] unless cache[k].nil?
  value = $items[id].value
  best_v = 0
  best_list = []
  ($items[id].count+1).times do |i|
    wlim = weight - i * $items[id].weight
    break if wlim < 0
    val, taken = choose_item(wlim, id - 1, cache)
    if val + i * value > best_v
      best_v = val + i * value
      best_list = taken + [i]
    end
  end
  cache[k] = [best_v, best_list]
  return [best_v, best_list]
end

val, list = choose_item(400, $items.length - 1, {})
w = 0
list.each_with_index do |cnt, i|
  if cnt > 0
    print "#{cnt} #{$items[i].name}\n"
    w += $items[i][1] * cnt
  end
end

p "Total weight: #{w}, Value: #{val}"


/* create SAS data set */
data mydata;
   input item $1-23 weight value pieces;
   datalines;
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
;

/* 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};
   num pieces {ITEMS};
   read data mydata into ITEMS=[item] weight value pieces;

   /* declare variables, objective, and constraints */
   var NumSelected {i in ITEMS} >= 0 <= pieces[i] integer;
   max TotalValue = sum {i in ITEMS} value[i] * NumSelected[i];
   con WeightCon:
      sum {i in ITEMS} weight[i] * NumSelected[i] <= 400;

   /* call mixed integer linear programming (MILP) solver */
   solve;

   /* print optimal solution */
   print TotalValue;
   print {i in ITEMS: NumSelected[i].sol > 0.5} NumSelected;
quit;


var raw = <<'TABLE'
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      1
suntancream  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
TABLE

struct KnapsackItem {
    String name,
    Number weight,
    Number value,
    Number quant,
}

var items = []
raw.each_line{ |row|
    var fields = row.words;
    items << KnapsackItem(
          name: fields[0],
        weight: fields[1].to_n,
         value: fields[2].to_n,
         quant: fields[3].to_n,
    )
}

func pick(weight, pos) is cached {

    if (pos.is_neg || weight.is_neg || weight.is_zero) {
        return (0, 0, [])
    }

    var (bv=0, bi=0, bw=0, bp=[])
    var item = items[pos];

    for i in range(0, item.quant) {
        break if (i*item.weight > weight)
        var (v, w, p) = pick(weight - i*item.weight, pos.dec)
        next if ((v += i*item.value) <= bv)
        (bv, bi, bw, bp) = (v, i, w, p)
    }

    (bv, bw + bi*item.weight, [bp..., bi])
}

var (v, w, p) = pick(400, items.end)
p.range.each { |i|
    say "#{p[i]} of #{items[i].name}" if p[i].is_pos
}
say "Value: #{v}; Weight: #{w}"


public struct KnapsackItem: Hashable {
  public var name: String
  public var weight: Int
  public var value: Int

  public init(name: String, weight: Int, value: Int) {
    self.name = name
    self.weight = weight
    self.value = value
  }
}

public func knapsack(items: [KnapsackItem], limit: Int) -> [KnapsackItem] {
  var table = Array(repeating: Array(repeating: 0, count: limit + 1), count: items.count + 1)

  for j in 1...items.count {
    let item = items[j-1]

    for w in 1...limit {
      if item.weight > w {
        table[j][w] = table[j-1][w]
      } else {
        table[j][w] = max(table[j-1][w], table[j-1][w-item.weight] + item.value)
      }
    }
  }

  var result = [KnapsackItem]()
  var w = limit

  for j in stride(from: items.count, to: 0, by: -1) where table[j][w] != table[j-1][w] {
    let item = items[j-1]

    result.append(item)

    w -= item.weight
  }

  return result
}

typealias GroupedItem = (name: String, weight: Int, val: Int, n: Int)

let groupedItems: [GroupedItem] = [
  ("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)
]

let items = groupedItems.flatMap({item in
  (0..<item.n).map({_ in KnapsackItem(name: item.name, weight: item.weight, value: item.val) })
})

let bagged = knapsack(items: items, limit: 400)
let (totalVal, totalWeight) = bagged.reduce((0, 0), {cur, item in (cur.0 + item.value, cur.1 + item.weight) })

print("Bagged the following \(bagged.count) items:")

for item in bagged {
  print("\t\(item.name)")
}

print("For a total value of \(totalVal) and weight of \(totalWeight)")


# The list of items to consider, as list of lists
set items {
    {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}
}

# Simple extraction functions
proc countednames {chosen} {
    set names {}
    foreach item $chosen {
	lappend names [lindex $item 3] [lindex $item 0]
    }
    return $names
}
proc weight {chosen} {
    set weight 0
    foreach item $chosen {
	incr weight [expr {[lindex $item 3] * [lindex $item 1]}]
    }
    return $weight
}
proc value {chosen} {
    set value 0
    foreach item $chosen {
	incr value [expr {[lindex $item 3] * [lindex $item 2]}]
    }
    return $value
}

# Recursive function for searching over all possible choices of items
proc knapsackSearch {items {chosen {}}} {
    # If we've gone over the weight limit, stop now
    if {[weight $chosen] > 400} {
	return
    }
    # If we've considered all of the items (i.e., leaf in search tree)
    # then see if we've got a new best choice.
    if {[llength $items] == 0} {
	global best max
	set v [value $chosen]
	if {$v > $max} {
	    set max $v
	    set best $chosen
	}
	return
    }
    # Branch, so recurse for chosing the current item or not
    set this [lindex $items 0]
    set rest [lrange $items 1 end]
    knapsackSearch $rest $chosen
    for {set i 1} {$i<=[lindex $this 3]} {incr i} {
	knapsackSearch $rest \
	    [concat $chosen [list [lreplace $this end end $i]]]
    }
}

# Initialize a few global variables
set best {}
set max 0
# Do the brute-force search
knapsackSearch $items
# Pretty-print the results
puts "Best filling has weight of [expr {[weight $best]/100.0}]kg and score [value $best]"
puts "Best items:"
foreach {count item} [countednames $best] {
    puts "\t$count * $item"
}


#import std
#import flo
#import lin

items = # name: (weight,value,limit)

<
   '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)>

system = # convert the item list to mixed integer programming problem specification

linear_system$[
   integers: ~&nS,
   upper_bounds: * ^|/~& [email protected],
   lower_bounds: @nS ~&\*0.+ :/'(slack)',
   costs: * ^|/~& negative+ [email protected],
   equations: ~&iNC\400.+ :/(1.,'(slack)')+ * ^|rlX/~& [email protected]]

format = @t --^*p\pad` @nS @mS printf/*'%0.0f '

#show+

main =  format solution system items


import "/fmt" for Fmt

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

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

var items = [
    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)
]

var n = items.count
var maxWeight = 400

var knapsack = Fn.new { |w|
    var m = List.filled(n + 1, null)
    for (i in 0..n) m[i] = List.filled(w + 1, 0)
    for (i in 1..n) {
        for (j in 0..w) {
            m[i][j] = m[i-1][j]
            for (k in 1..items[i - 1].count) {
                if (k * items[i - 1].weight > j) break
                var v = m[i - 1][j - k * items[i - 1].weight] + k * items[i - 1].value
                if (v > m[i][j]) m[i][j] = v
            }
        }
    }
    var s = List.filled(n, 0)
    var j = w
    for (i in n..1) {
        var v = m[i][j]
        var k = 0
        while (v != m[i - 1][j] + k * items[i - 1].value) {
            s[i - 1] = s[i - 1] + 1
            j = j - items[i - 1].weight
            k = k + 1
        }
    }
    return s
}

var s = knapsack.call(maxWeight)
System.print("Item Chosen             Weight Value  Number")
System.print("---------------------   ------ -----  ------")
var itemCount = 0
var sumWeight = 0
var sumValue  = 0
var sumNumber = 0
for (i in 0... n) {
       if (s[i] != 0) {
           itemCount  = itemCount + 1
           var name   = items[i].name
           var number = s[i]
           var weight = items[i].weight * number
           var value  = items[i].value  * number
           sumNumber  = sumNumber + number
           sumWeight  = sumWeight + weight
           sumValue   = sumValue + value
           Fmt.print("$-22s    $3d   $4d    $2d", name, weight, value, number)
       }
}
System.print("---------------------   ------ -----  ------")
Fmt.print("Items chosen $d           $3d   $4d    $2d", itemCount, sumWeight, sumValue, sumNumber)


fcn addItem(old,[(nm,w,v,c)]){  // old:list:(cost of:,(name,#,...))
   [1..c].reduce(fcn(list,i,nm,w,v,old){
      wi,left,right:=w*i,list[0,wi],list[wi,*];
      new:=old.apply('wrap([(val,itms)]){ T(val + v*i,itms.append(nm,i)) });
      left.extend(right.zipWith(  // inc
	    fcn([(v1,_)]a,[(v2,_)]b){ v1>v2 and a or b  },new));
   },old,nm,w,v,old);
}//--> new list


L(ln) File(‘data.txt’).read_lines()
   I Float(ln.split(‘ ’, group_delimiters' 1B)[2]) > 6
      print(ln)


FCB1:	equ	5Ch	; FCB for first command line argument
puts:	equ	9	; CP/M syscall to print a string
fopen:	equ	15	; CP/M syscall to open a file
fread:	equ	20	; CP/M syscall to read a block from a file
dta:	equ	80h	; Default disk transfer address
	org	100h
	lxi	d,FCB1	; Try to open the file given on the command line
	mvi	c,fopen
	call	5
	inr	a	; A = 0 = error
	jz	err
	lxi	h,line	; Start of line buffer
block:	push	h	; Keep line buffer pointer
	lxi	d,FCB1	; Read a block from the file
	mvi	c,fread
	call	5
	pop	h	; Restore line buffer pointer
	dcr	a	; A = 1 = end of file (done)
	rz
	inr	a	; otherwise, A <> 0 = read error
	jnz	err
	lxi	d,dta	; Start of block
char:	ldax	d	; Grab character from block
	mov	m,a	; Store in line buffer
	inx	h	; Advance line buffer pointer
	cpi	10	; End of line?
	cz	doline	; Then handle the line
	inr	e	; Next character in block
	jz	block	; Rollover = get new block
	jmp	char 	; Otherwise = get next char
	;;;	Handle a line
doline:	push	d	; Keep block pointer
	mvi	m,'$'	; Terminate line buffer with CP/M end-of-string marker
	mvi	a,32
scan1:	dcx	h	; Scan backwards from end of line until we find
	cmp	m	; a non-control/whitespace character
	jnc	scan1	; (this makes it newline-format agnostic)
scan2:	dcx	h	; Then scan backwards until we _do_ find whitespace
	cmp	m	; This should leave us pointing right before the number
	jc	scan2
	inx	h	; First digit - we can cheat a little since we know
	mov	a,m	; earthquakes >=10 are physically impossible
	cpi	'7'	; If 7 or larger we know we should print it
	jnc	print
	cpi	'6' 	; If smaller than 6 we know we mustn't print it
	jc	next
	inx	h	; If 6, we must check fractional part
	mov	a,m
	cpi	'.'	; If no fractional part, then it is exactly 6 so
	jnz	next	; we shouldn't print it
scan3:	inx	h
	mov	a,m
	cpi	'$'	; If we reach the end, don't print it
	jz	next
	cpi	'1' 	; But if fractional part > 0, do print it
	jc	scan3
print:	lxi	d,line	; Print the line
	mvi	c,puts
	call	5
next:	pop	d	; Restore block pointer
	lxi	h,line	; Put line buffer pointer back at beginning
	ret
err:	lxi	d,emsg	; Print error message and stop
	mvi	c,puts
	jmp	5
emsg:	db	'Error!$'
line:	equ	$	; Line buffer after program


INCLUDE "H6:REALMATH.ACT"

BYTE FUNC FindFirstNonspace(CHAR ARRAY s BYTE start)
  WHILE start<=s(0) AND s(start)=32
  DO
    start==+1
  OD
RETURN (start)

BYTE FUNC FindFirstSpace(CHAR ARRAY s BYTE start)
  WHILE start<=s(0) AND s(start)#32
  DO
    start==+1
  OD
RETURN (start)

BYTE FUNC Found(CHAR ARRAY s REAL POINTER value)
  BYTE pos,v
  CHAR ARRAY sub

  pos=FindFirstNonspace(s,1)
  pos=FindFirstSpace(s,pos)
  pos=FindFirstNonspace(s,pos)
  pos=FindFirstSpace(s,pos)
  pos=FindFirstNonspace(s,pos)
  IF pos>s(0) THEN RETURN (0) FI

  SCopyS(sub,s,pos,s(0))
  ValR(sub,v)
  IF RealGreaterOrEqual(value,v)=0 THEN
    RETURN (1)
  FI
RETURN (0)

PROC Process(CHAR ARRAY fname REAL POINTER value BYTE search)
  CHAR ARRAY line(255)
  BYTE dev=[1]

  Close(dev)
  Open(dev,fname,4)
  WHILE Eof(dev)=0
  DO
    InputSD(dev,line)
    IF search=0 OR Found(line,value)=1 THEN
      PrintE(line)
    FI
  OD
  Close(dev)
RETURN

PROC Main()
  CHAR ARRAY fname="H6:QUAKES.TXT"
  REAL value

  Put(125) PutE() ;clear the screen
  IntToReal(6,value)
  PrintF("Reading ""%S""...%E%E",fname)
  Process(fname,value,0)
  PutE()
  Print("Searching for earthquakes > ")
  PrintRE(value) PutE()
  Process(fname,value,1)
RETURN


-- Kernighans large earthquake problem
with Ada.Text_IO;       use Ada.Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
use Ada.Strings;

procedure Main is
   Inpt_File : File_Type;
   Space     : Natural;
begin
   Open (File => Inpt_File, Mode => In_File, Name => "data.txt");
   while not End_Of_File (Inpt_File) loop
      declare
         Line : String :=
           Trim (Source => Get_Line (File => Inpt_File), Side => Both);
      begin

         if Line'Length > 0 then
            Space := Line'Last;
            loop
               exit when Line (Space) = ' ' or else Space = 0;
               Space := Space - 1;
            end loop;

            if Space > 0 then
               if Float'Value (Line (Space .. Line'Last)) > 6.0 then
                  Put_Line (Line);
               end if;
            end if;
         end if;
      end;
   end loop;
   Close (Inpt_File);
end Main;


IF  FILE input file;
    STRING file name = "data.txt";
    open( input file, file name, stand in channel ) /= 0
THEN
    # failed to open the file #
    print( ( "Unable to open """ + file name + """", newline ) )
ELSE
    # file opened OK #
    BOOL at eof := FALSE;
    # set the EOF handler for the file #
    on logical file end( input file, ( REF FILE f )BOOL:
                                     BEGIN
                                         # note that we reached EOF on the latest read #
                                         at eof := TRUE;
                                         # return TRUE so processing can continue #
                                         TRUE
                                     END
                       );
    # return the real value of the specified field on the line #
    PROC real field = ( STRING line, INT field )REAL:
         BEGIN
            REAL result  := 0;
            INT  c pos   := LWB line;
            INT  max pos := UPB line;
            STRING f     := "";
            FOR f ield number TO field WHILE c pos <= max pos DO
                # skip leading spaces #
                WHILE IF c pos > max pos THEN FALSE ELSE line[ c pos ] = " " FI DO
                    c pos +:= 1
                OD;
                IF c pos <= max pos THEN
                    # have a field #
                    INT start pos = c pos;
                    WHILE IF c pos > max pos THEN FALSE ELSE line[ c pos ] /= " " FI DO
                        c pos +:= 1
                    OD;
                    IF field number = field THEN
                        # have the required field #
                        f := line[ start pos : c pos - 1 ]
                    FI
                FI
            OD;
            IF f /= "" THEN
                # have the field - assume it a real value and convert it #
                FILE real value;
                associate( real value, f );
                on value error( real value
                              , ( REF FILE f )BOOL:
                                     BEGIN
                                         # "handle" invalid data #
                                         result := 0;
                                         # return TRUE so processing can continue #
                                         TRUE
                                     END
                              );
                get( real value, ( result ) )
            FI;
            result
         END # real field # ;
    # show the lines where the third field is > 6 #
    WHILE NOT at eof
    DO
        STRING line;
        get( input file, ( line, newline ) );
        IF real field( line, 3 ) > 6 THEN
            print( ( line, newline ) )
        FI
    OD;
    # close the file #
    close( input file )
FI


/* Kernighans large earthquake problem. */

#include <flow.h>
#include <flow-flow.h>

#define MAX_LINE 1000

DEF-MAIN(argv,argc)
   MSET(fd, Event )
   TOK-INIT
   OPEN-INPUT("datos.txt")(fd)
   COND( IS-NOT-FILE-ERROR? )
      TOK-SEP( " " ), TOK(3)
      WHILE( NOT( EOF(fd) ) )
         LET( Event := USING(MAX_LINE) READ-LINE(fd) APPLY-TRM )
         WHEN( LEN(Event) ){
            WHEN( GT?( VAL(TOK-GET(Event)), 6 ) ){
               PRNL( Event )
            }
         }
      WEND
      CLOSE(fd)
   ELS
      PRNL("Error: ", ~GET-STR-FILE-ERROR )
   CEND
END


on kernighansEarthquakes(magnitudeToBeat)
    -- A local "owner" for the long AppleScript lists. Speeds up references to their items and properties.
    script o
        property individualEntries : {}
        property qualifyingEntries : {}
    end script

    -- Read the text file assuming it's UTF-8 encoded and get a list of the individual entries.
    set textFilePath to (path to desktop as text) & "data.txt"
    set earthquakeData to (read file textFilePath as «class utf8»)
    set o's individualEntries to earthquakeData's paragraphs
    -- Get the input magnitude in text form now rather than coercing it during the repeat.
    set magnitudeToBeat to magnitudeToBeat as text

    -- Check the entries with AppleScript's text item delimiters set to likely white space characters and considering numeric strings.
    -- With these delimiters, the entries' magnitudes will be the last 'text item' in each line
    -- (assuming for this exercise that there'll never be white space at the end of any of the lines).
    -- Store entries with qualifying magnitudes in a new list.
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to {space, tab, character id 160} -- White space characters.
    considering numeric strings -- Compare numbers in strings numerically instead of lexically.
        repeat with i from 1 to (count o's individualEntries)
            set thisEntry to item i of o's individualEntries
            if (thisEntry's last text item > magnitudeToBeat) then set end of o's qualifyingEntries to thisEntry
        end repeat
    end considering

    -- Coerce the list of qualifying earthquakes to a single, linefeed-delimited text and return the result.
    set AppleScript's text item delimiters to linefeed
    set largeEarthquakes to o's qualifyingEntries as text
    set AppleScript's text item delimiters to astid

    return largeEarthquakes
end kernighansEarthquakes

kernighansEarthquakes(6)


quakes←{
    ⍺←6
    nl←⎕UCS 13 10
    file←80 ¯1⎕MAP ⍵
    lines←((~file∊nl)⊆file)~¨⊂nl
    keep←⍺{0::0 ⋄ ⍺ < ⍎3⊃(~⍵∊4↑⎕TC)⊆⍵}¨lines
    ↑keep/lines
}


data: {
    3/13/2009    CostaRica           5.1
    8/27/1883    Krakatoa            8.8
    5/18/1980    MountStHelens       7.6
}

define :earthquake [date place magnitude][]

print first sort.descending.by:'magnitude map split.lines data =>
    [to :earthquake split.words &]


#!/bin/bash
while read line
do
    [[ ${line##* } =~ ^([7-9]|6\.0*[1-9]).*$ ]] && echo "$line"
done < data.txt


f = freefile
filename$ = "data.txt"
open f, filename$

dim tok$(1)
while not eof(f)
	tok$[] = readline(f)
	if (right(tok$[], 4)) > 6 then print tok$[]
end while
close f
end


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

int main() {
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    char *lw, *lt;
    fp = fopen("data.txt", "r");
    if (fp == NULL) {
        printf("Unable to open file\n");
        exit(1);
    }
    printf("Those earthquakes with a magnitude > 6.0 are:\n\n");
    while ((read = getline(&line, &len, fp)) != EOF) {
        if (read < 2) continue;   /* ignore blank lines */
        lw = strrchr(line, ' ');  /* look for last space */
        lt = strrchr(line, '\t'); /* look for last tab */
        if (!lw && !lt) continue; /* ignore lines with no whitespace */
        if (lt > lw) lw = lt;     /* lw points to last space or tab */
        if (atof(lw + 1) > 6.0) printf("%s", line);
    }
    fclose(fp);
    if (line) free(line);
    return 0;
}


using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    static void Main() {
        foreach (var earthquake in LargeEarthquakes("data.txt", 6))
            Console.WriteLine(string.Join(" ", earthquake));
    }

    static IEnumerable<string[]> LargeEarthquakes(string filename, double limit) =>
        from line in File.ReadLines(filename)
        let parts = line.Split(default(char[]), StringSplitOptions.RemoveEmptyEntries)
        where double.Parse(parts[2]) > limit
        select parts;

}


// Randizo was here!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    ifstream file("../include/earthquake.txt");

    int count_quake = 0;
    int column = 1;
    string value;
    double size_quake;
    string row = "";

    while(file >> value)
    {
        if(column == 3)
        {
            size_quake = stod(value);

            if(size_quake>6.0)
            {
                count_quake++;
                row += value + "\t";
                cout << row << endl;
            }

            column = 1;
            row = "";
        }
        else
        {
            column++;
            row+=value + "\t";
        }
    }

    cout << "\nNumber of quakes greater than 6 is " << count_quake << endl;

    return 0;
}


use: cx;

'data.txt' `r fopen lines {
  let: (time place mag) @@s split ..;
  let: (m1 m2) $mag @. split &int map ..;
  $m1 6 >= $m2 0 > and {[$time @@s $place @@s $mag] say} if
} for


      *>
      *> Kernighan large earthquake problem
      *> Tectonics: cobc -xj kernighan-earth-quakes.cob
      *>            quakes.txt with the 3 sample lines
      *>            ./kernighan-earth-quakes
      *>
       >>SOURCE FORMAT IS FREE
       identification division.
       program-id. quakes.

       environment division.
       configuration section.
       repository.
           function all intrinsic.

       input-output section.
       file-control.
           select quake-data
           assign to command-filename
           organization is line sequential
           status is quake-fd-status
           .

       data division.
       file section.
       fd quake-data record varying depending on line-length.
           01 data-line       pic x(32768).

       working-storage section.
       01 quake-fd-status pic xx.
          88 ok values "00", "01", "02", "03", "04",
                       "05", "06", "07", "08", "09".
          88 no-more value "10".
          88 io-error value high-value.

       01 line-length usage binary-long.

       01 date-time pic x(10).
       01 quake pic x(20).
       01 magnitude pic 99v99.

       01 command-filename pic x(80).

       procedure division.
       show-big-ones.

       accept command-filename from command-line
       if command-filename equal spaces then
           move "data.txt" to command-filename
       end-if

       open input quake-data
       perform status-check
       if io-error then
           display trim(command-filename) " not found" upon syserr
           goback
       end-if

       read quake-data
       perform status-check
       perform until no-more or io-error
           unstring data-line delimited by all spaces
              into date-time quake magnitude
           end-unstring

           if magnitude greater than 6
               display date-time space quake space magnitude
           end-if

           read quake-data
           perform status-check
       end-perform

       close quake-data
       perform status-check
       goback.
      *> ****

       status-check.
       if not ok and not no-more then   *> not normal status, bailing
           display "io error: " quake-fd-status upon syserr
           set io-error to true
       end-if
       .

       end program quakes.


include "cowgol.coh";
include "file.coh";

# Process a file line by line
interface LineCb(line: [uint8]);
sub ForEachLine(fcb: [FCB], cb: LineCb) is
    var buf: uint8[256];
    var ptr := &buf[0];

    var length := FCBExt(fcb);
    while length != 0 loop
        var ch := FCBGetChar(fcb);
        [ptr] := ch;
        ptr := @next ptr;
        if ch == '\n' then
            [ptr] := 0;
            ptr := &buf[0];
            cb(&buf[0]);
        end if;
        length := length - 1;
    end loop;
end sub;

# Get magnitude from line
# Cowgol does not support floating point arithmetic, so the integer and
# fractional parts are returned separately
sub magnitude(line: [uint8]): (i: uint8, frac: uint8) is
    i := 0;
    frac := 0;
    var col: uint8 := 1;
    var space: uint8 := 0;
    # scan ahead to 3rd column
    while col < 3 loop
        var ch := [line];
        line := @next line;
        if ch == 0 then break; end if;
        if ch <= ' ' then
            while ch <= ' ' and ch != 0 loop
                ch := [line];
                line := @next line;
            end loop;
            col := col + 1;
        end if;
    end loop;
    if ch == 0 then
        return; # no 3rd column
    end if;
    line := @prev line;

    var n: int32;
    var pos: [uint8];
    # grab integer part
    (n, pos) := AToI(line);
    if pos == line then
        return; # no value
    end if;
    i := n as uint8;
    if [pos] == '.' then
        # grab fractional part
        (n, pos) := AToI(@next pos);
        frac := n as uint8;
    end if;
end sub;

# Print any line that has a magnitude > 6
sub PrintIfGt6 implements LineCb is
    var i: uint8;
    var frac: uint8;
    (i, frac) := magnitude(line);
    if i > 6 or (i == 6 and frac > 0) then
        print(line);
    end if;
end sub;

# Open "data.txt" and scan each line
var quakes: FCB;
if FCBOpenIn(&quakes, "data.txt") != 0 then
    print("Error!\n");
    ExitWithError();
end if;

ForEachLine(&quakes, PrintIfGt6);


import std.conv : to;
import std.regex : ctRegex, split;
import std.stdio : File, writeln;

void main() {
    auto ctr = ctRegex!"\\s+";

    writeln("Those earthquakes with a magnitude > 6.0 are:");
    foreach (line; File("data.txt").byLineCopy) {
        auto parts = split(line, ctr);
        if (parts[2].to!double > 6.0) {
            writeln(line);
        }
    }
}


(with-temp-buffer
  (insert-file-contents "data.txt")
  (goto-char (point-min))
  (while (not (eobp))
    (let* ((line (buffer-substring (line-beginning-position)
                                   (line-end-position)))
           (magn (nth 2 (split-string line "\\s-+"))))
      (when (> (string-to-number magn) 6.0)
        (message line)))
    (forward-line 1)))


USING: io math math.parser prettyprint sequences splitting ;
IN: rosetta-code.kernighan

lines [ "\s" split last string>number 6 > ] filter .


Dim As Long f
f = Freefile
Dim As String nomArchivo = "data.txt"

If Open(nomArchivo For Input As #f)  Then
    Print "ERROR: No se pudo abrir " ; nomArchivo
    Sleep : End
End If

Dim As String tok(), lin
Do While Not Eof(f)
    Line Input #f, lin
    If Val(Right(lin, 3)) > 6 Then Print lin
Loop
Close #f
Sleep


package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    f, err := os.Open("data.txt")
    if err != nil {
        fmt.Println("Unable to open the file")
        return
    }
    defer f.Close()
    fmt.Println("Those earthquakes with a magnitude > 6.0 are:\n")
    input := bufio.NewScanner(f)
    for input.Scan() {
        line := input.Text()
        fields := strings.Fields(line)
        mag, err := strconv.ParseFloat(fields[2], 64)
        if err != nil {
            fmt.Println("Unable to parse magnitude of an earthquake")
            return
        }
        if mag > 6.0 {
            fmt.Println(line)
        }
    }
}


import java.util.regex.Pattern

class LargeEarthquake {
    static void main(String[] args) {
        def r = Pattern.compile("\\s+")
        println("Those earthquakes with a magnitude > 6.0 are:\n")
        def f = new File("data.txt")
        f.eachLine { it ->
            if (r.split(it)[2].toDouble() > 6.0) {
                println(it)
            }
        }
    }
}


import qualified Data.ByteString.Lazy.Char8 as C

main :: IO ()
main = do
  cs <- C.readFile "data.txt"
  mapM_ print $
    C.lines cs >>=
    (\x ->
        [ x
        | 6 < (read (last (C.unpack <$> C.words x)) :: Float) ])


NB. this program is designed for systems where the line ending is either LF or CRLF

NB. filename select_magnitude minimum
NB. default file is /tmp/famous.quakers

select_magnitude=: '/tmp/famous.quakers'&$: : (4 :0)
 data =. 1!:1 boxopen x       NB. read the file
 data =. data -. CR           NB. remove nasty carriage returns
 data =. ,&LF^:(LF~:{:) data  NB. append new line if none found
 lines =. [;._2 data          NB. split the literal based on the final character
 magnitudes =. ". _1&{::@(<;._2)@(,&' ')@deb"1 lines
 (y <: magnitudes) # lines
)


import java.io.BufferedReader;
import java.io.FileReader;

public class KernighansLargeEarthquakeProblem {

    public static void main(String[] args) throws Exception {
        try (BufferedReader reader  = new BufferedReader(new FileReader("data.txt")); ) {
            String inLine = null;
            while ( (inLine = reader.readLine()) != null ) {
                String[] split = inLine.split("\\s+");
                double magnitude = Double.parseDouble(split[2]);
                if ( magnitude > 6 ) {
                    System.out.println(inLine);
                }
            }
        }

    }

}


const fs = require("fs");
const readline = require("readline");

const args = process.argv.slice(2);
if (!args.length) {
    console.error("must supply file name");
    process.exit(1);
}

const fname = args[0];

const readInterface = readline.createInterface({
    input: fs.createReadStream(fname),
    console: false,
});

readInterface.on("line", (line) => {
    const fields = line.split(/\s+/);
    if (+fields[fields.length - 1] > 6) {
        console.log(line);
    }
});


jq -Rrn 'inputs | . as $line | [splits("  *") ] | select((.[2]|tonumber) > 6) | $line' data.txt


using DataFrames, CSV

df = CSV.File("kernighansproblem.txt", delim=" ", ignorerepeated=true,
    header=["Date", "Location", "Magnitude"], types=[DateTime, String, Float64],
    dateformat="mm/dd/yyyy") |> DataFrame

println(filter(row -> row[:Magnitude] > 6, df))


arg pop nip len dup

( [get nip]
  [drop drop "data.txt"]
) if

%f
dup "r" fopen !f
$f 0 < ( [drop "Could not open '" print print "' for reading" print -1 end ] [drop] ) if

[dup split 3 get tonum 6 > ( [drop print nl] [drop drop] ) if]
[$f fgets dup -1 #]
while

drop
$f fclose

"End " input


// Version 1.2.40

import java.io.File

fun main(args: Array<String>) {
    val r = Regex("""\s+""")
    println("Those earthquakes with a magnitude > 6.0 are:\n")
    File("data.txt").forEachLine {
        if (it.split(r)[2].toDouble() > 6.0) println(it)
    }
}


-- arg[1] is the first argument provided at the command line
for line in io.lines(arg[1] or "data.txt") do  -- use data.txt if arg[1] is nil
  magnitude = line:match("%S+$")
  if tonumber(magnitude) > 6 then print(line) end
end


Module Find_Magnitude  {
	data$={8/27/1883    Krakatoa            8.8
	5/18/1980    MountStHelens       7.6
	3/13/2009    CostaRica           5.1
	1/23/4567    EdgeCase1           6
	1/24/4567    EdgeCase2           6.0
	1/25/4567    EdgeCase3           6.1
	}
	Open "data.txt" for output as F
	Print #F, data$;
	Close #F
	Open "data.txt" for input as F
	While not eof(#F)
		Line Input #f, part$
		REM if val(mid$(part$,30))>6 then print part$
		if val(mid$(part$,rinstr(rtrim$(part$)," ")))>6 then print part$
	End While
	Close #F
}
Find_Magnitude


Import["data.txt", "Table"] // Select[Last /* GreaterThan[6]]


import strscans

for line in "data.txt".lines:
  var date, name: string
  var magnitude: float
  if scanf(line, "$+ $s$+ $s$f", date, name, magnitude):
    if magnitude > 6:
      echo line
  # else wrong line: ignore.


perl -n -e '/(\S+)\s*$/ and $1 > 6 and print' data.txt


with javascript_semantics
constant filename = "data.txt"
string text = iff(platform()=JS or not file_exists(filename)?"""
8/27/1883    Krakatoa            8.8
5/18/1980    MountStHelens       7.6
3/13/2009    CostaRica           5.1""" : get_text(filename))
sequence lines = split_any(text,"\r\n")
for i=1 to length(lines) do
    sequence r = scanf(lines[i],"%s %f")
    if length(r)=1 and r[1][2]>6 then
        printf(1,"%s\n",{lines[i]})
    end if
end for


argument tail nip len dup
if
    get nip
else
    drop drop "data.txt"
endif

dup "r" fopen
dup 0 < if drop "Could not open '" print print "' for reading" print -1 quit endif
nip

true
while
    dup fgets
    dup 0 < if
        drop false
    else
        dup split 3 get tonum 6 > if drop print else drop drop endif
        true
    endif
endwhile
fclose


<?php

// make sure filename was specified on command line
if ( ! isset( $argv[1] ) )
    die( 'Data file name required' );

// open file and check for success
if ( ! $fh = fopen( $argv[1], 'r' ) )
    die ( 'Cannot open file: ' . $argv[1] );

while ( list( $date, $loc, $mag ) = fscanf( $fh, "%s %s %f" ) ) {
    if ( $mag > 6 ) {
        printf( "% -12s % -19s %.1f\n", $date, $loc, $mag );
    }
}

fclose( $fh );


(load "@lib/misc.l")

(in "kernighan.txt"
   (until (eof)
      (let (Date (read)  Quake (read)  Mag (read))
     (when (> Mag 6)
        (prinl (align -10 Date) " " (align -15 Quake) " " Mag)))))
(bye)


:- initialization(main, main).

process_line(Line):-
    split_string(Line, "\s\t", "\s\t", [_, _, Magnitude_string]),
    read_term_from_atom(Magnitude_string, Magnitude, []),
    Magnitude > 6,
    !,
    writef('%w\n', [Line]).
process_line(_).

process_stream(Stream):-
    read_line_to_string(Stream, String),
    String \= end_of_file,
    !,
    process_line(String),
    process_stream(Stream).
process_stream(_).

process_file(File):-
    open(File, read, Stream),
    process_stream(Stream),
    close(Stream).

main([File]):-
    process_file(File),
    !.
main(_):-
    swritef(Message, 'File argument is missing\n', []),
    write(user_error, Message).


If OpenConsole() And ReadFile(0,"data.txt")
  PrintN("Those earthquakes with a magnitude > 6.0 are:")
  While Not Eof(0)
    buf$=Trim(ReadString(0))
    If ValF((StringField(buf$,CountString(buf$," ")+1," ")))>6.0
      PrintN(buf$)
    EndIf
  Wend
  CloseFile(0)
  Input()
EndIf


python -c '
with open("data.txt") as f:
    for ln in f:
        if float(ln.strip().split()[2]) > 6:
            print(ln.strip())'


#lang racket

(with-input-from-file "data/large-earthquake.txt"
  (λ ()
    (for ((s (in-port read-line))
          #:when (> (string->number (third (string-split s))) 6))
    (displayln s))))


/*REXX program to read a file containing a list of earthquakes:   date, site, magnitude.*/
parse arg iFID mMag .                            /*obtain optional arguments from the CL*/
if iFID=='' | iFID==","  then iFID= 'earthquakes.dat' /*Not specified?  Then use default*/
if mMag=='' | mMag==","  then mMag= 6                 /* "      "         "   "     "   */
#=0                                              /*# of earthquakes that meet criteria. */
   do j=0  while lines(iFID)\==0                 /*read all lines in the input file.    */
   if j==0  then say 'Reading from file: ' iFID  /*show the name of the file being read.*/
   parse value linein(iFID) with date site mag . /*parse three words from an input line.*/
   if mag<=mMag  then iterate                    /*Is the quake too small?  Then skip it*/
   #= # + 1;     if j==0  then say               /*bump the number of qualifying quakes.*/
   if #==1  then say center('date', 20, "═")     '=magnitude='     center("site", 20, '═')
   say               center(date, 20)      center(mag/1, 11)   '  '        site
   end   /*j*/                                   /*stick a fork in it,  we're all done. */
say
say
if j\==0  then say j  'records read from file: ' iFID
say
if j==0  then say er 'file    '          iFID           "   is empty or not found."
         else say #  ' earthquakes listed whose magnitude is  ≥ ' mMag