aboutsummaryrefslogtreecommitdiff
path: root/challenge-018/archargelod/nim/ch_2.nim
blob: 5da5e8e0dbfa521ebdb3219feb94c60bf06e93af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off
type
  PriorityQueue*[T] = object
    data: seq[tuple [item: T, priority: Natural]]

proc isEmpty*(q: PriorityQueue): bool =
  q.data.len == 0

proc add*[T](q: var PriorityQueue[T], item: sink T, priority: Natural = 0) =
  ## add item to the queue with specified priority
  ## 0 is max priority, 1 is less priority than 0 and so on
  proc findBestPos(data: seq[tuple [item: T, priority: Natural]], priority: int): int =
    # binary search
    var
      pivot = data.len div 2
      left = 0
      right = data.high

    while right - left > 1:
      if priority < data[pivot].priority:
        left = pivot
      else:
        right = pivot
      pivot = left + (right - left) div 2

    right

  if q.isEmpty or priority <= q.data[^1].priority:
    q.data.add (item, priority)
  elif priority > q.data[0].priority:
    q.data.insert((item, priority), 0)
  else:
    var pos = q.data.findBestPos(priority)
    q.data.insert((item, priority), pos)

proc pop*[T](q: var PriorityQueue[T]): T =
  ## remove the item with minimum priority value from the queue
  ## and return it
  if q.isEmpty:
    raise newException(ValueError, "can't pop value; the queue is empty")
  q.data.pop().item

when isMainModule:
  import std/unittest

  const
    Test = [
      ("World", 20),
      (",", 5),
      ("!", 1000),
      ("Hello", 0),
      (" ", 10),
    ]
    Expected = "Hello, World!"

  suite "Priority Queue":
    test "Hello world ordered with priority": 
      var queue: PriorityQueue[string]
      var res = newStringOfCap(Expected.len)
      for (word, prio) in Test:
        queue.add(word, prio)

      while not queue.isEmpty:
        res &= queue.pop()

      check res == Expected