# Silly Stock Market

Given a string with a multiple people's investment data, find out how much profit/loss they recorded.

The string only contains capital and lowercase letters, like this:

AABaBbba


Each letter represents a person - a capital letter means buy, a lowercase letter means sell. The price of the stock they are investing in (CGLF) starts at $50. After someone buys, the price goes up 5%. After someone sells the price goes down 5%. You need to figure out how much money each person who participated made/lost. ## Notes: • The string will always be valid, no selling without first buying. Also, everyone who buys a stock will sell it eventually. • Your calculations should be accurate to at least 6 decimal places. However, final answers should be rounded to two decimals. ## Test Cases: Input: AABaBbba • A: Buy -$50
• A: Buy - $52.50 • B: Buy -$55.125
• a: Sell - $57.88125 • B: Buy -$54.9871875
• b: Sell - $57.736546875 • b: Sell -$54.8497195313
• a: Sell - $52.1072335547 • Person A profit: 57.88125+52.1072335547-50-52.50=7.4884835547 • Person B profit: 57.736546875+54.8497195313-55.125-54.9871875=2.4740789063 Output: A:7.49,B:2.47 (order doesn't matter, separators not required) Input: DGdg • D: Buy -$50
• G: Buy - $52.50 • d: Sell -$55.125
• g: Sell - $52.36875 • Person D profit: 55.125-50=5.125 • Person G profit: 52.36875-52.50=-0.13125 Output: D:5.13,G:-.13 Input: ADJdja • A: Buy -$50
• D: Buy - $52.50 • J: Buy -$55.125
• d: Sell - $57.88125 • j: Sell -$54.9871875
• a: Sell - 52.237828125 • Person A profit: 52.237828125-50=2.237828125 • Person D profit: 57.88125-52.50=5.38125 • Person J profit: 54.9871875-55.125=-0.1378125 Output: A:2.24,D:5.38,J:-.14 • @ETHproductions When you print output, it doesn't really matter what the datatype is, it just needs to convey the right information. Jan 12, 2016 at 20:50 • Can the final result be truncated instead of rounded? Jan 12, 2016 at 22:08 • @Mwr Sorry, you have to round. Jan 12, 2016 at 22:11 • Do we have to output the people in alphabetical order? Jan 13, 2016 at 10:32 • Also, Python rounds stuff weirdly; 5.125 rounds to 5.12 by default. Is this accepted? Jan 13, 2016 at 10:45 ## 9 Answers # APL (Dyalog Extended), 34 32 bytes ⌊{⍺,2⍕+/-⍵}⌸××50×¯1×\⍤↓1,1+.05××  Monadic × in Dyalog extended for letters corresponds to the casing ¯1 1 ≡ ×'aA' 1+.05×× - 1 + 0.05 times the sign (either 1.05 or 0.95) 1, - concat 1 to the front ¯1×\⍤↓ - cumulative product and drop the last element 50× - multiply by 50 ××50... - the sign times that ⌊{⍺,2⍕+/-⍵}⌸ - group (dyadic ⌸) by the lowercased input (⌊) {⍺,2⍕+/-⍵} - return the left item (the person) concat their rounded total  -2 thanks to Adám Try it online! • ¯1 1 ≡ ×'aA' and being able to floor letters makes dyalog much more elegant than J in this case. Jan 10, 2021 at 18:40 • @Jonah only dyalog extended, it wouldn't be as nice in regular dyalog Jan 10, 2021 at 18:54 • ×∘(×\)¯1↓×¯1×\⍤↓ – Adám Feb 18, 2021 at 6:50 ## Java, 277 bytes class c{public static void main(String[]a){double[]m=new double[26];double s=50;for(byte b:a[0].getBytes()){if(b>=97){m[b-97]+=s;s*=.95;}else{m[b-65]-=s;s*=1.05;}}char g=65;for(double k:m){if(k!=0){System.out.println(g+String.format(java.util.Locale.ENGLISH,"%.2f",k));}g++;}}}  Ungolfed: class c { public static void main(String[]a) { double[] m = new double[26]; double s = 50; for(byte b : a[0].getBytes()) { if(b>=97) { m[b-97]+=s; s*=.95; } else { m[b-65]-=s; s*=1.05; } } char g=65; for(double k:m) { if(k!=0) { System.out.println(g+String.format(java.util.Locale.ENGLISH,"%.2f",k)); } g++; } } }  • A lot of the formatting is unnecessary. Having a 0 before the decimal point is o.k., commas and colons are not necessary. Jan 12, 2016 at 20:47 • great this reduces my byte count significantly Jan 12, 2016 at 20:49 • The class doesn't need to be public. Jan 12, 2016 at 21:43 • Is specifying the Locale necessary? I don't mind if it shows up as "3,54". Jan 13, 2016 at 16:39 • Store your money in a float, this saves bytes and might get you some extra profit ;) Jan 13, 2016 at 16:54 # JavaScript (ES7), 145 142 bytes I can't find a shorter way to round out the results... x=>[for(c of(i=50,a={},x))(a[d=c.toUpperCase()]=a[d]||0,c<"["?(a[d]-=i,i*=1.05):(a[d]+=i,i*=.95))]&&Object.keys(a).map(k=>[k,a[k].toFixed(2)])  Fun fact: this would only be 101 bytes if not for the rounding requirement: x=>[for(c of(i=50,a={},x))(a[d=c.toUpperCase()]=a[d]||0,c<"["?(a[d]-=i,i*=1.05):(a[d]+=i,i*=.95))]&&a  • 43 bytes seems to much..I'm sure you can find a better way! Jan 12, 2016 at 21:08 # Python 3, 116 bytes P=50 M={} for c in input():C=c.upper();u=c>C;u+=~-u;M[C]=M.get(C,0)+P*u;P*=1-u*.05 for k in M:print(k,round(M[k],2))  ### Ungolfed price = 50 profits = {} for char in input(): upper = char.upper() direction = 2 * (char > upper) - 1 profits[upper] = profits.get(upper, 0) + price * direction price *= 1 - direction * .05 for key in profits: print(key, round(profits[key], 2))  • It seems shorter to just do u=2*(c>C)-1 directly. – xnor Jan 13, 2016 at 21:11 • at the end of line 3, /20 would save one byte over *.05 Feb 18, 2021 at 13:33 # ARM Thumb-2 (VFP + printf, softfp ABI), 109 104 bytes Uses the softfp ABI (default on Android). It won't work on armhf Linux. f7ff fffe is a 4 byte linker placeholder for printf. Both of these examples must be placed at an address that is not a multiple of 4 (but even), and must be in a W+X section because we modify an inline printf string in place. b5f8 2100 2234 3a01 b402 d8fc f2c4 0249 ec42 1b10 ed9f 1b11 f810 2b01 b192 3a61 bf48 3220 eb0d 02c2 ed92 5b00 bf47 ee35 5b40 ee00 0b01 ee35 5b00 ee00 0b41 ed82 5b00 e7e9 2641 bc0c b11b a005 7006 f7ff fffe 3601 2e5a ddf6 bdf8 999a 9999 9999 3fa9 2558 322e 0066  Assembly:  .syntax unified .arch armv6t2 // We need VFPv2 for this. .fpu vfpv2 // We modify an inline string in place, so we need W+X. .section ".writeable_text","awx",%progbits .thumb .globl silly_stocks .thumb_func // Must NOT be 4 byte aligned. // .align 4 // nop // void silly_stocks(const char *input); // Follows AAPCS convention. // input is a null-terminated string in r0. silly_stocks: push {r3-r7, lr} // double buf[26] = {0} movs r1, #0 movs r2, #26*2 .Lclear_loop: subs r2, #1 push {r1} bhi .Lclear_loop .Lclear_loop_end: // note: r1 and r2 are zero at this point // r1:r2 = 0x4049000000000000 = 50.0 double movt r2, #0x4049 vmov d0, r1, r2 vldr d1, .Lfloat_pool .Lprocess_loop: // Loop until the null terminator. // while (r2 = *input++) ldrb r2, [r0], #1 cbz r2, .Lprocess_loop_end // tolower(r2) - 'a' // // Specifically, we subtract 'a', and if the char was uppercase, // it would be negative, triggering the N flag, which is why we // check the mi condition in the following IT blocks. subs r2, #'a' it mi // if (isupper(r2)) addmi r2, #'a' - 'A' // Yucky. We can't use proper offsetting with VFP and we need to // keep the flags for the IT block. add.w r2, sp, r2, lsl #3 // Behold, the beautiful syntax of VFP/NEON. // Combine it with a an IT block and you get a 10 letter mnemonic. OwO vldr.64 d5, [r2] ittee mi // if (isupper(r2)) { // Buy vsubmi.f64 d5, d5, d0 // profit[i] -= d0 vmlami.f64 d0, d0, d1 // stock_price += stock_price * 0.05 // } else { // Sell vaddpl.f64 d5, d5, d0 // profit[i] += stock_price vmlspl.f64 d0, d0, d1 // stock_price -= stock_price * 0.05 // } endif vstr.64 d5, [r2] b .Lprocess_loop .Lprocess_loop_end: movs r6, #'A' .Lprint_loop: // Pop the double into r2 and r3. We are using the softfp abi, so // doubles are passed in integer registers. pop {r2, r3} // Only check if the most signicant half of the double is zero. // Any non-zero double that is 0x00000000xxxxxxxx is denormal. cbz r3, .Lprint_loop_skip // Set up an AEABI call to printf. adr r0, .Lprintf_str // Instead of %c, store the char directly (that's why we need W+X) strb r6, [r0] bl printf .Lprint_loop_skip: // Loop from A-Z. adds r6, #1 cmp r6, #'Z' ble .Lprint_loop pop {r3-r7, pc} // At least for the softfp ABI, doubles are smaller than floats. // This is because printf takes doubles, not floats, and we need // to pass them in a register pair. // So we would need something like this, which is 12 bytes. // vpop {d0} // vcvt.f64.f32 d0, s0 // vmov r2, r3, d0 .align 2 .Lfloat_pool: .double 0.05 .Lprintf_str: // Our printf string. We modify X directly. .asciz "X%.2f" .section ".testsuite_unscored","ax",%progbits .macroTEST str
bl            puts
bl            silly_stocks
movs          r0, #'\n'
bl            putchar
b             2f
.align 2
1:
.asciz        "\str"
.align 2
2:
.endm

.align 2
.globl main
.thumb_func
main:
push          {r4, lr}
$TEST "AABaBbba"$TEST         "DGdg"
TEST "ADJdja" pop {r4, pc}  Decided to take a shot at VFP code in ARM assembly instead of doing something easy (and basically identical to the Java entry) like C or C++. One of the things I realized the hard way was that ARM actually needs the stack to be 8 byte aligned, or else subtle bugs will occur. Two hours of debugging I am NEVER getting back. 😫 Oddly enough, using doubles is smaller than floats, despite the larger literal pool. This is because the C calling convention mandates that floats be promoted to double in variadic functions, so we would have to convert to double anyways, and that is larger than the 8 bytes for the larger pool. Output isn't pretty. But the question says "separators not required" so I took that in the most literal sense. 😏 AABaBbba A7.49B2.47 DGdg D5.12G-0.13 ADJdja A2.24D5.38J-0.14  But aside from the 5.12 which is the same rounding error that was mentioned in Python, the results are correct. # ARM Thumb-2 (VFP + printf, softfp ABI, very imprecise), 99 96 bytes This version uses 32-bit x 16-bit fixed point arithmetic. It lacks the required 6 digits of precision, but for the test cases it products the same results. Interpret it as you wish. Must be loaded at an address that is not a multiple of 4 for constant pool alignment. Machine code: b5f8 2100 2534 3d01 b402 d8fc f2c0 0132 4d11 f810 2b01 b172 3a61 bf48 3220 f85d 3032 fb51 f605 bf47 1a5b 4431 440b 1b89 f84d 3032 e7ed 2641 ecbd 0b02 eeba 0bc8 ec53 2b10 b11b a004 7006 f7ff fffe 3601 2e5a ddf1 bdf8 cccc 0ccc 2558 322e 0066  Assembly:  .syntax unified .arch armv6t2 // We need VFPv2 for this. .fpu vfpv2 // We modify an inline string in place, so we need W+X. .section ".writeable_text_fixed","awx",%progbits .thumb .globl silly_stocks_fixed .thumb_func // Must not be 4 byte aligned. // .align 4 // nop // void silly_stocks_fixed(const char *input); // Follows AAPCS convention. // input is a null-terminated string in r0. silly_stocks_fixed: push {r3-r7, lr} // We use double the width because we need to keep alignment. // int64_t buf[26] = {0} movs r1, #0 movs r5, #26*2 .Lclear_loop_fixed: subs r5, #1 push {r1} bhi .Lclear_loop_fixed .Lclear_loop_end_fixed: // Load our float constants from the pool. movt r1, #0x32 // 0x00320000 = 50.0 in 16-bit fixed point ldr r5, .L.05.fix32 // 0x0ccccccc = 0.05 in 32-bit fixed point .Lprocess_loop_fixed: // Loop until the null terminator. // while (r2 = *input++) ldrb r2, [r0], #1 cbz r2, .Lprocess_loop_end_fixed // tolower(r2) - 'a' // // Specifically, we subtract 'a', and if the char was uppercase, // it would be negative, triggering the N flag, which is why we // check the mi condition in the following IT blocks. subs r2, #'a' it mi // if (isupper(r2)) addmi r2, #'a' - 'A' ldr r3, [sp, r2, lsl #3] // fixed point multiply: // x<fixA> = (y<fixB> * z<fixC>) >> (B + C - A) // tmp<fix16> = (stock_price<fix16> * 0.05<fix32>) >> 32 smmul r6, r1, r5 // r6 = stock_price * 0.05 ittee mi // if (isupper(r2)) { // Buy submi r3, r1 // profit[i] -= stock_price addmi r1, r6 // stock_price += stock_price * 0.05 // } else { // Sell addpl r3, r1 // profit[i] += stock_price subpl r1, r6 // stock_price -= stock_price * 0.05 // } endif str r3, [sp, r2, lsl #3] b .Lprocess_loop_fixed .Lprocess_loop_end_fixed: movs r6, #'A' .Lprint_loop_fixed: // Pop the result into d0 (also cleaning the stack) vpop {d0} // Convert from fix16 to double vcvt.f64.s32 d0, d0, #16 // Move the double result into r2 and r3. This is for the softfp ABI // which passes floating point values in registers. vmov r2, r3, d0 // Only check if the most signicant half of the double is zero. // Any non-zero double that is 0x00000000xxxxxxxx is denormal. cbz r3, .Lprint_loop_skip_fixed // Set up an AEABI call to printf. adr r0, .Lprintf_str_fixed // Instead of %c, store the char directly (that's why we need W+X) strb r6, [r0] bl printf .Lprint_loop_skip_fixed: // Loop from A-Z. adds r6, #1 cmp r6, #'Z' ble .Lprint_loop_fixed pop {r3-r7, pc} // 0.05 in fix32. .L.05.fix32: .word 0x0ccccccc // Our printf string. We replace the X when we use it. .Lprintf_str_fixed: .asciz "X%.2f" .section ".testsuite_unscored","ax",%progbits .macroTEST str
bl            puts
bl            silly_stocks_fixed
movs          r0, #'\n'
bl            putchar
b             2f
.align 2
1:
.asciz        "\str"
.align 2
2:
.endm

