Software for the classic HP 12C calculator ------------------------------------------ This page contains my own key-in programs created for the HP 12C programmable financial calculator to extend its capabilities. All programs have been tested on the classic ("gold") 12C from 2001 with a 884 KHz Agilent CPU of the HP Nut architecture. == Table of contents == This document contains the TRICKS, UTILS, SUITES and GAMES sections. TRICKS: * Min/max snippets * GTO-less conditionals * Reliable absolute value snippet * Reliable modulo * Pseudorandom number generation * Generating several random integers in a single pass * Hidden polynomial evaluator * Hidden polynomial solver * Indirect register access * Harnessing extra memory from the Nj registers * (Ab)using RCL CFj to organize small non-nested loops UTILS: * Trigonometry: - Sine or cosine (Taylor-based) - Sine and cosine (fast) - recommended - FinSin: sine and arcsine based on the financial functions - Arctangent (fixed-time) - Scaling down the arctangent arguments - Calculating arcsine and arccosine using arctangent programs - Useful constants * Coordinate unit conversions * Measurement unit conversions * Modular exponentiation * Prime number generator (fun-sized) * One-time pad encryption/decryption helper * FinPoly: generalized Minimax polynomial calculator * KHCEmu12: WDR's Der Know-How Computer emulator SUITES: * Luxferre's Trigonometry Suite * Luxferre's Complex Number Suite * Luxferre's Nautical Converter * Neo12C: a handy 2x2 matrix operations suite GAMES: * Dice roll simulator * YahBox12 (Yahtzee dice box simulator) * Nicomachus * UltimateMoo12 (Bulls and Cows HP 12C port) * Hurwump12: Hunt the Hurkle + Mugwump 2-in-1 game pack for HP 12C * Hurwurk12: Hunt the Hurkle + Mugwump + Snark 3-in-1 game pack * OptiWump12: an optimized Mugwump port for the 12C * OptiSnark12: an optimized Snark port for the 12C * Hurkle3D aka Depth Charge * Nim12: a classic variant of the Nim game * EvenWins12: a port of the "Even Wins" game to HP 12C ################################## TRICKS #################################### This section contains short (usually unnumbered) snippets of code to be used in HP 12C programs to perform common tasks not supported natively by its instruction set. == Min/max snippets == Whenever you need to detect the greatest or the lowest value among the two or even three in your program (that are already present in the stack), that's very simple: * 2-value maximum: x<=y x<>y * 2-value minimum: x<=y x<>y x<>y * 3-value maximum: x<=y x<>y x<>y ROLL x<=y x<>y * 3-value minimum: x<=y x<>y ROLL x<=y x<>y x<>y The 2-value maximum/minimum snippets do not alter the other stack values, just put one value in front and the other in the back. Bonus: here's how to check if the maximum of the three values is equal to the sum of the other two. x<=y x<>y (maxAB minAB C -) x<>y (minAB maxAB C -) ROLL (maxAB C - minAB) x<=y x<>y (maxABC min(minAB,C) - minAB) ROLL (min(minAB,C) - minAB maxABC) x<>y (- min(minAB,C) minAB maxABC) ROLL (min(minAB,C) minAB maxABC -) + (min(minAB,C)+minAB maxABC - -) - (maxABC-minAB-min(minAB,C) - - -) x=0 ... == GTO-less conditionals == Sometimes, you don't need to use jumps to perform conditional actions. Maximum/minimum is just one example. To push a value A if the condition holds or the value B if it doesn't, the usual construction looks like this: (n) x=0 (or x<=y) (n+1) GTO n+4 (n+2) [B] (n+3) GTO n+5 (n+4) [A] (n+5) ... Takes five steps but requires keeping track of instruction numbers. Here are the replacements. * Push the value A on top of the stack if the value in the X register is 0, push the value B otherwise: [A ENTER] [B] ROLL ROLL x<>y ROLL x=0 ROLL ROLL * Push 1 (or any other constant) on top of the stack if the value in the X register is 0, push 0 otherwise (shortcut): ENTER x=0 1 - CHS * Push the value A on top of the stack if the value in the X register is less than or equal to the value in the Y register, push the value B otherwise (if Y > X): [A ENTER] [B] ROLL ROLL x<=y ROLL ROLL ROLL == Reliable absolute value snippet == Unlike e.g. MK-52, HP 12C also lacks an absolute value function. A naive and short implementation within a program would be like: ENTER x SQRT However, this uses an extra stack register and a slow SQRT function, which also might lead to precision loss. A faster approach which guarantees no precision loss is only one step longer: 0 x<>y x<=y CHS Using the min snippet above, the fastest way to calculate abs(a - b) is: x<=y x<>y x<>y - This works because the minimum of the two will always get into the X register. == Reliable modulo == Since the 12C doesn't have a modulo operation but has a FRAC function, one might be tempted to use it if it's necessary to calculate a full remainder (not just check whether it's 0). For a generic a mod b operation, the naive routine would be: [a ENTER b] / LSTx x<>y FRAC x However, while this routine works fine for divisors like 2, 5 or 10, it is not recommended for the fractions that end up having infinite digits since the loss of precision can accumulate rather quickly. The RND function will do if you operate on limited precision that you are sure to not exceed anytime, but a more reliable approach would be: [a ENTER b] / LSTx x<>y FRAC x . 5 + INTG In a program, it takes 9 steps (or 8 if the constant 0.5 is already stored elsewhere). If you are ready to trade more steps for speed, the following snippet is available that's only using the INTG function once and performs only stack operations (assuming the dividend is in the reg Y and the divisor in the reg X, so the stack state for a mod b is (b a - -)): [a ENTER b] x<>y ENTER ROLL x<>y / LSTx x<>y INTG x x<>y ROLL - If you only need to check if the modulo is 0, a 3-step routine (/ FRAC x=0) is fine though. For a register Rn from R0 to R4, the operation Rn mod b would look like: b STO / [n] RCL [n] FRAC x . 5 + INTG STO [n] This routine also takes 9 steps but also stores the value into the same register. == Pseudorandom number generation == Another notable thing missing in HP 12C is any kind of random number generator. Here's my personal approach to generating pseudorandom numbers from 0 to 1 using the calculator's transcendental functions in the shortest way possible while still avoiding any statistical bias. The formula is: S[n] = frac(12 * exp(S[n-1] + 3)). The line numbering can be arbitrary as this is supposed to be a snippet of another program, but please make sure to end it with GTO 00 if you plan on using it in a standalone manner: 01 RCL n ; recall Rn 02 FRAC ; and take its fractional part 03 3 ; push 3 04 + ; add 3 05 e^x ; take its natural exponent 06 12x ; multiply by 12 and rewrite Rn 07 FRAC ; return its fractional part for further usage Set the initial seed between 0 and 1 to the financial register n before running the snippet. Alternatively, you can use the S[n] = frac(-12 / ln(S[n-1])) formula that takes the same amount of steps, may be a little slower but pushes only one extra value into the stack (preserving the contents of Y and Z registers in Z and T respectively): 01 RCL n ; recall Rn 02 FRAC ; and take its fractional part 03 LN ; get its ln value 04 CHS ; change the sign 05 1/x ; get the reciprocal 06 12x ; multiply by 12 and rewrite Rn 07 FRAC ; return its fractional part for further usage In case you need to use Rn for some other purposes (including those described in this chapter), here's an alternative PRNG using Ri and the formula S[n] = frac(exp(S[n-1] + 7) / 12): 01 RCL i ; recall Ri 02 FRAC ; and take its fractional part 03 7 ; push 7 04 + ; add 7 05 e^x ; take its natural exponent 06 12/ ; divide by 12 and rewrite Ri 07 FRAC ; return its fractional part for further usage == Generating several random integers in a single pass == As long as N^M fits into nine digits at most, you can generate M pseudorandom numbers from 0 to N-1 at once to save both the program size and execution time. Here's how it's done. Suppose we use the PRNG described in the previous section and continue from that point: 08 RCL i ; suppose we have our upper limit N in Ri 09 x ; multiply by the pseudorandom output 10 INTG ; get the pseudorandom integer Ni 11 LSTx ; restore the raw output 12 FRAC ; get the intermediate fractional part 13 x<>y ; move Ni to the front of the stack ... ; do something with Ni (not losing the fraction in the reg. Y) xx x<>y ; move the fraction to the front of the stack xx GTO 08 ; do the same again to get the next number == Hidden polynomial evaluator == The NPV (net present value) function of the HP 12C in fact evaluates polynomials with the coefficients stored in R0..Rn and the argument stored in Ri, but the argument first needs to be converted according to the formula Ri = (1/x - 1) * 100. Luckily, we have a shortcut to do this: 1/x 1 x<>y D% i where D% is the delta-% key, left to the normal % key. Then, we can store the polynomial coefficients in the Horner order (from the lowest power to the highest) using the CFo function to store the first one and CFj to store the rest of them. You can also save repeated coefficients after pressing CFj by specifying [count] Nj to populate move than one coefficient with the same value. When all coefficients are in place and the argument is in Ri (converted according to the algorithm above), running NPV will compute the polynomial value. There also exists an alternate way of storing the coefficients: store the polynomial degree d into Rn and then directly assign values to the registers R0..Rd. This only works in case you don't have multiple consecutively repeated coefficients, if you do then you will have to use the CFo/CFj/Nj approach. == Hidden polynomial solver == Once we have stored the coefficients in the registers as described in the previous section, we can use the IRR (internal rate of return) function to find the roots of this polynomial. After entering the coefficients, press 1 IRR and then % + 1/x to display the actual root. In case you're getting Error 3 or want to find another root, you can press CLx and supply a different initial guess by typing it in and then pressing RCL g R/S IRR. You'll then need to issue 1 x<>y % + 1/x to get the actual root value. In case you're getting Error 7, this means the HP-12C cannot solve the polynomial equation with these coefficients. That might be because they cannot all be positive or negative. == Indirect register access == Officially, HP 12C doesn't support indirect register addressing, but that's not entirely true. Combined with the register Rn, the CFj command allows accessing main memory registers by their index, namely: * writing: [index-1] n [value] CFj * reading: [index] n RCL CFj When writing, it does the pre-increment of the Rn contents, so you must specify 1 less into the index, e.g. -1 to write to R0 and 4 to write to R5. When reading, the CFj command automatically post-decrements the contents of the Rn register. When writing one position beyond the last available index, an error won't be thrown but the value will be stored into the FV register instead. E.g. if your program takes up all available steps and only R0 to R6 are accessible, writing a value with 6 n [value] CFj will populate the FV register instead of the inaccessible R7 register. Note: inside a program, it's better to use STO n instead of just n to prevent inadvertent triggering of TVM calculations that could alter the other financial registers. Same goes for STO i and others. == Harnessing extra memory from the Nj registers == In case you don't need the polynomial functionality or the NPV/IRR functionality per se, you can use the 21 additional registers the 12C provides to store integers from 0 to 99 inclusively (you'll get an Error 6 if you try writing a non-integer number or an integer out of these bounds). You'll also need the register n to control the interaction with Nj registers: unlike the previous section, this is the only way of interacting with them. * Write the register Nj[index]: [index] n [value] Nj * Read the register Nj[index]: [index] n RCL Nj The index must be from 0 to 20, the value must be from 0 to 99. Both must be integers. Unlike CFj and RCL CFj, the Nj and RCL Nj commands do not alter the Rn register contents. Despite the limitations on what they can store, the Nj registers survive the CL.FIN (f x<>y) command. On the CL.REG (f CLx) command, they all get reset to 1. Although it's not documented anywhere, the amount of available Nj registers is one more than the amount of available general purpose registers displayed in g MEM. That is, if all program steps are taken, you have 7 general purpose registers and 8 Nj registers available. == (Ab)using RCL CFj to organize small non-nested loops == Since the 12C doesn't have any special loop functionality, a normal loop would look like this (using R0..R4 for storage arithmetic, R0 provided as an example here): (n) 5 ; push iteration count (n+1) STO 0 ; store iteration count into R0 (n+2) ... ; loop start ... ; main loop body (k) 1 ; push 1 (k+1) STO - 0 ; decrement R0 (k+2) RCL 0 ; recall its contents (k+3) x=0 ; if it's 0 (k+4) GTO (k+6) ; then skip the next instruction (k+5) GTO (n+2) ; else go to the loop start However, if the iteration count is small enough (within the amount of accessible main registers + 1) and the body doesn't alter the contents of Rn, we can save one program step by doing this instead: (n) 5 ; push iteration count (n+1) STO n ; set Rn (n+2) ... ; loop start ... ; main loop body (k) RCL CFj ; decrement the n register (k+1) RCL n ; recall its contents (k+2) x=0 ; if it's 0 (k+3) GTO (k+5) ; then skip the next instruction (k+4) GTO (n+2) ; else go to the loop start As a bonus, you can issue RCL CFj earlier in the loop body instead and do something with the register contents read by it. This allows to dynamically iterate over register contents in a list-like fashion. ################################### UTILS #################################### These are the programs that mostly solve a single task well. == Trigonometry == Among other things, the 12C is famous for the absence of trigonometry functions. These programs aim to fill in this gap. For a full set of functions in a single program, see the SUITES section. ## Sine or cosine (Taylor-based) ## Only calculates either sine or cosine, but does it with maximum accuracy. Reuses the same Taylor series algorithm. The argument must be in radians. To calculate sine, type 1 STO 3 [arg] STO 1 STO 2 R/S. To calculate cosine, type 0 STO 3 1 STO 1 STO 2 [arg] R/S. Listing: 01 ENTER ; commit x to stack 02 x ; calculate x^2 03 CHS ; calculate -x^2 04 STO 5 ; save -x^2 to R5 05 RCL 2 ; loop start; save the current result at R2 06 STO 6 ; ...to the previous result cache at R6 07 RCL 5 ; recall -x^2 08 RCL 3 ; recall c 09 1 ; calculate c + 1 10 + 11 / ; calculate (-x^2) / (c + 1) 12 RCL 3 ; recall c 13 2 ; calculate c + 2 14 + 15 / ; calculate (-x^2) / (c + 1) / (c + 2) 16 STO x 1 ; multiply this result by t and store into t 17 2 ; add 2 18 STO + 3 ; ...to the c value 19 RCL 1 ; recall t 20 STO + 2 ; and add it to R2 21 RCL 2 ; recall the result 22 RCL 6 ; recall the previous result cache 23 - ; subtract the cache value 24 x=0 ; if they are equal... 25 GTO 27 ; then skip to the end 26 GTO 05 ; else go to the loop start 27 RCL 2 ; display the result 28 GTO 00 ; program end ## Sine and cosine (fast) - recommended ## Based on the approximation to convert a hyperbolic cosine value into the trigonometric cosine value. Calculates both sine and cosine with near-machine precision, leaving cosine in the X register and sine in the Y register. Takes about 4 seconds to run. Enter the argument (from 0 to Pi/2 radians) and press R/S. The cosine value will be on the display. Press x<>y to view the sine value or the division key to get the tangent. From the tangent view, press 1/x to get the cotangent. Listing: 01 STO 0 ; store our argument x into R0 02 4 ; push 4 03 y^x ; calculate x^4 04 12/ ; calculate x^4 / 12 as the variable K (storing it into Ri) 05 STO 1 ; store it into R1 too 06 ENTER ; push into the stack 07 x ; calculate K^2 08 1 09 4 10 0 11 / ; calculate K^2 / 140 12 STO + 1 ; append into R1 13 RCL i ; recall K 14 x ; calculate K^3 / 140 15 9 16 9 17 0 18 / ; calculate K^3 / 138600 19 STO + 1 ; append this into R1 too 20 RCL 0 ; recall x 21 e^x ; natural exponent 22 ENTER ; push into the stack 23 1/x ; reciprocal: calculate e^(-x) 24 + ; calculate e^x + e^(-x) 25 2 ; calculate (e^x + e^(-x))/2 26 / ; the result is cosh x which can be used to approx cos x 27 STO - 1 ; subtract this from R1 28 2 ; and add the final 2 29 STO + 1 ; the cosine value is now in R1 30 RCL 1 ; recall it 31 ENTER ; push into the stack 32 x ; calculate (cos x)^2 33 1 ; push 1 34 - ; calculate (cos x)^2 - 1 35 CHS ; calculate 1 - (cos x)^2 = (sin x)^2 36 SQRT ; calculate sin x 37 RCL 1 ; recall cos x 38 GTO 00 ; PROFIT! ## FinSin: sine and arcsine based on the financial functions ## Using the NPV and IRR functions of the 12C, we can evaluate polynomials to approximate trigonometric functions. Particularly, we can get a nice approximation from the setup close to what the Apollo mission had been using when landing on the Moon. The arcsine function is just solving the root of the same polynomial by replacing the free coefficient 0 with the opposite to the argument, so it takes little space too. Not counting the setup steps, the entire code is just 22 steps long. The sine part is accurate to the fourth decimal digit after rounding, the arcsine part is accurate to about 6.2 angular seconds. The proper polynomial setup is: CLx CFo 1.57065 CFj 0 CFj .64323 CHS CFj 0 CFj .0727 CFj or: 5 n CL.STAT 1.57065 STO 1 .64323 CHS STO 3 .0727 STO 5 All input/output is in degrees. Run with R/S to get sine, run with GTO 13 R/S to get arcsine. Listing: ; sine part 01 9 02 0 03 x<>y 04 / ; divide by 90, then perform 1/x 05 1 ; prepare as NPV input 06 x<>y 07 D% 08 i ; save as NPV input 09 CLx ; ensure the R0 is set to 0 10 STO 0 ; to make the calculations correct 11 NPV ; run it 12 GTO 00 ; this is your sine ; arcsine part 13 CHS ; change the argument sign 14 STO 0 ; replace the free coefficient with it 15 1 ; prepare to run IRR 16 RCL g R/S ; run it 17 % ; get the true root 18 + 19 1/x 20 9 21 0 22 x ; multiply to get the degrees 23 GTO 00 ; this is your arcsine ## Arctangent (fixed-time) ## Based on the arithmetic-geometric mean algorithm. For the default 15 iterations, the runtime is just under 17 seconds regardless of the argument. You can change the amount of iterations in the code to get faster results at the expense of accuracy. At the default iteration count, it starts losing the last (9th) digit of precision at the values of x about 2.1, but never loses accuracy up to the 8th decimal digit. The tests showed no practical sense increasing the iteration count above 15. No setup or argument conversion necessary, just enter the argument and press R/S. Listing: 01 STO 4 ; store the x argument into R4 02 ENTER ; push into the stack 03 x ; calculate x^2 04 1 ; push 1 05 STO 2 ; store 1 into b while at it 06 + ; calculate 1 + x^2 07 SQRT ; calculate sqrt(1 + x^2) 09 1/x ; calculate a0 09 STO 1 ; store a 10 STO 3 ; store a0 11 1 ; push the iteration count (15 by default) 12 5 13 STO 0 ; store iteration count into R0 14 RCL 1 ; loop start, recall a 15 RCL 2 ; recall b 16 + ; a + b 17 2 ; push 2 18 / ; get the arithmetic mean 19 STO 1 ; store the new a value 20 RCL 2 ; recall b again 21 x ; calculate a*b 22 SQRT ; calculate sqrt(a*b) 23 STO 2 ; store the new b value 24 1 ; push 1 25 STO - 0 ; decrement the iteration count 26 RCL 0 ; recall the iteration count 27 x=0 ; if out of iterations, then 28 GTO 30 ; go to the end 29 GTO 14 ; else go to the loop start 30 RCL 4 ; recall x 31 RCL 3 ; recall a0 32 x ; multiply them 33 RCL 1 ; recall a 34 / ; the result is x * a0 / a 35 GTO 00 ; program end ## Scaling down the arctangent arguments ## In order to bring any argument to the range 0<=x<=1, you can use the following algorithm: 1. Save the pi/2 constant into some register the program doesn't touch, e.g. to R7: 1.570796327 STO 7 2. Before running the arctangent program, type in your large argument and then press 1/x. 3. Press R/S to start the program. When it finishes, type RCL 7 x<>y - to get your result. ## Calculating arcsine and arccosine using arctangent programs ## Using any program to calculate arctangents, you can calculate arcsine by keying in: [arg] ENTER ENTER x 1 x<>y - SQRT / R/S and arccosine by keying in: [arg] ENTER ENTER x 1 x<>y - SQRT x<>y / R/S or [arg] ENTER ENTER x 1 x<>y - SQRT / 1/x R/S ## Useful constants ## These constants are recommended to save somewhere in the registers to aid with trigonometric operations. * 1.570796327: pi/2, can be used to derive the arctangents of large arguments and complementary angles. * 57.29577951: 180/pi, defines how many degrees are in a radian. Divide by it to convert into radians, multiply by it to convert into degrees. == Coordinate unit conversions == Another practical feature common for almost all scientific calculators but missing in the 12C is the ability to convert degree-minute-second notation used for geographical coordinates to just degrees (with a fractional part) and vice versa. Let's fix this. This program combines the two algorithms into a single conversion utility. Enter a positive value to convert ddd.mmss... to decimal degrees, and a negative value to convert decimal degrees to the ddd.mmss... format. The sign will be changed according to the format: ddd.mmss is always positive, decimal degrees is always negative. ## Listing ## 01 INTG ; get the degrees part 02 STO 0 ; store the degrees into R0 03 LSTx ; get the original value 04 FRAC ; get the fractional part 05 0 ; push 0 06 x<>y ; exchange the stack 07 x<=y ; if the value is negative 08 GTO 23 ; then go to the decimal to DMS part 09 EEX ; start of the DMS to decimal part; push 100 10 2 ; 11 x ; multiply by 100 12 ENTER ; push this into stack 13 INTG ; get the minutes part 14 6 ; push 60 15 0 16 / ; get the decimal part of minutes 17 STO + 0 ; add to the result 18 x<>y ; get the cached minutes.seconds 19 FRAC ; get the fractional part 20 3 ; push 36 21 6 22 GTO 39 ; go to the common finalizer 23 6 ; start of the decimal to DMS part; push 60 24 0 25 STO 1 ; cache 60 into R1 26 x ; convert into minutes.parts_of_minute format 27 ENTER ; stash it 28 INTG ; get the amount of minutes 29 EEX ; push 100 30 2 31 / ; divide 32 STO + 0 ; add to the result cache 33 x<>y ; retrieve the minutes.parts_of_minute value 34 FRAC ; get the fractional part 35 RCL 1 ; recall 60 36 x ; convert into the number of seconds 37 EEX ; push 10000 38 4 39 / ; common finalizer 40 STO + 0 ; add to the result 41 RCL 0 ; show the result 42 CHS ; change the result sign 43 GTO 00 ; program end == Measurement unit conversions == This section contains short snippets to convert between some US measurement units and world standard measurement units. Assumes that the argument already has been pushed to the stack (e.g. typed in and then ENTER is pressed). Temperature conversions: * Celsius to Fahrenheit: 1.8 x 32 + * Fahrenheit to Celsius: 32 - 1.8 / Some US length unit conversions can be simplified if we enter a constant 0.3048 (meters in a foot) into the n register my the means of multiplying 0.0254 meters in an inch by 12: .0254 12x With this in place, we have: * Meters to feet: RCL n / * Feet to meters: RCL n x * Meters to yards: RCL n / 3 / * Yards to meters: RCL n x 3 x The rest of the conversions is just constant-based: * Centimeters to inches: 2.54 / * Inches to centimeters: 2.54 x * Kilometers/kph to US miles/mph: 1.609344 / * US miles/mph to kilometers/kph: 1.609344 x * Kilometers/kph to international nautical miles/knots: 1.852 / * International nautical miles/knots to kilometers/kph: 1.852 x * Kilometers per hour to meters per second: 3.6 / * Meters per second to kilometers per hour: 3.6 x * Kilograms to pounds: .45359237 / * Pounds to kilograms: .45359237 x * Liters to US gallons: 3.785411784 / * US gallons to liters: 3.785411784 x * Milliliters to US fluid ounces: 29.57352956 / * US fluid ounces to milliliters: 29.57352956 x * Hectopascals (mbar) to mmHg: 1.333223874 / * mmHg to hectopascals (mbar): 1.333223874 x == Modular exponentiation == This program combines the concepts from the modulo tricks section with a fast modular exponentiation algorithm to compute large exponents modulo some other value within reasonable time on HP 12C. Enter the arguments for a ^ b (mod c) in the following order: a ENTER b ENTER c. ## Listing ## 01 1 13 x 25 FRAC 37 FRAC 49 x 02 STO 3 14 . 26 LSTx 38 x 50 RCL 5 03 ROLL 15 5 27 INTG 39 RCL 5 51 + 04 STO 0 16 STO 5 28 STO 2 40 + 52 INTG 05 ROLL 17 + 29 x<>y 41 INTG 53 STO 1 06 STO 2 18 INTG 30 x=0 42 STO 3 54 GTO 20 07 ROLL 19 STO 1 31 GTO 43 43 RCL 1 55 RCL 3 08 STO 1 20 RCL 2 32 RCL 1 44 STO x 1 56 GTO 00 09 RCL 0 21 x=0 33 STO x 3 45 RCL 0 10 STO / 1 22 GTO 55 34 RCL 0 46 STO / 1 11 RCL 1 23 2 35 STO / 3 47 RCL 1 12 FRAC 24 / 36 RCL 3 48 FRAC == Prime number generator (fun-sized) == This program successively generates first ten prime numbers (from 2 to 29). Start with GTO 00 R/S. Press any key to stop, R/S to resume. Because the program runs out of precision after the 10th iteration, this is more for amusement purposes, although the algorithm itself uses no (external) registers and can be used within some other programs to get first ten primes in linear time. ## Listing ## 01 2 11 7 02 . 12 INTG 03 9 13 PSE 04 2 14 ENTER 05 0 15 ENTER 06 0 16 LSTx 07 5 17 FRAC 08 0 18 x 09 9 19 + 10 7 20 GTO 12 == One-time pad encryption/decryption helper == This program merely _subtracts_ two 5-digit numbers from one another digit-wise, modulo 10. The usage guide will show how to use it in subtraction-only (XOR-like) encryption/decryption. Note: this program is optimized for speed rather than size. The three-register version with loops was about half as long but took over 10 seconds instead of <6.5 on the original HP 12C. ## Listing ## 01 EEX 17 INTG 33 RCL 5 49 LSTx 65 INTG 81 RCL 2 02 9 18 STO + 1 34 x 50 FRAC 66 STO - 4 82 FRAC 03 / 19 LSTx 35 INTG 51 RCL 5 67 RCL 5 83 + 04 INTG 20 FRAC 36 STO + 4 52 x 68 STO / 0 84 RCL 5 05 STO 0 21 RCL 5 37 LSTx 53 INTG 69 STO / 1 85 x 06 LSTx 22 x 38 FRAC 54 STO - 2 70 STO / 2 86 RCL 3 07 FRAC 23 INTG 39 RCL 5 55 LSTx 71 STO / 3 87 FRAC 08 1 24 STO + 2 40 x 56 FRAC 72 STO / 4 88 + 09 0 25 LSTx 41 INTG 57 RCL 5 73 RCL 0 89 RCL 5 10 STO + 0 26 FRAC 42 STO - 0 58 x 74 FRAC 90 x 11 STO 1 27 RCL 5 43 LSTx 59 INTG 75 x 91 RCL 4 12 STO 2 28 x 44 FRAC 60 STO - 3 76 RCL 1 92 FRAC 13 STO 3 29 INTG 45 RCL 5 61 LSTx 77 FRAC 93 + 14 STO 4 30 STO + 3 46 x 62 FRAC 78 + 94 RCL 5 15 STO 5 31 LSTx 47 INTG 63 RCL 5 79 RCL 5 95 x 16 x 32 FRAC 48 STO - 1 64 x 80 x 96 GTO 00 ## Usage guide ## This simple program can be used to aid with one-time pad encryption, where you have a non-repeatable keystream and a message of the same length, both converted into digital form and split into blocks of five decimal digits. You have to process the keystream and message pairs one block at a time. For more convenience, you can disable the decimals display by pressing f 0. 1. Input a 5-digit block of the keystream first, then a 5-digit block of the message/ciphertext as the second part of the same number. 2. Press R/S. The encryption/decryption result will be displayed. The operation is the same for encryption and decryption. The result of each operation must contain exactly five digits. If the result on the display contains less digits, pad them manually with zeroes on the left side, e.g. if you get 394, write down 00394 as the result. Example. Suppose we have a message block 31415 and a key block 92653. Enter the number to encrypt with the key block first and the message second: 9265331415 R/S We get the result 61248. To decrypt it with the same key block, enter: 9265361248 R/S We get the initial message block 31415. == FinPoly: generalized Minimax poynomial calculator == Using the approach introduced in FinSin, we can generalize it to calculate any functions (and their inverses) that can be represented with a Minimax polynomial approximation. In an even more general sense, this program 1) automates the steps required to use the HP 12C's hidden polynomial evaluator, 2) enables solving the equation P(x) = a, not just P(x) = 0, by supplying a as the argument to the inverse function routine. ## Listing ## ; direct function computation part 01 1/x ; prepare the NPV input 02 1 03 x<>y 04 D% 05 i ; save as NPV input 06 NPV ; run it 07 GTO 00 ; get the direct result ; inverse computation part 08 RCL 0 ; recall the free coefficient a0 09 x<>y ; get the argument to the front 10 STO - 0 ; subtract it from a0 in R0 11 x<>y ; get the original a0 to the front 12 1 ; prepare to run IRR: (1 origA0 arg -) 13 RCL g R/S ; run it 14 % ; get the true root 15 + 16 1/x 17 x<>y ; get the original a0 to the front 18 STO 0 ; store the original a0 back to R0 19 x<>y ; show the result again 20 GTO 00 ; end of the program ## Setup ## Here are some recommended polynomial setups for functions which are simple to fill in. * Sine/arcsine (input/output in radians, high precision, R0..R7): 0 CFo 1 CFj 0 CFj 6 1/x CHS CFj 0 CFj 120 1/x CFj 0 CFj 5125 1/x CHS CFj or 7 n CL.STAT STO 0 1 STO 1 6 1/X CHS STO 3 120 1/x STO 5 5125 1/x CHS STO 7 * Cosine/arccosine (input/output in radians, mid-high precision, R0..R8): 1 CFo 0 CFj .5 CHS CFj 0 CFj 24 1/x CFj 0 CFj 721 1/x CHS CFj 0 CFj 42875 1/x CFj or 8 n CL.STAT STO 7 1 STO 0 .5 CHS STO 2 24 1/x STO 4 721 1/x CHS STO 6 42875 1/x STO 8 * ...to be continued ## Usage ## * Compute the direct function: [arg] R/S * Compute the inverse function: [arg] GTO 08 R/S == KHCEmu12: WDR's Der Know-How Computer emulator == This is an experiment of creating a fully functional emulator/VM on the HP 12C. This program emulates an educational paper computer model by WDR Computer Club called "Der Know-How Computer" created in 1983 (which is interesting since the 12C itself was first introduced in 1981), whose very limited instruction set was proven to be Turing-complete. While the original KHC worksheet had 8 registers and 21 program steps, this emulator supports up to 5 registers and 25 steps. Note that it is quite slow on the original 12C and even a simple addition program can take well over a minute to execute, but this was meant to be a proof of concept rather than a usable tool. ## Listing ## 01 1 17 - 33 LSTx 49 GTO 63 65 5 02 STO i 18 EEX 34 FRAC 50 x 66 + 03 RCL i 19 2 35 2 51 3 67 STO n 04 x=0 20 x<>y 36 5 52 x<>y 68 RCL CFj 05 GTO 00 21 y^x 37 x 53 - 69 x=0 06 1 22 RCL CFj 38 x<>y 54 x<>y 70 GTO 72 07 - 23 x<>y 39 x=0 55 5 71 GTO 76 08 ENTER 24 / 40 GTO 42 56 + 72 RCL i 09 ENTER 25 INTG 41 GTO 45 57 STO n 73 1 10 5 26 EEX 42 x<>y 58 x<>y 74 + 11 / 27 2 43 STO i 59 RCL CFj 75 STO i 12 INTG 28 / 44 GTO 03 60 + 76 RCL i 13 STO n 29 FRAC 45 2 61 CFj 77 1 14 ENTER 30 4 46 x<>y 62 GTO 76 78 + 15 5 31 x 47 x<=y 63 ROLL 79 STO i 16 x 32 INTG 48 GTO 50 64 x<>y 80 GTO 03 ## Instruction set and format ## Like in the original paper computer, the KHCEmu12's instructions are numbered from 1. That allowed to merge the Stop instruction with the Jump instruction: Stop means Jump 0, just like in the 12C itself. Hence, the actual KHCEmu12 instruction set has the following opcodes: 0) JMP k: jump to the instruction number k (JMP 0 is equivalent to halt/stop); 1) INC k: increment the register k; 2) DEC k: decrement the register k; 3) ISZ k: skip the next instruction if the register k is set to zero. Before storing the program in the 12C's registers, every instruction needs to be converted into exactly two digits according to the formula: instr = 25 * opcode + k. Then, in case k is a register number (i.e. the opcode is not 0), 1 needs to be subtracted. E.g. the halt instruction will be 00 and the JMP 12 instruction will be 12, but the INC 3 will be 1 * 25 + 3 - 1 = 27, the ISZ 1 instruction will be 3 * 25 + 1 - 1 = 75 and so on. Afterwards, the program needs to be packed from the least significant digit pairs to the most into the first five registers (R0 to R4). Let's see an example. Here's a "standard" adding program for the Know-How Computer that takes two registers and leaves the sum in the first of them (the instruction numbers aren't usually written but here they are written for clarity): 01 JMP 4 02 INC 1 03 DEC 2 04 ISZ 2 05 JMP 2 06 STP When converted to numeric encoding, these instructions look like this: JMP 4 -> 04 INC 1 -> 25 DEC 2 -> 51 ISZ 2 -> 76 JMP 2 -> 02 STP = JMP 0 -> 00 Now, let's pack these instructions into the first five registers of the 12C. Starting from the first encoded instruction, group them into five and write these groups in the reversed order: 0276512504 STO 0 0 STO 1 0 STO 2 0 STO 3 0 STO 4 In this format, the program is ready to run. ## Usage ## * Enter the program in the format stated above into the registers R0 to R4. * Enter the input register state into the registers R5 to R8 and RFV. * Press R/S to execute the program. * Look at the outputs by probing the registers R5 to R8 and RFV. The KHC registers are mapped to the 12C registers as follows: * KHC register 1 is stored in R5, * KHC register 2 is stored in R6, * KHC register 3 is stored in R7, * KHC register 4 is stored in R8, * KHC register 5 is stored in RFV. ################################## SUITES #################################### These programs combine several utilities based on a common topic into one, and can be executed from different points to perform different functions. Due to their length, the listings are hereby provided in a columnar format without comments. == Luxferre's Trigonometry Suite == This HP 12C program combines the above algorithms for fast direct trigonometry and fixed-time inverse trigonometric functions with a handy storage for the radian conversion constant 57.29577951 and optional automatic conversion of the inverse trig results back to degrees. ## Listing ## 01 STO 0 21 e^x 41 x 61 RCL 1 81 / 02 4 22 ENTER 42 1 62 RCL 2 82 R/S 03 y^x 23 1/x 43 x<>y 63 + 83 5 04 12/ 24 + 44 - 64 2 84 7 05 STO 1 25 2 45 SQRT 65 / 85 . 06 ENTER 26 / 46 / 66 STO 1 86 2 07 x 27 STO - 1 47 R/S 67 RCL 2 87 9 08 1 28 2 48 STO 4 68 x 88 5 09 4 29 STO + 1 49 ENTER 69 SQRT 89 7 10 0 30 RCL 1 50 x 70 STO 2 90 7 11 / 31 ENTER 51 1 71 1 91 9 12 STO + 1 32 x 52 STO 2 72 STO - 0 92 5 13 RCL i 33 1 53 + 73 RCL 0 93 1 14 x 34 - 54 SQRT 74 x=0 94 x 15 9 35 CHS 55 1/x 75 GTO 77 95 GTO 00 16 9 36 SQRT 56 STO 1 76 GTO 61 17 0 37 RCL 1 57 STO 3 77 RCL 4 18 / 38 GTO 00 58 1 78 RCL 3 19 STO + 1 39 ENTER 59 5 79 x 20 RCL 0 40 ENTER 60 STO 0 80 RCL 1 ## Main usage ## * Sine/cosine/tangent/cotangent: just enter the argument (from 0 to Pi/2 radians) and press R/S. The cosine value will be on the display. Press x<>y to view the sine value or the division key to get the tangent. From the tangent view, press 1/x to get the cotangent. * Arcsine: enter the argument and press GTO 39 R/S. Press R/S again in a second. * Arccosine: enter the argument and press GTO 39 R/S. Press 1/x R/S in a second. * Arctangent: enter the argument and press GTO 48 R/S. * Arccotangent: enter the argument and press 1/x GTO 48 R/S. * After running any inverse trigonometric function, you should either press GTO 00 to finish the operation or press R/S once again to convert the result from radians into degrees. * To convert any radian value in the X register into degrees, press GTO 83 R/S. * To convert any degree value in the X register into radians, press GTO 83 1/x R/S 1/x. ## Special cases ## * For obvious reasons, arcsin 1 and arccos 0 cannot be directly calculated by this program (a divide-by-zero condition occurs). Since arcsin 1 = arccos 0 = Pi/2 radians or 90 degrees, see below how to get the Pi/2 value. * To get the Pi/2 constant value, press 90 1/x GTO 83 R/S 1/x. * To get the Pi constant value, press 90 1/x GTO 83 R/S 1/x 2 x. This method is better than just entering 180 in the above sequence as it retains one more digit of precision. * To just get the radian conversion constant, press 1 GTO 83 R/S. ## Advanced usage ## * Convert polar coordinates r and phi to Cartesian coordinates x and y: [input phi] (GTO 83 1/x R/S 1/x) R/S [input r] x x<>y LSTx x (enter the part in (parentheses) if phi is in degrees) You'll get the y coordinate in the register X. Press x<>y to see the x coordinate. * Convert Cartesian coordinates x and y to polar coordinates r and phi: To get r: [input x] ENTER ENTER x [input y] ENTER x + SQRT To get phi AFTER you get r: / GTO 39 R/S 1/x R/S (press R/S again to convert phi into degrees) To get phi independently: [input y] ENTER [input x] / GTO 48 R/S Note that you may need to adjust the angle manually according to the quadrant. * Complex number multiplication (using polar coordinate conversions) Multiple complex numbers xn + i * yn can be processed at once. 1. For every complex number xn + i * yn, convert the (xn, yn) pair to (rn, tn) polar coordinates. 2. Multiply all rn values together into the value Pr. 3. Sum all tn values together into the value St. 4. Convert the (Pr, St) pair from the polar coordinates back to the Cartesian coordinates (Xr, Yr). 5. The resulting complex number is Xr + i * Yr. * Complex number division (using polar coordinate conversions) For two complex numbers x1 + i * y1 and x2 + i * y2: 1. For both complex numbers, convert the (xn, yn) pair to (rn, tn) polar coordinates. 2. Convert the (r1/r2, t1-t2) pair back to the Cartesian coordinates (Xr, Yr). 3. The resulting complex number is Xr + i * Yr. * Raising complex numbers to real powers (using polar coordinate conversions) For the complex number x + i * y and the real exponent n, perform these steps: 1. Convert the (x, y) pair to (r, t) polar coordinates. 2. Convert the (r^n, t * n) pair back to the Cartesian coordinates (Xr, Yr). 3. The resulting complex number is Xr + i * Yr. ## Inverse trigonometry precision adjustment ## The program steps 58 and 59 contain the constant 15, specifying the number of iterations for the AGM-based arctangent algorithm. Feel free to reduce this constant to calculate the inverse trig functions faster at the expense of the result accuracy. The number of iterations is mapped to the guaranteed accuracy and run time (on the original 12C) as follows: * 15: 9-10 digits after the decimal point (maximum accuracy), < 17 seconds * 14: 8-9 digits, < 16 seconds * 13: 8-9 digits, < 15 seconds * 12: 7-8 digits, < 14 seconds * 11: 6-7 digits, < 13 seconds * 10: 5-6 digits, < 12 seconds * 09: 5-6 digits, < 11 seconds * 08: 4-5 digits, < 10 seconds * 07: 3-5 digits, < 9 seconds * 06: 3-4 digits, < 8 seconds * 05: 2-3 digits, ~ 7 seconds To adjust the constant, enter P/R GTO . 57 and then the two digits from the mapping above. Press P/R to return to the run mode. == Luxferre's Complex Number Suite == Most scientific calculators have basic arithmetic operations on complex numbers. Let's equip the 12C with them. ## Listing ## 01 x<>y 14 STO 0 27 ROLL 40 x 53 x<>y 66 ENTER 02 ROLL 15 ROLL 28 ROLL 41 LSTx 54 STO 0 67 x 03 + 16 ENTER 29 ROLL 42 ROLL 55 ROLL 68 x<>y 04 ROLL 17 ENTER 30 x<>y 43 ROLL 56 RCL 1 69 ENTER 05 + 18 x 31 / 44 STO 0 57 x 70 x 06 x<>y 19 ROLL 32 CHS 45 x<>y 58 ROLL 71 + 07 ROLL 20 ROLL 33 RCL 0 46 x 59 x 72 SQRT 08 GTO 00 21 x 34 RCL 1 47 LSTx 60 x<>y 73 GTO 00 09 x<>y 22 LSTx 35 ROLL 48 ROLL 61 ROLL 10 ROLL 23 ROLL 36 ROLL 49 x<>y 62 - 11 ROLL 24 + 37 ROLL 50 ROLL 63 RCL 0 12 STO 1 25 / 38 STO 1 51 + 64 x<>y 13 ROLL 26 LSTx 39 x<>y 52 RCL 0 65 GTO 00 ## Usage guide ## This guide assumes the numbers a + b * i and c + d * i. The real part of the result will be in the X register, the imaginary part will be in the Y register (press x<>y to see it). * Addition: [a] ENTER [b] ENTER [c] ENTER [d] R/S * Subtraction: [a] ENTER [b] ENTER [c] CHS ENTER [d] CHS R/S * Multiplication: [a] ENTER [b] ENTER [c] ENTER [d] GTO 37 R/S * Division: [a] ENTER [b] ENTER [c] ENTER [d] GTO 09 R/S * Absolute value (single argument): [a] ENTER [b] GTO 66 R/S Addition/subtraction and absolute value use no memory registers. Multiplication and division use R0 and R1 registers. == Luxferre's Nautical Converter == This program combines the coordinate conversion routines with some measurement unit conversions related to nautical navigation. Usage guide follows. The program can run in two modes, not interfering with each other. ## Listing ## 01 INTG 21 6 41 RCL 0 61 2 81 3 02 STO 0 22 GTO 39 42 CHS 62 / 82 2 03 LSTx 23 6 43 GTO 00 63 12x 83 2 04 FRAC 24 0 44 1 64 ENTER 84 4 05 0 25 STO 1 45 . 65 5 85 STO PV 06 x<>y 26 x 46 8 66 . 86 R/S 07 x<=y 27 ENTER 47 STO 4 67 2 87 RCL 5 08 GTO 23 28 INTG 48 2 68 8 88 - 09 EEX 29 EEX 49 x 69 x 89 RCL 4 10 2 30 2 50 STO 2 70 STO 6 90 / 11 x 31 / 51 3 71 1 91 GTO 00 12 ENTER 32 STO + 0 52 2 72 . 92 RCL 4 13 INTG 33 x<>y 53 STO 5 73 8 93 x 14 6 34 FRAC 54 2 74 5 94 RCL 5 15 0 35 RCL 1 55 . 75 2 95 + 16 / 36 x 56 5 76 STO 3 96 GTO 00 17 STO + 0 37 EEX 57 4 77 1 18 x<>y 38 4 58 STO i 78 . 19 FRAC 39 / 59 ENTER 79 3 20 3 40 STO + 0 60 EEX 80 3 ## Coordinate conversion mode ## The first mode is the coordinate conversion mode. Enter a positive value to convert ddd.mmss... to decimal degrees, and a negative value to convert decimal degrees to the ddd.mmss... format. Press R/S and get the converted result. The sign will be changed according to the format: ddd.mmss is always positive, decimal degrees is always negative. You can just enter the program up to the step 43 if you only need this mode. ## Unit conversion mode ## The second mode is the measurement unit conversion mode. Set it up with GTO 44 R/S. After you press this sequence at least once, the following conversions become available: * Fahrenheit to Celsius: GTO 87 R/S * Celsius to Fahrenheit: GTO 92 R/S * m/s to km/h: RCL 2 x * km/h to m/s: RCL 2 / * Nautical miles to kilometers: RCL 3 x * Kilometers to nautical miles: RCL 3 / * Statute miles to kilometers: RCL 6 x * Kilometers to statute miles: RCL 6 / * Inches to centimeters: RCL i x * Centimeters to inches: RCL i / * Feet to meters: RCL n x * Meters to feet: RCL n / * Yards to meters: RCL n x 3 x * Meters to yards: RCL n / 3 / * mmHg to hectopascals (mbar): RCL PV x * Hectopascals (mbar) to mmHg: RCL PV / These conversions are available at any time, using coordinate conversion doesn't affect them. However, if you have changed any of the registers R2-R6, Rn, Ri or RPV, you need to enter the GTO 44 R/S sequence again in order to be able to use the unit conversion routines correctly. == Neo12C: a handy 2x2 matrix operations suite == While HP 15C contains full-featured matrix support and some other advanced scientific calculators have 2x2 matrix operation capabilities, the 12C has been missing all that. Not anymore. The 12C's register memory is enough for full 2x2 matrix operation support. The program leaves exactly 8 free main registers to enter the element data for the two 2x2 matrices. ## Listing ## 01 STO x 0 19 RCL 6 37 RCL 1 55 RCL 3 73 RCL 0 02 STO x 1 20 STO x 2 38 RCL 7 56 RCL 7 74 STO 3 03 STO x 2 21 RCL 7 39 x 57 x 75 x<>y 04 STO x 3 22 STO x 3 40 + 58 + 76 STO 0 05 GTO 60 23 GTO 60 41 STO 1 59 STO 3 77 1 06 RCL 4 24 RCL 0 42 RCL 2 60 RCL 0 78 CHS 07 STO + 0 25 ENTER 43 ENTER 61 RCL 3 79 STO x 1 08 RCL 5 26 ENTER 44 ENTER 62 x 80 STO x 2 09 STO + 1 27 RCL 4 45 RCL 4 63 RCL 1 81 GTO 60 10 RCL 6 28 x 46 x 64 RCL 2 82 RCL 1 11 STO + 2 29 RCL 1 47 RCL 3 65 x 83 RCL 2 12 RCL 7 30 RCL 6 48 RCL 6 66 - 84 STO 1 13 STO + 3 31 x 49 x 67 R/S 85 x<>y 14 GTO 60 32 + 50 + 68 STO / 0 86 STO 2 15 RCL 4 33 STO 0 51 STO 2 69 STO / 1 87 GTO 60 16 STO x 0 34 x<>y 52 x<>y 70 STO / 2 17 RCL 5 35 RCL 5 53 RCL 5 71 STO / 3 18 STO x 1 36 x 54 x 72 RCL 3 ## Usage guide ## Suppose we have two matrices A and B with their elements entered into corresponding registers: A: B: R0 R1 R4 R5 R2 R3 R6 R7 Then, the following operations are available for the matrix A and modify it in place: * Scalar multiplication by N: [input N] GTO 00 R/S * Inverse matrix: GTO 60 R/S R/S * Transposition: GTO 82 R/S And the following operations are available for the two matrices A and B: * Addition (A + B): GTO 06 R/S * Subtraction (B - A aka -A + B): 1 CHS GTO 00 R/S GTO 06 R/S * Full matrix multiplication (A x B): GTO 24 R/S * Hadamard product (element-wise multiplication, A (o) B): GTO 15 R/S The result is always put into R0..R3 (modifying the matrix A in place). Notice that in case of subtraction, the matrix order is reversed. At the end of these operations, the determinant of the resulting matrix is displayed. (Required!) Press GTO 00 if you don't need to compute the inverse matrix. At the end of these operations, the determinant of the resulting matrix is displayed. To directly calculate the determinant of matrix A without modifying it, press GTO 60 R/S. Press GTO 00 if you don't need to compute the inverse matrix after the determinant is displayed. ## Tips ## * Trace value of the matrix A: RCL 0 RCL 3 + * Trace value of the matrix B: RCL 4 RCL 7 + * Quickly enter the identity matrix into A: 1 STO 0 STO 3 CLx STO 1 STO 2 * Quickly enter the identity matrix into B: 1 STO 4 STO 7 CLx STO 5 STO 6 ################################### GAMES #################################### This section contains some simple calculator games that can fit into the 12C's limited 99-step program memory. Most game programs in this section require a PRNG seed value from 0 to 1 to be entered into the financial register n. E.g. to enter 0.384 as a seed, type .384 n. == Dice roll simulator == The simplest game in the list (or rather a helper program for tabletop games). Enter the number of sides into Ri, e.g. by pressing 6 i for a 6-sided die. Then, just press R/S every time you want to get a new random value from 1 to N. ## Listing ## 01 RCL n ; recall Rn 02 FRAC ; and take its fractional part 03 3 ; push 3 04 + ; add 3 05 e^x ; take its natural exponent 06 12x ; multiply by 12 and rewrite Rn 07 FRAC ; return its fractional part for further usage 08 RCL i ; recall the number of sides 09 x ; multiply by the number of sides 10 1 ; push 1 11 + ; add 1 12 INTG ; get the integer part 13 GTO 00 ; program end == YahBox12 (Yahtzee dice box simulator) == A Yahtzee tabletop game helper program to shuffle five 6-sided dice, reroll them by selection and display their sum. ## Listing ## 01 STO 2 12 0 23 GTO 37 34 + 45 STO + 4 02 EEX 13 STO 5 24 RCL n 35 INTG 46 1 03 5 14 STO x 1 25 FRAC 36 GTO 44 47 STO - 0 04 STO / 1 15 STO x 2 26 3 37 RCL 1 48 RCL 0 05 STO / 2 16 STO x 3 27 + 38 INTG 49 x=0 06 5 17 RCL 2 28 e^x 39 RCL 5 50 GTO 52 07 STO 0 18 INTG 29 12x 40 / 51 GTO 11 08 CLx 19 RCL 5 30 FRAC 41 FRAC 52 RCL 4 09 STO 3 20 / 31 6 42 RCL 5 53 RCL 3 10 STO 4 21 FRAC 32 x 43 x 54 STO 1 11 1 22 x=0 33 1 44 STO + 3 55 GTO 00 ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Gameplay ## * Type in 11111 R/S to get the initial/full roll. * To reroll certain positions, type in ones in the positions you want to reroll and zeroes in the positions you want to keep, then press R/S. E.g. you have rolled 35253 and only want to keep the fives, so you enter 10101 R/S next. Suppose you have rolled 25555 afterwards and aim for a yahtzee, so you enter 10000 R/S as you only want to reroll the first position. * After getting the roll, you can press x<>y to view the dice sum. == Nicomachus == This is more of a simple arithmetic trick rather than a full game, but it was featured in a famous BASIC games collection book. You think of a number between 1 and 100 and enter its remainders when divided by 3, 5 and 7, and the machine guesses the initial number. No setup necessary. ## Listing ## 01 1 06 1 11 0 16 5 21 GTO 23 02 5 07 x 12 x 17 - 22 GTO 14 03 x 08 + 13 + 18 0 23 LSTx 04 x<>y 09 x<>y 14 1 19 x<>y 24 + 05 2 10 7 15 0 20 x<=y 25 GTO 00 ## Gameplay ## Think of a number N between 1 and 100. Find its remainders from division by 3, 5 and 7. Then input: [N mod 3] ENTER [N mod 5] ENTER [N mod 7] R/S The calculator will show your initial number. == UltimateMoo12 (Bulls and Cows HP 12C port) == Probably the most complicated game in the list. Requires proper setup. The goal of the game is to guess a four-digit number (where all digits are different) in the fewest tries possible. ## Listing ## 01 CL.STAT 18 CLx 35 STO / 2 52 RCL n 69 1 02 RCL i 19 Nj 36 RCL 7 53 - 70 STO - 1 03 FRAC 20 RCL 7 37 STO x 4 54 RCL 7 71 RCL 1 04 7 21 STO / 4 38 RCL 4 55 / 72 x=0 05 + 22 1 39 INTG 56 FRAC 73 GTO 75 06 e^x 23 STO + 1 40 RCL 7 57 x=0 74 GTO 48 07 12/ 24 3 41 / 58 GTO 60 75 1 08 FRAC 25 RCL 1 42 FRAC 59 GTO 69 76 STO - 0 09 RCL 7 26 x<=y 43 RCL 7 60 RCL 7 77 RCL 0 10 x 27 GTO 02 44 x 61 1 78 x=0 11 INTG 28 R/S 45 STO n 62 RCL 0 79 GTO 81 12 STO n 29 STO 2 46 1 63 RCL 1 80 GTO 32 13 RCL Nj 30 4 47 Nj 64 - 81 RCL 8 14 x=0 31 STO 0 48 RCL 7 65 x=0 82 STO / 4 15 GTO 02 32 4 49 STO x 2 66 ROLL 83 RCL 3 16 RCL n 33 STO 1 50 RCL 2 67 ROLL 84 STO - 3 17 STO + 4 34 RCL 8 51 INTG 68 STO + 3 85 GTO 28 ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press this sequence: (f 0) f REG 10 STO 7 EEX 4 STO 8 [seed] i (the f 0 is optional just to get rid of the decimal zeroes, not affecting the gameplay) ## Gameplay ## 1. Press f PRGM R/S to start the game for the first time. 2. When 4 appears, enter your four-digit guess and press R/S. The number you enter must contain exactly four different digits (leading zero allowed). 3. The game will display your guess score: tens are bulls, ones are cows. Bulls are the number of digits guessed in the correct places. Cows are the number of digits present in the number but guessed in the wrong positions. E.g.: - 40 means the number has been fully guessed, - 12 means one digit has been guessed in the correct place and two in the wrong places, - 4 means all digits have been guessed but in the wrong positions, - 0 means none of the entered digits are present in the target number. 4. Enter your new guess and press R/S. You can view your previous guess by pressing RCL 2. 5. The game doesn't keep track of attempt count but the goal is to get the score 40 within seven attempts. 6. If you fully give up, you can view the target number by pressing f 4 RCL 4. 7. To start over with a new number to guess, press f PRGM R/S. == Hurwump12: Hunt the Hurkle + Mugwump 2-in-1 game pack for HP 12C == This is a program that contains two games with a lot of common logic, Hunt the Hurkle and Mugwump. You wander around a grid of caves and scan for a monster you need to hunt down (Hurkle/Mugwump respectively), and you need to find it as quickly as possible for the village safety. These two games became the precursors to more advanced adventure games like Hunt the Wumpus. ## Listing ## 01 STO 0 15 / 29 RCL 1 43 RCL 0 57 RCL 4 02 RCL n 16 ENTER 30 - 44 x=0 58 / 03 FRAC 17 INTG 31 STO 3 45 GTO 50 59 STO - 3 04 3 18 STO 2 32 ENTER 46 ROLL 60 ROLL 05 + 19 - 33 x 47 ROLL 61 x=0 06 e^x 20 1 34 SQRT 48 + 62 GTO 67 07 12x 21 0 35 STO 4 49 GTO 25 63 / 08 FRAC 22 x 36 x<>y 50 ROLL 64 3 09 EEX 23 STO 1 37 ENTER 51 RCL 3 65 x 10 2 24 CLx 38 x 52 5 66 STO + 3 11 x 25 R/S 39 LSTx 53 STO 3 67 RCL 3 12 INTG 26 RCL 2 40 x<>y 54 ROLL 68 GTO 25 13 1 27 - 41 SQRT 55 x=0 14 0 28 x<>y 42 x<>y 56 GTO 60 ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Gameplay ## * Press 0 R/S to start the Hunt the Hurkle game, 1 R/S to start the Mugwump game (in fact, any non-zero value in the register X will start the Mugwump game). * Enter the (x,y) coordinates (from (0,0) to (9,9)) to guess the Hurkle/Mugwump location: x ENTER y R/S * Hurkle mode: you get a direction 1 to 9 (according to the keyboard) to go further, 5 is a victory. * Mugwump mode: you get the grid distance (in the amount of squares to travel) to the Mugwump, 0 is a victory. * Press GTO 00 [0|1] R/S to start over the game. The (0,0) point is the northwestern corner of the grid. In the Hurkle mode, the directions can easily be visualized if you look at the calculator keyboard: * 1 is go southwest, * 2 is go south, * 3 is go southeast, * 4 is go west, * 5 is no movement (you've found the target), * 6 is go east, * 7 is go northwest, * 8 is go north, * 9 is go northeast. == Hurwurk12: Hunt the Hurkle + Mugwump + Snark 3-in-1 game pack == In case you also need a Snark game for more grid hide-and-seek adventure variety, this is a larger version of the previous pack that also includes it. ## Listing ## 01 STO 0 21 0 41 STO i 61 GTO 25 81 ROLL 02 RCL n 22 x 42 ROLL 62 ROLL 82 RCL 5 03 FRAC 23 STO 1 43 ENTER 63 RCL 3 83 RCL 6 04 3 24 CLx 44 x 64 5 84 + 05 + 25 R/S 45 STO 6 65 STO 3 85 RCL i 06 e^x 26 RCL 2 46 LSTx 66 ROLL 86 x<=y 07 12x 27 - 47 x<>y 67 x=0 87 GTO 90 08 FRAC 28 x<>y 48 SQRT 68 GTO 72 88 2 09 EEX 29 RCL 1 49 x<>y 69 RCL 4 89 GTO 25 10 2 30 - 50 RCL 0 70 / 90 - 11 x 31 STO 3 51 x=0 71 STO - 3 91 x=0 12 INTG 32 ENTER 52 GTO 62 72 ROLL 92 GTO 95 13 1 33 x 53 x<>y 73 x=0 93 CLx 14 0 34 STO 5 54 ROLL 74 GTO 79 94 GTO 25 15 / 35 SQRT 55 2 75 / 95 1 16 ENTER 36 STO 4 56 x<=y 76 3 96 GTO 25 17 INTG 37 x<>y 57 GTO 81 77 x 18 STO 2 38 ROLL 58 ROLL 78 STO + 3 19 - 39 ROLL 59 ROLL 79 RCL 3 20 1 40 x 60 + 80 GTO 25 ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Gameplay ## * Press 0 R/S to start the Hunt the Hurkle game, 1 R/S to start the Mugwump game, 2 R/S to start the Snark game (in fact, any value > 1 in the register X will start the Snark game). * In the Hurkle/Mugwump mode, enter the (x,y) coordinates (from (0,0) to (9,9)) to guess the Hurkle/Mugwump location: x ENTER y R/S * In the Snark mode, first enter the circle radius r and then the coordinates: r ENTER x ENTER y R/S * Hurkle mode: you get a direction 1 to 9 (according to the keyboard) to go further, 5 is a victory. * Mugwump mode: you get the grid distance (in the amount of squares to travel) to Mugwump, 0 is a victory. * Snark mode: you get 0 if Snark is outside the circle, 1 if Snark is on the circle, 2 if inside the circle. 1 with the circle of radius 0 is a victory. * Press GTO 00 [0|1|2] R/S to start over the game. The (0,0) point is the northwestern corner of the grid. In the Hurkle mode, the directions can easily be visualized if you look at the calculator keyboard: * 1 is go southwest, * 2 is go south, * 3 is go southeast, * 4 is go west, * 5 is no movement (you've found the target), * 6 is go east, * 7 is go northwest, * 8 is go north, * 9 is go northeast. ## OptiWump12: an optimized Mugwump port for the 12C ## In case you're only interested in the Mugwump game among the trilogy, here's a highly optimized version. ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Listing ## 01 RCL n 08 1 15 1 22 RCL 8 29 x<=y 02 FRAC 09 0 16 0 23 x<=y 30 x<>y 03 3 10 x 17 x 24 x<>y 31 x<>y 04 + 11 INTG 18 INTG 25 x<>y 32 - 05 e^x 12 STO 7 19 STO 8 26 - 33 + 06 12x 13 LSTx 20 CLx 27 x<>y 34 GTO 21 07 FRAC 14 FRAC 21 R/S 28 RCL 7 ## Gameplay ## * Press R/S to start the game. * When prompted, enter the (x,y) coordinates (from (0,0) to (9,9)) to guess the Mugwump location in the form: x ENTER y * The grid distance (in the amount of squares to travel) to Mugwump is displayed, 0 is a victory. * Press GTO 00 R/S to start over. The (0,0) point is the northwestern corner of the grid. ## OptiSnark12: an optimized Snark port for the 12C ## In case you're only interested in the Snark game among the trilogy, here's a highly optimized version. ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Listing ## 01 RCL n 11 INTG 21 STO 0 31 SUM+ 41 - 02 FRAC 12 STO 7 22 f SUM 32 x<>y 42 ENTER 03 3 13 LSTx 23 RCL 0 33 ENTER 43 x=0 04 + 14 FRAC 24 R/S 34 x 44 1 05 e^x 15 1 25 RCL 8 35 RCL 3 45 - 06 12x 16 0 26 - 36 x<>y 46 CHS 07 FRAC 17 x 27 SUM+ 37 x<=y 47 GTO 21 08 1 18 INTG 28 ROLL 38 GTO 41 09 0 19 STO 8 29 RCL 7 39 2 10 x 20 CLx 30 - 40 GTO 21 ## Gameplay ## * Press R/S to start the game. * When prompted, enter the circle radius r and then the (x,y) coordinates (from (0,0) to (9,9)) to guess the Mugwump location in the form: r ENTER x ENTER y * The game displays 0 if Snark is outside the circle, 1 if Snark is on the circle, 2 if inside the circle. 1 with the circle of radius 0 is a victory. * Press GTO 00 R/S to start over. The (0,0) point is the northwestern corner of the grid. ## Hurkle3D aka Depth Charge ## This is an adaptation of Hunt the Hurkle for a 3D space 10x10x10 units each, also known as the (submarine-themed) Depth Charge game from the old BASIC books. You enter the three coordinates (surface coordinates and then the depth) and get the directions where to move next. ## Listing ## 01 RCL n 16 RCL 5 31 STO 4 46 x 61 RCL 0 02 FRAC 17 x 32 ROLL 47 SQRT 62 x=0 03 3 18 INTG 33 RCL 3 48 / 63 GTO 73 04 + 19 STO 2 34 - 49 STO - 4 64 ENTER 05 e^x 20 LSTx 35 STO 0 50 x<>y 65 ENTER 06 12x 21 FRAC 36 ROLL 51 x=0 66 x 07 FRAC 22 RCL 5 37 RCL 2 52 GTO 61 67 SQRT 08 1 23 x 38 - 53 ENTER 68 / 09 0 24 INTG 39 x<>y 54 ENTER 69 . 10 STO 5 25 STO 1 40 RCL 1 55 x 70 3 11 x 26 CLx 41 - 56 SQRT 71 x 12 INTG 27 R/S 42 x=0 57 / 72 STO - 4 13 STO 3 28 5 43 GTO 50 58 3 73 RCL 4 14 LSTx 29 . 44 ENTER 59 x 74 GTO 27 15 FRAC 30 5 45 ENTER 60 STO + 4 ## Setup ## Before the first-time launch, select a random seed from 0 to 1, then press [seed] n. No other setup is necessary. ## Gameplay ## Press R/S to start the game. When prompted with 0, enter the (x,y,z) coordinates (from (0,0,0) to (9,9,9)) to guess the Hurkle/submarine location: x ENTER y ENTER z R/S The (0,0,0) point is northwestern point on the grid, with depth 0 (surface). The game will respond with the directions in the following format: [surf].[depth], where the [surf] value is the same as for the regular Hurkle, according to the calculator keypad layout: * 1 is go southwest, * 2 is go south, * 3 is go southeast, * 4 is go west, * 5 is no movement (you're on the same surface coordinates as the target), * 6 is go east, * 7 is go northwest, * 8 is go north, * 9 is go northeast, and the [depth] value is the direction for the third coordinate, according to the calculator keypad layout: * 2 is go up, * 5 is no movement (you're on the required depth), * 8 is go down. So, you have won whenever the game responds with 5.5 (no movement required in either direction). To restart the game from the beginning, press GTO 00 R/S. ## Nim12: a classic variant of the Nim game ## This is a 12-coin version of Nim on the 12C. Ironic, huh? Modeled after the oldschool Dr. Nim toy and a lot of homebrew implementations, it only offers an option for the player to go first, a single pile of coins and 3 coins maximum to be taken in a single turn. However, you can actually customize the number of coins, the allowed maximum number to take and the victory condition at the beginning of the source code, for instance, turning it into the "23 matches" game or even a "100 game". The machine is always aiming for the optimal strategy and also asks you to repeat your move if you try taking away an invalid number of coins. ## Listing ## 01 1 10 x<=y 19 ROLL 28 - 37 - 02 2 11 GTO 06 20 x<>y 29 GTO 33 38 x=0 03 STO 0 12 x<>y 21 RCL 0 30 RCL 0 39 GTO 41 04 0 13 0 22 1 31 RCL 1 40 GTO 06 05 STO 1 14 x<>y 23 - 32 - 41 RCL 0 06 RCL 0 15 x<=y 24 x<=y 33 STO - 0 42 GTO 00 07 R/S 16 GTO 06 25 GTO 30 34 PSE 08 0 17 STO - 0 26 ROLL 35 RCL 1 09 4 18 x<>y 27 x<>y 36 RCL 0 ## Gameplay ## 1. Press (GTO 00) R/S to start the game from the beginning. 2. The remaining number of coins is displayed. Enter the number of coins to take from the pile. The game will prompt you again if you enter an invalid amount. 3. The game will briefly show you how many coins the computer opponent has taken, and then goes back to step 2. 4. When the coins cannot be taken anymore, the game shows 0 or 1 and ends. Press R/S to restart. Victory condition: depending on the game mode, 0 is the victory condition if the winner is supposed to take the last coin, 1 if the loser is supposed to take the last coin. ## Customization for various game modes ## * Classic Nim/Dr.Nim (default) | P/R 1 2 SST 0 SST SST SST 0 4 P/R * 23 matches game | P/R 2 3 SST 1 SST SST SST 0 4 P/R * 100 game | P/R EEX 2 SST 0 SST SST SST 1 1 P/R * Don't Say 13 | P/R 1 3 SST 1 SST SST SST 0 3 P/R == EvenWins12: a port of the "Even Wins" game to HP 12C == "Even Wins" is a Nim-like game where the goal is to get an even number of coins/matches/other tokens at the end of the game. Two players can take from 1 to 4 tokens at a time. The starting token amount is 27 by default but is customizable (must be odd). You always go first and the machine is following the optimal strategy. No setup is necessary. Removing the decimals with f 0 is recommended though. ## Listing ## 01 2 16 x<=y 31 INTG 46 x<=y 61 - 02 7 17 GTO 07 32 6 47 GTO 50 62 1 03 STO 0 18 RCL 0 33 x 48 RCL 0 63 x<=y 04 CLx 19 1 34 RCL 0 49 GTO 65 64 x<>y 05 STO 1 20 + 35 x<>y 50 ROLL 65 STO + 2 06 STO 2 21 x<=y 36 - 51 x<>y 66 STO - 0 07 RCL 0 22 GTO 07 37 RCL 1 52 1 67 PSE 08 x=0 23 x<>y 38 2 53 + 68 GTO 07 09 GTO 69 24 STO + 1 39 / 54 4 69 RCL 1 10 R/S 25 STO - 0 40 FRAC 55 x<=y 70 EEX 11 5 26 RCL 0 41 x=0 56 x<>y 71 2 12 x<=y 27 x=0 42 GTO 59 57 x<>y 72 x 13 GTO 07 28 GTO 69 43 ROLL 58 GTO 65 73 RCL 2 14 CLx 29 6 44 RCL 0 59 x<>y 74 + 15 x<>y 30 / 45 5 60 1 75 GTO 00 ## Gameplay ## * Press R/S to start the game. * When prompted with the current token count in the pile, enter the amount of tokens to remove (from 1 to 4) and press R/S. You'll be re-prompted if an invalid amount is entered. * The game will briefly display how many tokens the machine has taken and then prompt you again. * In case the pile becomes empty after your or the machine's move, the game ends, displaying both your and machine's piles of tokens in the format PPMM where PP is the two digits of how many tokens the player has taken and MM is the two digits of how many tokens the machine has taken, e.g. 1116 means you have taken 11 tokens and the machine has taken 16 tokens. * Whoever has an even amount of tokens at the end is the winner. ## Customization ## The first two steps of the program contain the total number of tokens. 27 is the classic default value. You can replace it with any two-digit odd number. --- Luxferre ---