File: nu-example.nu

package info (click to toggle)
cloc 2.06-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,064 kB
  • sloc: perl: 30,146; cpp: 1,219; python: 623; ansic: 334; asm: 267; makefile: 244; sh: 186; sql: 144; java: 136; ruby: 111; cs: 104; pascal: 52; lisp: 50; haskell: 35; f90: 35; cobol: 35; objc: 25; php: 22; javascript: 15; fortran: 9; ml: 8; xml: 7; tcl: 2
file content (268 lines) | stat: -rw-r--r-- 8,114 bytes parent folder | download
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# Source: https://github.com/nushell/nu_scripts/blob/e82487722bce88c11f6b31788142b29e4c40bda4/games/paperclips/game.nu

# nu-niversal paperclips - a (somewhat) faithful clone of Universal Paperclips
# play the original at: https://www.decisionproblem.com/paperclips/index2.html

# NOTE: scalars are off cuz i'm counting by pennies instead of dollars and cents

const carriage_return = "\n\r"

# Resets cursor to home position and hides it to prevent visual distraction
def reset-cursor [] {
  print -n "\e[H"  # Move cursor to home position (top-left)
  print -n "\e[?25l"  # Hide cursor
}

# Clears all content from cursor position to end of screen
def clear-to-end [] {
  print -n "\e[J"  # Clear from cursor to end of screen
}

# Updates the terminal display with current game state
def refresh-game-view [state] {
  reset-cursor
  render-game-display $state
}

def make-paperclip [state, amount: int] {
  mut new_state = $state
  $new_state.paperclips.total += $amount
  $new_state.paperclips.stock += $amount
  $new_state.wire.length -= $amount
  $new_state.paperclips.current_second_clips += $amount  # Add this line
  $new_state
}

def sell-paperclips [state] {
  if $state.paperclips.stock == 0 { return $state }
  # numbers picked by the OG, i haven't sussed out exactly why.
  if (random float 0.0..1.0) > ($state.market.demand / 100) { return $state }
  mut amount = 0.7 * ($state.market.demand ** 1.15) | math floor
  if $amount > $state.paperclips.stock { $amount = $state.paperclips.stock }
  mut new_state = $state
  let transaction = $amount * $state.paperclips.price
  $new_state.money += $transaction
  $new_state.paperclips.stock -= $amount
  $new_state
}

def update-demand [state] {
  let marketing = 1.1 ** ($state.market.level - 1)
  mut new_state = $state
  $new_state.market.demand = ((.8 / $state.paperclips.price) * $marketing) * 1000
  $new_state
}

def get-user-input [] {
  let key = (input listen --types [key])
  if ($key.code == 'c') and ($key.modifiers == ['keymodifiers(control)']) {
    print -n "\e[?25h"  # Show cursor before exiting
    exit
  }
  $key.code | job send 0
}

def format-text [prefix: string, value: number, --money --round] {
  mut value = $value
  if $money {
    $value = $value / 100.0 | math round --precision 2
  }
  if $round {
    $value = $value | math round --precision 2
  }
  # e.g. "Paperclips: XXX\n\r" or "Unsold Inventory: $X.XX\n\r"
  $"($prefix): (if $money { "$" } else { })($value | into string --group-digits)(if $round { "%" } else { })($carriage_return)"
}

# Prints text after clearing the current line with ANSI escape code
def clear-line [text] {
  print -n $"\e[2K($text)"
}

def render-game-display [state] {
  # Game title and stats
  clear-line (format-text "Paperclips" $state.paperclips.total)
  clear-line $carriage_return

  # Business section
  clear-line "Business:\n\r"
  clear-line "---------------\n\r"
  clear-line (format-text 'Available Funds' $state.money --money)
  clear-line (format-text 'Unsold Inventory' $state.paperclips.stock)
  clear-line (format-text 'Price Per Clip' $state.paperclips.price --money)
  clear-line (format-text 'Public Demand' $state.market.demand --round)
  clear-line $carriage_return
  clear-line (format-text 'Marketing Level' $state.market.level)
  clear-line (format-text 'Marketing cost' $state.market.cost --money)
  clear-line $carriage_return

  # Manufacturing section
  clear-line "Manufacturing:\n\r"
  clear-line "---------------\n\r"
  clear-line (format-text 'Clips per Second' $state.paperclips.rate)
  clear-line $carriage_return

  # Wire section
  if $state.wire.length == 1 { "inch" } else { "inches" }
  clear-line $"Wire: ($state.wire.length | into string -g) (
    if $state.wire.length == 1 { "inch" } else { "inches" }
  )\n\r"
  clear-line (format-text 'Wire cost' $state.wire.cost --money)
  clear-line $carriage_return

  # Autoclippers (conditional)
  if $state.autoclippers.unlocked {
    clear-line (format-text "Autoclippers" $state.autoclippers.count)
    clear-line (format-text 'Autoclipper cost' $state.autoclippers.cost --money)
    clear-line $carriage_return
  }

  # Controls
  clear-line $"($state.control_line)\n\r"

  # Clean up any trailing content from previous longer displays
  clear-to-end
}