.align 2
.globl main
.thumb_func
main:
push          {r4, lr}
$TEST "AABaBbba"$TEST         "DGdg"
$TEST "ADJdja" pop {r4, pc}  For the reference, here is the results for float vs fixed point at 6 digits of precision. AABaBbba float: A:7.488484,B:2.474079, fixed: A:7.488434,B:2.474060, DGdg float: D:5.125000,G:-0.131250, fixed: D:5.124969,G:-0.131256, ADJdja float: A:2.237828,D:5.381250,J:-0.137812, fixed: A:2.237808,D:5.381226,J:-0.137817,  # Perl 5-MList::Util=pairmap -F, 80 bytes $p=50;map{$k{uc$_}+=$q=95>ord?-$p:$p;$p-=$q/20}@F;pairmap{printf"$a:%.2f ",\$b}%k


Try it online!

# Javascript (ES6, Node.js), 136 bytes

## Source

s=>(m=50,a={},[...s].map(p=>(u=p.toUpperCase(),n=p==u?1:-1,a[u]=(a[u]||0)-m*n,m*=1+n/20)),Object.keys(a).map(k=>a[k]=a[k].toFixed(2)),a)


## Explanation

f=s=>( // (s)tring
m=50, // stock value (m)oney
a={}, // (a)ll people
[...s].map(
p=>(
u=p.toUpperCase(), // (u)ppercase: used to group buys and sells for each person
n=p==u?1:-1, // sig(n): 1 for buy, -1 for sell
a[u]=(a[u]||0)-m*n, // adjust balance with stock value and sign
)
),
Object.keys(a).map(k=>a[k]=a[k].toFixed(2)), // round profits
a // return profits
)


## Proof

f=s=>(m=50,a={},[...s].map(p=>(u=p.toUpperCase(),n=p==u?1:-1,a[u]=(a[u]||0)-m*n,m*=1+n/20)),Object.keys(a).map(k=>a[k]=a[k].toFixed(2)),a)
const TESTS = [
['AABaBbba',{A:'7.49',B:'2.47'}],
['DGdg',{D:'5.13',G:'-0.13'}],
]

TESTS.forEach(([input,expected])=>{
console.log(input);
console.log(expected);
console.log(f(input))
});

# Japt, 91 84 bytes

A=[]J=50¡AhD=Xc %H(X<'_?[AgD ª0 -JJ*=1.05]:[AgD +JJ*=.95] g};A£X©[Y+I d X*L r /L]} f


Based on my JS answer. Try it online!

# J, 64 bytes

tolower(~.@[,.(0j2":_50*+/)/.)](]*1*/\@}:@,1+0.05*])_1+2*91>3&u:


Try it online!