about summary refs log tree commit diff stats
path: root/nqueens.mu
blob: 7d9610278b24107dae1fba5b573f521da8ec6225 (plain) (blame)
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# http://rosettacode.org/wiki/N-queens_problem
# port of the Arc solution at http://arclanguage.org/item?id=19743

container square [
  rank:number
  file:number
]

def nqueens n:number, queens:address:list:square -> result:number [
  local-scope
  load-ingredients
  # if 'queens' is already long enough, print it and return
  added-so-far:number <- length queens
  {
    done?:boolean <- greater-or-equal added-so-far, n
    break-unless done?
    stash queens
    return 1
  }
  # still work to do
  next-rank:number <- copy 0
  {
    break-unless queens
    first:square <- first queens
    existing-rank:number <- get first, rank:offset
    next-rank <- add existing-rank, 1
  }
  result <- copy 0
  next-file:number <- copy 0
  {
    done?:boolean <- greater-or-equal next-file, n
    break-if done?
    curr:square <- merge next-rank, next-file
    {
      curr-conflicts?:boolean <- conflict? curr, queens
      break-if curr-conflicts?
      new-queens:address:list:square <- push curr, queens
      sub-result:number <- nqueens n, new-queens
      result <- add result, sub-result
    }
    next-file <- add next-file, 1
    loop
  }
]

def conflict? curr:square, queens:address:list:square -> result:boolean [
  local-scope
  load-ingredients
  result1:boolean <- conflicting-file? curr, queens
  reply-if result1, result1
  result2:boolean <- conflicting-diagonal? curr, queens
  reply result2
]

def conflicting-file? curr:square, queens:address:list:square -> result:boolean [
  local-scope
  load-ingredients
  curr-file:number <- get curr, file:offset
  {
    break-unless queens
    q:square <- first queens
    qfile:number <- get q, file:offset
    file-match?:boolean <- equal curr-file, qfile
    reply-if file-match?, 1/conflict-found
    queens <- rest queens
    loop
  }
  reply 0/no-conflict-found
]

def conflicting-diagonal? curr:square, queens:address:list:square -> result:boolean [
  local-scope
  load-ingredients
  curr-rank:number <- get curr, rank:offset
  curr-file:number <- get curr, file:offset
  {
    break-unless queens
    q:square <- first queens
    qrank:number <- get q, rank:offset
    qfile:number <- get q, file:offset
    rank-delta:number <- subtract qrank, curr-rank
    file-delta:number <- subtract qfile, curr-file
    rank-delta <- abs rank-delta
    file-delta <- abs file-delta
    diagonal-match?:boolean <- equal rank-delta, file-delta
    reply-if diagonal-match?, 1/conflict-found
    queens <- rest queens
    loop
  }
  reply 0/no-conflict-found
]
an class="o">='vimCodeElement'> <span class="Comment">//: Support literal non-integers.</span> <span class="Comment">//: '3.14159:literal' is ugly, so we'll just say '3.14159' for non-integers.</span> <span class="Delimiter">:(scenarios load)</span> <span class="Delimiter">:(scenario noninteger_literal)</span> recipe main [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">3.14159</span> ] <span class="traceContains">+parse: ingredient: {name: &quot;3.14159&quot;, properties: [&quot;3.14159&quot;: &quot;literal-number&quot;]}</span> <span class="Delimiter">:(after &quot;reagent::reagent(string s)&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_noninteger<span class="Delimiter">(</span>s<span class="Delimiter">))</span> <span class="Delimiter">{</span> name = s<span class="Delimiter">;</span> types<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> properties<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair&lt;string<span class="Delimiter">,</span> vector&lt;string&gt; &gt;<span class="Delimiter">(</span>name<span class="Delimiter">,</span> vector&lt;string&gt;<span class="Delimiter">()));</span> properties<span class="Delimiter">.</span>back<span class="Delimiter">().</span>second<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span><span class="Constant">&quot;literal-number&quot;</span><span class="Delimiter">);</span> set_value<span class="Delimiter">(</span>to_double<span class="Delimiter">(</span>s<span class="Delimiter">));</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(code)</span> <span class="Normal">bool</span> is_noninteger<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> s<span class="Delimiter">.</span>find_first_not_of<span class="Delimiter">(</span><span class="Constant">&quot;0123456789-.&quot;</span><span class="Delimiter">)</span> == string::npos &amp;&amp; s<span class="Delimiter">.</span>find<span class="Delimiter">(</span><span class="Constant">'.'</span><span class="Delimiter">)</span> != string::npos<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">double</span> to_double<span class="Delimiter">(</span>string n<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">char</span>* end = <span class="Constant">NULL</span><span class="Delimiter">;</span> <span class="Comment">// safe because string.c_str() is guaranteed to be null-terminated</span> <span class="Normal">double</span> result = strtod<span class="Delimiter">(</span>n<span class="Delimiter">.</span>c_str<span class="Delimiter">(),</span> &amp;end<span class="Delimiter">);</span> assert<span class="Delimiter">(</span>*end == <span class="cSpecial">'\0'</span><span class="Delimiter">);</span> <span class="Identifier">return</span> result<span class="Delimiter">;</span> <span class="Delimiter">}</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->