def main [] {
  reset-cursor
  print "Welcome to nu-niversal paperclips!"
  clear-to-end
  sleep 2sec
  reset-cursor
  let table_name = "clip_message_queue"

  mut state = {
    delta_time: 0sec
    paperclips: {
      total: 0
      stock: 0
      price: 25
      rate: 0  # Changed from -1 to 0: This will show last second's rate
      current_second_clips: 0  # Add: Accumulator for current second
    }
    last_second_timestamp: (date now)  # Add: Track when current second started
    market: {
      demand: 0
      level: 1
      cost: 10000
    }
    money: 0
    control_line: "controls: [a]dd paperclip; buy [w]ire; price [u]p; price [d]own; [q]uit"
    wire: {
      length: 1000
      cost: 2000
    }
    autoclippers: {
      count: 0
      unlocked: false
      cost: 1000
      multiplier: 1.25
    }
  }
  let save_exists = ('./gamestate.nuon' | path exists)
  if $save_exists {
    $state = open './gamestate.nuon'
  }
  # initial setup
  $state = update-demand $state
  refresh-game-view $state
  get-user-input

  loop {
    let seconds = $state.delta_time
    if ($seconds) > (1sec) {
      $state.delta_time -= $seconds
      # TODO: tweak numbers
      if (random bool --bias 0.5) {
        let deviation = (0.75 + (random float 0.0..0.50))
        $state.wire.cost *= $deviation
        if $state.wire.cost < 1200 {
          $state.wire.cost = 1200
        } else if $state.wire.cost > 3000 {
          $state.wire.cost = 3000
        }
      }
      $state = update-demand $state

      # Calculate total autoclipper production for this time period
      let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round
      mut index = 0
      while $index < $amount {
        $state = make-paperclip $state 1
        $index += 1
      }

      $state = sell-paperclips $state
    }
    let prev = date now

    # Check if a second has passed and roll over counters
    let now = date now
    if ($now - $state.last_second_timestamp) >= 1sec {
      $state.paperclips.rate = $state.paperclips.current_second_clips
      $state.paperclips.current_second_clips = 0
      $state.last_second_timestamp = $now
    }

    if (($state.paperclips.total > 9) and ($state.autoclippers.count < 1)) and not $state.autoclippers.unlocked {
      $state.autoclippers.unlocked = true
      $state.control_line += "; [b]uy autoclipper"
    }

    # Update display with current game state
    refresh-game-view $state

    try {
      let key = job recv --timeout 0sec
      match $key {
        "a" => {
          # TODO: add some way to grow amount?
          $state = make-paperclip $state 1
        }
        "b" => {
          if $state.money >= $state.autoclippers.cost {
            $state.money -= $state.autoclippers.cost
            $state.autoclippers.count += 1
            $state.autoclippers.cost = ($state.autoclippers.cost * 1.25 | math round)
          }
        }
        "d" => {
          if $state.paperclips.price > 1 {
            $state.paperclips.price -= 1
            $state = update-demand $state
          }
        }
        "q" => {
          if not $save_exists {
            $state | save gamestate.nuon
          } else {
            $state | save gamestate.nuon --force
          }
          print -n "\e[?25h"  # Show cursor before exiting
          break
        }
        "u" => {
          $state.paperclips.price += 1
          $state = update-demand $state
        }
        "w" => {
          if $state.money >= $state.wire.cost {
            $state.wire.length += 1000
            $state.money -= $state.wire.cost
          }
        }
        _ => {
          ""
        }
      }
      job spawn { get-user-input }
    }

    # for 60fps framerate lock
    sleep 16.666ms
    let now = date now
    let delta = $now - $prev
    $state.delta_time += $delta
  }
}