From e7f04b3241c14f4004e5f44860bd58ec17f67af0 Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Tue, 29 Apr 2025 08:54:58 -0500 Subject: [PATCH 1/6] add paperclips v0.0 --- games/paperclips/game.nu | 82 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 games/paperclips/game.nu diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu new file mode 100644 index 00000000..0d66391b --- /dev/null +++ b/games/paperclips/game.nu @@ -0,0 +1,82 @@ +# job spawn { loop { $state.paperclips += $state.autoclippers.count; sleep 1sec } } + +def get-user-input [queue] { + # TODO: figure out how to get redrawing without waiting on the key + # maybe use a bg job, wait until job is done, then get result? + # and/or use the key stor, and/or use a local file? + let key = (input listen --types [key]) + # print $"pressed ($key); keycode = ($key.code)" + if ($key.code == 'c' or $key.code == 'q') and ($key.modifiers == ['keymodifiers(control)']) { + break + } + stor insert --table-name $queue --data-record {keycode: $key.code} +} + +def print-line [state] { + print $"paperclips: ($state.paperclips)" + if $state.autoclippers.unlocked { + print $"autoclipper cost: ($state.autoclippers.cost)" + } + print $state.control_line +} + +def main [] { + let table_name = "clip_message_queue" + stor create --table-name $table_name --columns {keycode: str} + # TODO: figure out persistence - saving and loading + mut state = { + delta_time: 0sec + paperclips: 0 + control_line: "controls: [a]dd paperclip; [q]uit" + autoclippers: { + count: 0 + unlocked: false + cost: 10 + multiplier: 1.25 + } + } + print-line $state + get-user-input $table_name + loop { + clear + let seconds = $state.delta_time + if ($seconds) > (1sec) { + $state.paperclips += (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round + $state.delta_time -= $seconds + } + let prev = date now + print-line $state + if (($state.paperclips > 8) and ($state.autoclippers.count < 1)) and not $state.autoclippers.unlocked { + $state.autoclippers.unlocked = true + $state.control_line += "; [b]uy autoclipper" + } + if (job list | length) == 0 { + let key = stor open | query db $"SELECT keycode FROM ($table_name)" | get keycode.0 + match $key { + "a" => { + $state.paperclips += 1 + } + "b" => { + if $state.paperclips >= $state.autoclippers.cost { + $state.paperclips -= $state.autoclippers.cost + $state.autoclippers.count += 1 + $state.autoclippers.cost = ($state.autoclippers.cost * 1.25 | math round) + } + } + "q" => { + break + } + _ => { + "" + } + } + stor delete --table-name $table_name --where-clause $"keycode == '($key)'" + job spawn { get-user-input $table_name } + } + # for 60fps framerate lock + sleep 0.01666666667sec + let now = date now + let delta = $now - $prev + $state.delta_time += $delta + } +} From 5fd8ee044a0d4512c0a328dbc2367a87a49cf9a7 Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:10:19 -0500 Subject: [PATCH 2/6] wire implemented! --- games/paperclips/game.nu | 63 ++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu index 0d66391b..75ee5834 100644 --- a/games/paperclips/game.nu +++ b/games/paperclips/game.nu @@ -1,9 +1,14 @@ -# job spawn { loop { $state.paperclips += $state.autoclippers.count; sleep 1sec } } +# nu-niversal paperclips - a (somewhat) faithful clone of Universal Paperclips +# play the original at: https://www.decisionproblem.com/paperclips/index2.html + +def buy-paperclip [state, amount: int] { + mut new_state = $state + $new_state.paperclips += $amount + $new_state.wire.length -= $amount + return $new_state +} def get-user-input [queue] { - # TODO: figure out how to get redrawing without waiting on the key - # maybe use a bg job, wait until job is done, then get result? - # and/or use the key stor, and/or use a local file? let key = (input listen --types [key]) # print $"pressed ($key); keycode = ($key.code)" if ($key.code == 'c' or $key.code == 'q') and ($key.modifiers == ['keymodifiers(control)']) { @@ -13,21 +18,33 @@ def get-user-input [queue] { } def print-line [state] { - print $"paperclips: ($state.paperclips)" + print -n $"paperclips: ($state.paperclips)\n\r" + print -n $"wire: ($state.wire.length) inches\n\r" + print -n $"wire cost: ($state.wire.cost)\n\r" if $state.autoclippers.unlocked { - print $"autoclipper cost: ($state.autoclippers.cost)" + print -n $"autoclippers: ($state.autoclippers.count)\n\r" + print -n $"autoclipper cost: ($state.autoclippers.cost)\n\r" } - print $state.control_line + print -n $"($state.control_line)\n\r" } def main [] { + clear + print "Welcome to nu-niversal paperclips!" + sleep 2sec + clear let table_name = "clip_message_queue" stor create --table-name $table_name --columns {keycode: str} - # TODO: figure out persistence - saving and loading mut state = { delta_time: 0sec paperclips: 0 - control_line: "controls: [a]dd paperclip; [q]uit" + # TODO: set to 0 when you have basic economy set up + money: 100 + control_line: "controls: [a]dd paperclip; buy [w]ire; [q]uit" + wire: { + length: 1000 + cost: 20 + } autoclippers: { count: 0 unlocked: false @@ -35,18 +52,23 @@ def main [] { multiplier: 1.25 } } + let save_exists = ('./gamestate.nuon' | path exists) + if $save_exists { + $state = open './gamestate.nuon' + } print-line $state get-user-input $table_name loop { clear let seconds = $state.delta_time if ($seconds) > (1sec) { - $state.paperclips += (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round + let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round + $state = buy-paperclip $state $amount $state.delta_time -= $seconds } let prev = date now print-line $state - if (($state.paperclips > 8) and ($state.autoclippers.count < 1)) and not $state.autoclippers.unlocked { + if (($state.paperclips > 9) and ($state.autoclippers.count < 1)) and not $state.autoclippers.unlocked { $state.autoclippers.unlocked = true $state.control_line += "; [b]uy autoclipper" } @@ -54,7 +76,8 @@ def main [] { let key = stor open | query db $"SELECT keycode FROM ($table_name)" | get keycode.0 match $key { "a" => { - $state.paperclips += 1 + # TODO: add some way to grow amount? + $state = buy-paperclip $state 1 } "b" => { if $state.paperclips >= $state.autoclippers.cost { @@ -64,8 +87,24 @@ def main [] { } } "q" => { + # if not $save_exists { + # $state | save gamestate.nuon + # } else { + # $state | save gamestate.nuon --force + # } break } + "w" => { + $state.wire.length += 1000 + # TODO: tweak numbers + if (random bool --bias 0.5) { + let deviation = (0.75 + (random float 0.0..0.50)) + $state.wire.cost += $deviation | math round + if $state.wire.cost < 12 { + $state.wire.cost = 12 + } + } + } _ => { "" } From c7bd547d973b8b9b216cf47b69ec6e95f88a376e Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Wed, 30 Apr 2025 09:26:43 -0500 Subject: [PATCH 3/6] move from stor to job mailbox --- games/paperclips/game.nu | 59 ++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu index 75ee5834..353507fa 100644 --- a/games/paperclips/game.nu +++ b/games/paperclips/game.nu @@ -1,6 +1,7 @@ # nu-niversal paperclips - a (somewhat) faithful clone of Universal Paperclips # play the original at: https://www.decisionproblem.com/paperclips/index2.html +# TODO: figure out how to display this visually... maybe just a quick loop? def buy-paperclip [state, amount: int] { mut new_state = $state $new_state.paperclips += $amount @@ -14,17 +15,19 @@ def get-user-input [queue] { if ($key.code == 'c' or $key.code == 'q') and ($key.modifiers == ['keymodifiers(control)']) { break } - stor insert --table-name $queue --data-record {keycode: $key.code} + # stor insert --table-name $queue --data-record {keycode: $key.code} + $key.code | job send 0 } def print-line [state] { print -n $"paperclips: ($state.paperclips)\n\r" print -n $"wire: ($state.wire.length) inches\n\r" - print -n $"wire cost: ($state.wire.cost)\n\r" + print -n $"wire cost: $($state.wire.cost / 100.0)\n\r" if $state.autoclippers.unlocked { print -n $"autoclippers: ($state.autoclippers.count)\n\r" - print -n $"autoclipper cost: ($state.autoclippers.cost)\n\r" + print -n $"autoclipper cost: $($state.autoclippers.cost / 100.0)\n\r" } + print -n $"money: $($state.money / 100.0)\n\r" print -n $"($state.control_line)\n\r" } @@ -34,21 +37,21 @@ def main [] { sleep 2sec clear let table_name = "clip_message_queue" - stor create --table-name $table_name --columns {keycode: str} + # stor create --table-name $table_name --columns {keycode: str} mut state = { delta_time: 0sec paperclips: 0 # TODO: set to 0 when you have basic economy set up - money: 100 + money: 100000 control_line: "controls: [a]dd paperclip; buy [w]ire; [q]uit" wire: { length: 1000 - cost: 20 + cost: 2000 } autoclippers: { count: 0 unlocked: false - cost: 10 + cost: 1000 multiplier: 1.25 } } @@ -58,13 +61,23 @@ def main [] { } print-line $state get-user-input $table_name + loop { clear let seconds = $state.delta_time if ($seconds) > (1sec) { - let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round - $state = buy-paperclip $state $amount $state.delta_time -= $seconds + let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round + mut index = 0 + while $index < $amount { + $state = buy-paperclip $state 1 + $index += 1 + clear + print-line $state + # TODO: figure out a better solution here + sleep 0.05sec + } + clear } let prev = date now print-line $state @@ -72,16 +85,18 @@ def main [] { $state.autoclippers.unlocked = true $state.control_line += "; [b]uy autoclipper" } - if (job list | length) == 0 { - let key = stor open | query db $"SELECT keycode FROM ($table_name)" | get keycode.0 + # if (job list | length) == 0 { + try { + # let key = stor open | query db $"SELECT keycode FROM ($table_name)" | get keycode.0 + let key = job recv --timeout 0sec match $key { "a" => { # TODO: add some way to grow amount? $state = buy-paperclip $state 1 } "b" => { - if $state.paperclips >= $state.autoclippers.cost { - $state.paperclips -= $state.autoclippers.cost + 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) } @@ -95,13 +110,15 @@ def main [] { break } "w" => { - $state.wire.length += 1000 - # TODO: tweak numbers - if (random bool --bias 0.5) { - let deviation = (0.75 + (random float 0.0..0.50)) - $state.wire.cost += $deviation | math round - if $state.wire.cost < 12 { - $state.wire.cost = 12 + if $state.money >= $state.wire.cost { + $state.wire.length += 1000 + # TODO: tweak numbers + if (random bool --bias 0.5) { + let deviation = (0.75 + (random float 0.0..0.50)) + $state.wire.cost += $deviation | math round + if $state.wire.cost < 12 { + $state.wire.cost = 12 + } } } } @@ -109,7 +126,7 @@ def main [] { "" } } - stor delete --table-name $table_name --where-clause $"keycode == '($key)'" + # stor delete --table-name $table_name --where-clause $"keycode == '($key)'" job spawn { get-user-input $table_name } } # for 60fps framerate lock From b2b64b432d7fa67e9e506b55c69825811db86857 Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:38:09 -0500 Subject: [PATCH 4/6] basic economy --- games/paperclips/game.nu | 91 +++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu index 353507fa..5fec575b 100644 --- a/games/paperclips/game.nu +++ b/games/paperclips/game.nu @@ -2,32 +2,64 @@ # play the original at: https://www.decisionproblem.com/paperclips/index2.html # TODO: figure out how to display this visually... maybe just a quick loop? -def buy-paperclip [state, amount: int] { +def make-paperclip [state, amount: int] { mut new_state = $state - $new_state.paperclips += $amount + $new_state.paperclips.total += $amount + $new_state.paperclips.stock += $amount $new_state.wire.length -= $amount return $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 + return $new_state +} + +def update-demand [state] { + let marketing = 1.1 ** ($state.market.level - 1) + mut new_state = $state + # this is off by 1000x??? figure out what you're doing wrong + $new_state.market.demand = ((.8 / $state.paperclips.price) * $marketing) * 1000 + return $new_state +} + def get-user-input [queue] { let key = (input listen --types [key]) # print $"pressed ($key); keycode = ($key.code)" - if ($key.code == 'c' or $key.code == 'q') and ($key.modifiers == ['keymodifiers(control)']) { - break + if ($key.code == 'c') and ($key.modifiers == ['keymodifiers(control)']) { + exit } # stor insert --table-name $queue --data-record {keycode: $key.code} $key.code | job send 0 } def print-line [state] { - print -n $"paperclips: ($state.paperclips)\n\r" - print -n $"wire: ($state.wire.length) inches\n\r" - print -n $"wire cost: $($state.wire.cost / 100.0)\n\r" + print -n $"Paperclips: ($state.paperclips.total | into string -g)\n\r\n\r" + print -n "Business:\n\r" + print -n "---------------\n\r" + print -n $"Avaulable Funds: $($state.money / 100.0 | into string -g)\n\r" + print -n $"Unsold Inventory: ($state.paperclips.stock | into string -g)\n\r" + print -n $"Price Per Clip: $($state.paperclips.price / 100.0 | into string -g)\n\r" + print -n $"Public Demand: ($state.market.demand | math round | into string -g)%\n\r\n\r" + print -n $"Marketing Level: ($state.market.level | into string -g)\n\r" + print -n $"Marketing cost: $($state.market.cost / 100.0 | into string -g)\n\r\n\r" + print -n "Manufacturing:\n\r" + print -n "---------------\n\r" + print -n $"Clips per Second: ($state.paperclips.rate)\n\r\n\r" + print -n $"Wire: ($state.wire.length | into string -g) inches\n\r" + print -n $"Wire cost: $($state.wire.cost / 100.0 | into string -g)\n\r\n\r" if $state.autoclippers.unlocked { - print -n $"autoclippers: ($state.autoclippers.count)\n\r" - print -n $"autoclipper cost: $($state.autoclippers.cost / 100.0)\n\r" + print -n $"autoclippers: ($state.autoclippers.count | into string -g)\n\r" + print -n $"autoclipper cost: $($state.autoclippers.cost / 100.0 | into string -g)\n\r" } - print -n $"money: $($state.money / 100.0)\n\r" print -n $"($state.control_line)\n\r" } @@ -40,10 +72,19 @@ def main [] { # stor create --table-name $table_name --columns {keycode: str} mut state = { delta_time: 0sec - paperclips: 0 - # TODO: set to 0 when you have basic economy set up - money: 100000 - control_line: "controls: [a]dd paperclip; buy [w]ire; [q]uit" + paperclips: { + total: 0 + stock: 0 + price: 25 + rate: "NOT IMPLEMENTED :(" + } + market: { + demand: 32 + 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 @@ -70,18 +111,19 @@ def main [] { let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round mut index = 0 while $index < $amount { - $state = buy-paperclip $state 1 + $state = make-paperclip $state 1 $index += 1 clear print-line $state # TODO: figure out a better solution here - sleep 0.05sec + sleep 16.666ms } + $state = sell-paperclips $state clear } let prev = date now print-line $state - if (($state.paperclips > 9) and ($state.autoclippers.count < 1)) and not $state.autoclippers.unlocked { + 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" } @@ -92,7 +134,7 @@ def main [] { match $key { "a" => { # TODO: add some way to grow amount? - $state = buy-paperclip $state 1 + $state = make-paperclip $state 1 } "b" => { if $state.money >= $state.autoclippers.cost { @@ -101,6 +143,12 @@ def main [] { $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 @@ -109,6 +157,10 @@ def main [] { # } break } + "u" => { + $state.paperclips.price += 1 + $state = update-demand $state + } "w" => { if $state.money >= $state.wire.cost { $state.wire.length += 1000 @@ -120,6 +172,7 @@ def main [] { $state.wire.cost = 12 } } + $state.money -= $state.wire.cost } } _ => { @@ -130,7 +183,7 @@ def main [] { job spawn { get-user-input $table_name } } # for 60fps framerate lock - sleep 0.01666666667sec + sleep 16.666ms let now = date now let delta = $now - $prev $state.delta_time += $delta From 2806a7cc1a3c6da29bb3c616f3e9366c6e288457 Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Thu, 1 May 2025 08:11:39 -0500 Subject: [PATCH 5/6] add paperclips v0.1 --- .gitignore | 2 + games/paperclips/game.nu | 111 ++++++++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index 0ac21c72..ebdc940f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ # ignore the git mailmap file .mailmap +# nu-specific check-files.nu +gamestate.nuon .vscode/ diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu index 5fec575b..f9b58e85 100644 --- a/games/paperclips/game.nu +++ b/games/paperclips/game.nu @@ -1,13 +1,16 @@ # nu-niversal paperclips - a (somewhat) faithful clone of Universal Paperclips # play the original at: https://www.decisionproblem.com/paperclips/index2.html -# TODO: figure out how to display this visually... maybe just a quick loop? +# NOTE: scalars are off cuz i'm counting by pennies instead of dollars and cents + +let carriage_return = "\n\r" + 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 - return $new_state + $new_state } def sell-paperclips [state] { @@ -20,45 +23,63 @@ def sell-paperclips [state] { let transaction = $amount * $state.paperclips.price $new_state.money += $transaction $new_state.paperclips.stock -= $amount - return $new_state + $new_state } def update-demand [state] { let marketing = 1.1 ** ($state.market.level - 1) mut new_state = $state - # this is off by 1000x??? figure out what you're doing wrong $new_state.market.demand = ((.8 / $state.paperclips.price) * $marketing) * 1000 - return $new_state + $new_state } -def get-user-input [queue] { +def get-user-input [] { let key = (input listen --types [key]) - # print $"pressed ($key); keycode = ($key.code)" if ($key.code == 'c') and ($key.modifiers == ['keymodifiers(control)']) { exit } - # stor insert --table-name $queue --data-record {keycode: $key.code} $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)" +} + def print-line [state] { - print -n $"Paperclips: ($state.paperclips.total | into string -g)\n\r\n\r" + print -n $"(format-text "Paperclips" $state.paperclips.total)" + print -n $carriage_return print -n "Business:\n\r" print -n "---------------\n\r" - print -n $"Avaulable Funds: $($state.money / 100.0 | into string -g)\n\r" - print -n $"Unsold Inventory: ($state.paperclips.stock | into string -g)\n\r" - print -n $"Price Per Clip: $($state.paperclips.price / 100.0 | into string -g)\n\r" - print -n $"Public Demand: ($state.market.demand | math round | into string -g)%\n\r\n\r" - print -n $"Marketing Level: ($state.market.level | into string -g)\n\r" - print -n $"Marketing cost: $($state.market.cost / 100.0 | into string -g)\n\r\n\r" + print -n $"(format-text 'Available Funds' $state.money --money)" + print -n $"(format-text 'Unsold Inventory' $state.paperclips.stock)" + print -n $"(format-text 'Price Per Clip' $state.paperclips.price --money)" + print -n $"(format-text 'Public Demand' $state.market.demand --round)" + print -n $carriage_return + print -n $"(format-text 'Marketing Level' $state.market.level)" + print -n $"(format-text 'Marketing cost' $state.market.cost --money)" + print -n $carriage_return print -n "Manufacturing:\n\r" print -n "---------------\n\r" - print -n $"Clips per Second: ($state.paperclips.rate)\n\r\n\r" - print -n $"Wire: ($state.wire.length | into string -g) inches\n\r" - print -n $"Wire cost: $($state.wire.cost / 100.0 | into string -g)\n\r\n\r" + print -n $"(format-text 'Clips per Second' $state.paperclips.rate)" + print -n $carriage_return + if $state.wire.length == 1 { "inch" } else { "inches" } + print -n $"Wire: ($state.wire.length | into string -g) ( + if $state.wire.length == 1 { "inch" } else { "inches" } + )\n\r" + print -n $"(format-text 'Wire cost' $state.wire.cost --money)" + print -n $carriage_return if $state.autoclippers.unlocked { - print -n $"autoclippers: ($state.autoclippers.count | into string -g)\n\r" - print -n $"autoclipper cost: $($state.autoclippers.cost / 100.0 | into string -g)\n\r" + print -n $"(format-text "Autoclippers" $state.autoclippers.count)" + print -n $"(format-text 'Autoclipper cost' $state.autoclippers.cost --money)" + print -n $carriage_return } print -n $"($state.control_line)\n\r" } @@ -69,17 +90,17 @@ def main [] { sleep 2sec clear let table_name = "clip_message_queue" - # stor create --table-name $table_name --columns {keycode: str} + mut state = { delta_time: 0sec paperclips: { total: 0 stock: 0 price: 25 - rate: "NOT IMPLEMENTED :(" + rate: -1 } market: { - demand: 32 + demand: 0 level: 1 cost: 10000 } @@ -100,14 +121,27 @@ def main [] { if $save_exists { $state = open './gamestate.nuon' } + # initial setup + $state = update-demand $state print-line $state - get-user-input $table_name + get-user-input loop { clear 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 let amount = (($seconds | into int | $in / 1000000000) * $state.autoclippers.count) | math round mut index = 0 while $index < $amount { @@ -122,14 +156,15 @@ def main [] { clear } let prev = date now - print-line $state + 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" } - # if (job list | length) == 0 { + + print-line $state + try { - # let key = stor open | query db $"SELECT keycode FROM ($table_name)" | get keycode.0 let key = job recv --timeout 0sec match $key { "a" => { @@ -150,11 +185,11 @@ def main [] { } } "q" => { - # if not $save_exists { - # $state | save gamestate.nuon - # } else { - # $state | save gamestate.nuon --force - # } + if not $save_exists { + $state | save gamestate.nuon + } else { + $state | save gamestate.nuon --force + } break } "u" => { @@ -164,14 +199,6 @@ def main [] { "w" => { if $state.money >= $state.wire.cost { $state.wire.length += 1000 - # TODO: tweak numbers - if (random bool --bias 0.5) { - let deviation = (0.75 + (random float 0.0..0.50)) - $state.wire.cost += $deviation | math round - if $state.wire.cost < 12 { - $state.wire.cost = 12 - } - } $state.money -= $state.wire.cost } } @@ -179,9 +206,9 @@ def main [] { "" } } - # stor delete --table-name $table_name --where-clause $"keycode == '($key)'" - job spawn { get-user-input $table_name } + job spawn { get-user-input } } + # for 60fps framerate lock sleep 16.666ms let now = date now From d26fb4cb3d1d8e5d08f88237d1b1a92334c06ff1 Mon Sep 17 00:00:00 2001 From: 0x4D5352 <67082011+0x4D5352@users.noreply.github.com> Date: Thu, 1 May 2025 13:54:14 -0500 Subject: [PATCH 6/6] update game thanks to @cablehead --- games/paperclips/game.nu | 120 +++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 36 deletions(-) diff --git a/games/paperclips/game.nu b/games/paperclips/game.nu index f9b58e85..80961941 100644 --- a/games/paperclips/game.nu +++ b/games/paperclips/game.nu @@ -3,13 +3,31 @@ # NOTE: scalars are off cuz i'm counting by pennies instead of dollars and cents -let carriage_return = "\n\r" +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 } @@ -36,6 +54,7 @@ def update-demand [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 @@ -53,42 +72,62 @@ def format-text [prefix: string, value: number, --money --round] { $"($prefix): (if $money { "$" } else { })($value | into string --group-digits)(if $round { "%" } else { })($carriage_return)" } -def print-line [state] { - print -n $"(format-text "Paperclips" $state.paperclips.total)" - print -n $carriage_return - print -n "Business:\n\r" - print -n "---------------\n\r" - print -n $"(format-text 'Available Funds' $state.money --money)" - print -n $"(format-text 'Unsold Inventory' $state.paperclips.stock)" - print -n $"(format-text 'Price Per Clip' $state.paperclips.price --money)" - print -n $"(format-text 'Public Demand' $state.market.demand --round)" - print -n $carriage_return - print -n $"(format-text 'Marketing Level' $state.market.level)" - print -n $"(format-text 'Marketing cost' $state.market.cost --money)" - print -n $carriage_return - print -n "Manufacturing:\n\r" - print -n "---------------\n\r" - print -n $"(format-text 'Clips per Second' $state.paperclips.rate)" - print -n $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" } - print -n $"Wire: ($state.wire.length | into string -g) ( + clear-line $"Wire: ($state.wire.length | into string -g) ( if $state.wire.length == 1 { "inch" } else { "inches" } )\n\r" - print -n $"(format-text 'Wire cost' $state.wire.cost --money)" - print -n $carriage_return + clear-line (format-text 'Wire cost' $state.wire.cost --money) + clear-line $carriage_return + + # Autoclippers (conditional) if $state.autoclippers.unlocked { - print -n $"(format-text "Autoclippers" $state.autoclippers.count)" - print -n $"(format-text 'Autoclipper cost' $state.autoclippers.cost --money)" - print -n $carriage_return + clear-line (format-text "Autoclippers" $state.autoclippers.count) + clear-line (format-text 'Autoclipper cost' $state.autoclippers.cost --money) + clear-line $carriage_return } - print -n $"($state.control_line)\n\r" + + # Controls + clear-line $"($state.control_line)\n\r" + + # Clean up any trailing content from previous longer displays + clear-to-end } def main [] { - clear + reset-cursor print "Welcome to nu-niversal paperclips!" + clear-to-end sleep 2sec - clear + reset-cursor let table_name = "clip_message_queue" mut state = { @@ -97,8 +136,10 @@ def main [] { total: 0 stock: 0 price: 25 - rate: -1 + 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 @@ -123,11 +164,10 @@ def main [] { } # initial setup $state = update-demand $state - print-line $state + refresh-game-view $state get-user-input loop { - clear let seconds = $state.delta_time if ($seconds) > (1sec) { $state.delta_time -= $seconds @@ -142,27 +182,34 @@ def main [] { } } $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 - clear - print-line $state - # TODO: figure out a better solution here - sleep 16.666ms } + $state = sell-paperclips $state - clear } 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" } - print-line $state + # Update display with current game state + refresh-game-view $state try { let key = job recv --timeout 0sec @@ -190,6 +237,7 @@ def main [] { } else { $state | save gamestate.nuon --force } + print -n "\e[?25h" # Show cursor before exiting break } "u" => {