Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
klafbang
Nov 18, 2009
Clapping Larry

Carbon dioxide posted:

There are no decimals. The chip supports all integer values between -999 and +999 inclusive (but the in/output on the analog p0 and p1 pins is always mapped to a number between 0 and 100).

You don’t need decimals to be able to turn division into multiplication. If we look at algebra, what computers do is basically computations in the ring Z/nZ where n is the number of different numbers (so 1999 in the example, often 232 or 264 in real computers).

That means computation is not our regular operations, but rater the operations “modulo n,” which is good enough in most cases. modulo just means “the remainder after division by n,” so for example 4 + 7 modulo 10 is 11 modulo 10 = 1 and 3 * 5 modulo 10 = 15 modulo 10 = 5.

The reason this is useful for division is because it is possible for two integers to be multiplied and get 1. For example, 3 * 7 modulo 10 = 21 modulo 10 = 1. In a sense, 7 = 1/3 modulo 10.

Consider 9 / 3 = 3. Also, 9 * 7 modulo 10 = 63 modulo 10 = 3. Hey, that works! Similarly, 6 * 7 modulo 10 = 42 modulo 10 = 2.

The condition for a number to have an inverse is that it has to be coprime with n. That means the largest common factor between the number and n has to be one. For example, 2 does not have an inverse modulo 10; we cannot find a number that multiplied with 2 yields a number with remainder 1 when divided by 10 (such a number would be odd, and 2 multiplied by any integer is even) because 2 and 10 have a common factor of 2. 4, 5, 6, and 8 also don’t work, but the inverse of 9 is 9 (9 * 9 modulo 10 = 81 modulo 10 = 1, so division and multiplication by 9 is the same modulo 10).

For this machine, though, n = 1999, which is a prime. That means that *every* number has an inverse, and we can divide by any number using multiplication! (Assuming that the machine behaves “sensibly” for a certain value of sensibly during overruns.). Try dividing by 42 by multiplying by 238 (after adding 999 to move the value to the interval 0-1998).

We have to be careful with fractions; for example, what is 8 / 3? Well, 8 * 7 modulo 10 = 56 modulo 10 = 6, which seems a bit weird; we would expect either 2 or 3. 6 is the correct answer, though, because 6 * 3 modulo 10 = 18 modulo 10 = 8.

This corresponds to how we can compute a - b by finding the inverse of b (often called -b) and using addition as a - b = a + (-b).

This actually has uses in cryptography.

klafbang fucked around with this message at 22:07 on Aug 16, 2018

Adbot
ADBOT LOVES YOU

idhrendur
Aug 20, 2016

ivantod posted:

Considering that the game is set in China, and that the currency symbol is ¥, I would assume that the costs are given in Chinese Yuan, so 1¥ = 0.15$. Does that sound less pricy? :v:

Maybe? I'm not a hardware guy so I'm not used to choosing the chips, just programming them. But the one I've used the most lately is ~$3 each, and have tons more pins, USB handled automatically, plenty of other protocols automatic, etc. But it seems like this game is also near future, so inflation could be a thing.

Quackles
Aug 11, 2018

Pixels of Light.







Jie’s daughter is a game whiz.



I’ve been playing this for three hours now.

[ ~ ]

OK, in the interest of getting something useful done with my time, I figure I might explain the rules of Jie’s daughter’s game, and maybe a bit of strategy to go with it.


The Goal

First off: The goal is to get all the cards up to the spaces in the top. You can move cards that aren’t buried under anything, as well as stacks that are built down in alternating colors (like Solitaire).

The three cells in the top left are ‘free’ and any card can be moved there (though they’ll be used to stack the Dragons by the end of the game - see below). The flower card will fly into the top center as soon as it’s movable. And the number cards go into the three slots on the top right, sorted by color and in numerical order.


Number Cards



You can move a number card:
• Onto free cells
• Onto a card of the next number up (but not of the same color) to make a stack - you can repeat this to build up a big stack all the way up to 9.
• Onto a blank cell on the table
• Onto their spot in the top right if the previous number card of the same color is already there (this will happen automatically a lot)

You can move a stack of number cards in the same way, except it can’t go in a free cell or the top right (except one card at a time). It’s possible to move just part of a stack around, as long as you have somewhere you can set it down.

If you unearth a ‘1’ card, it will automatically fly up to a spot on the top right (as will a ‘2’ if the ‘1’ of the same color is already there.)
Cards of higher values will only automatically move to the top right if all the cards of the previous number are there already (so a 5 will only move there if all three 4s are present, for example).

You can also move a number cards to the top right manually if it qualifies to be there but the game hasn’t auto-moved it yet. Once you do this with a card, it can’t be moved back, so this is mostly an advanced strategic move.


The Dragons



‘Dragons’ are the cards with the large symbol on it. There’s four of each.

You can move the dragons:
• Onto free cells
• Onto a blank cell on the table
…and that’s it. As you might imagine, Dragons are going to be generally annoying to deal with

If all four of a Dragon are unburied (movable), you can push the button with the associated symbol (near the top center) to send those four Dragons to one of the free cells, permanently. This will lock that free cell for the rest of the game, but that’s usually an OK tradeoff.

You do need at least one free cell that is either {A} empty, or {B} has one of the Dragons you’re trying to clear away already in it, for this to work.


Strategy

Like a lot of solitaire games, this game has a ‘tipping point’ after which winning becomes pretty trivial. The trick is not getting stuck along the way.

When the game starts, you have two major goals to accomplish in the early to medium part of the game:

• Get the number cards 1-3 for each color up to the top right. This is your primary priority.
• Get one set (or more) of the Dragons out of the way. You’ll probably have to do this to accomplish the first goal.

Take a look at the tableau before you make any moves - try to see where the 1s, 2s, and 3s are, how buried they are, and how many cards you’ll need to move to get to them. Also note where the Dragons are. If any set of Dragons is near the top of the table piles, it might be worth trying to remove that set early - the same goes for if a particular set of Dragons is blocking access to a lot of 1-3s (though this might be harder depending on how far those Dragons are towards the bottom).

Once you start moving, building is your friend - but be careful if you build on piles that have a 1, 2, or 3 buried underneath them. Try to have an idea of what your plan is for moving your stack off the pile later so you can get at the number cards you’re going for.

It’s a good idea not to move Dragons willy-nilly if you don’t immediately have to get at what’s under them. An easy way to lose a game is to have Dragons locking up most of the piles and no valid moves. Removing a set of 4 Dragons from the board is almost always a good thing, though, especially if it leads to freeing a blank spot on the table.
You’ll do best if you plan which Dragons you’ll remove first and just how you’re going to get there - and in particular, you might want to favor moving number cards to free cells over Dragons, as the number card can be easier to get out later.

Once you have the 1-3s sorted out, your job becomes a lot easier - if you haven’t made a serious attempt at removing Dragons before, you should see if you can easily take out any sets now. Building stacks and moving number cards to the top right should be a lot easier as well.

Good luck!





I should probably learn to read Chinese at some point. Right now I’m stuck with cruddy machine translation. Or David.

That said: Poor Joe.




P.S.: Might as well respond to a few replies while I have the time…

Aesculus posted:

I've been to Shenzhen once, it's pretty great. The Pizza Huts are more upmarket dine-in establishments that serve steak and duck and the rollercoasters are insane.


@Aesculus - Thanks for the tip! I’ll have to check out a Pizza Hut here sometime.

Solumin posted:

I sure hope you got permission from your manager and from Legal to post source code and pictures of hardware to your personal blog. :colbert:

@Solumin - Tell you what: you don’t tell Jie, and I won’t tell Jie.

Ibblebibble posted:

Can you multiply by decimals to divide?

klafbang posted:

You don’t need decimals to be able to turn division into multiplication.

@Ibblebibble, also @klafbang - Alas, no. MCs use only integer math, from -999 to 999. Any value that would overflow or underflow will get capped at the most appropriate of those two values, so the idea to use modulo arithmetic doesn’t work… I think.


Tenebrais posted:

Programming is a fun and rewarding hobby that some people happen to make the mistake of doing as a job.

@Tenebrais - Well said! :hfive:


P.P.S: Jie said something about his daughter planning to submit the game to an app store or two

Quackles fucked around with this message at 07:29 on Aug 17, 2018

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
So what does that email conversation say? I'm not about to try to re-type the characters into Google Translate.

I'm guessing it involves Joe getting raked over the coals for playing solitaire at work?

Ibblebibble
Nov 12, 2013

My Chinese reading is pretty rusty but the general gist I got from it is that Joe got so into the game that it had to be pulled from his work computer.

Edit: a slightly better translation, but probably not perfect:

Joe: Great! I can't put this down! Your daughter is amazing!

Lili: Boss, please tell your daughter her game is too good, so I have removed it from Joe's computer, in order to make him work better.

Joe: Aww.

Ibblebibble fucked around with this message at 22:51 on Aug 16, 2018

Aesculus
Mar 22, 2013

Quackles posted:




@Aesculus - Thanks for the tip! I’ll have to check out a Pizza Hut here sometime.
I recommend the clam chowder and any of the pasta dishes. Don't bother with the steaks, they're mostly there to lure natives into an overpriced idea of western food.

Also does your boss know you've spent three hours on solitaire just today? :ohdear:

Grayshift
May 31, 2013
Oh nice, I am curious to see if I even remember what puzzle it was that eventually stumped me when you get there.

Shenzhen I/O is pretty great, definitely the hardest Zachtronics game since Spacechem for the cutthroat space/instruction/timing limitations. TIS-100 may have had a bizarre architecture but it was positively roomy in each cell - 15 instruction lines, two registers and a SWAP instruction! Luxury, considering how many cells you might need just to bridge inputs to outputs. Shenzhen makes you pay for everything. The timing conditions were always my big failure. Any puzzle that required bridging the two input types caused some hair tearing because I could never find a simple, satisfying way to do it.

A note should be made about the music in Zachlikes, it's all fantastic "focusing" music. Especially the Solitaire theme.

Jie is a really good character. There's a sense of a fantastic, smart personality being filtered through excessively formal/terse language skills.

Tenebrais
Sep 2, 2011

Grayshift posted:

A note should be made about the music in Zachlikes, it's all fantastic "focusing" music. Especially the Solitaire theme.

They're all very good. All of the Zachtronics games' soundtracks are by Matthew S. Burns and are available on Bandcamp.

Quackles
Aug 11, 2018

Pixels of Light.


All the Parts!



Carl came by and dumped a bunch of datasheets on my desk. It’s the rest of the garden-variety parts that Longteng likes to use: two more variants of the MC#### line, some memory chips, a bunch of logic gates (one per chip casing? There’s no bulk deal? Really?) and something called a ‘Digital I/O Expander’, which apparently lets you control three 100/0 (on/off) outputs from one XBus (digital I/O) port.

I also got Carl to explain exactly what Joe does! Turns out "Product Manager" is a nice way way of saying "Sales". It explains a lot, especially Joe's super-excited attitude. He's definitely a people person.

Indirectly, this explains what David does, as well. My first guess was mostly on the money - if "Product Manager" is "Sales", then "International Product Manager" is... the same, but focusing on what Western audiences would like, I guess. I wonder what sort of stuff they'll come up with?

Anyway, back to the new parts.

Microcontrollers

The biggest present in this whole package is the MC6000. It's basically the MC4000's big brother - space for 14 lines of code (a pretty respectable amount, honestly), a second register (dat), and two extra digital I/O (XBus) pins!! It costs 5¥ a shot instead of 3¥, but it's pretty worth it.





There is one catch, though: all those arithmetic instructions I explained in the last Corner still only target acc - and there's no 'swap' instruction or anything that reverses the contents of the two registers. So using MCs for math, even MC6000s, will still be cumbersome.

There's also a variant version of the MC4000 called the MC4000X. It costs the same, but the 4000X has four digital I/O pins (x0-x3) rather than two simple (p0, p1) and two digital (x0, x1).




Memory Chips

I've got two types of memory chips available to me: the 100P-14 (read/write) and the 200P-14 (read-only). They each hold 14 values, and basically behave about like you'd expect for memory - you tell the chip where in its storage you want to read or write data, then write or read values in/out as appropriate. Both are ¥2 each.



There are a few wrinkles, though. The first is that the 100P starts blank, and you have to get data into it by writing it at runtime. Meanwhile, the 200P is set up with values in my simulator, and then its contents are fixed forever after - you can only read data out of it.



The second wrinkle is that both the 100P and 200P have "auto-incrementing address pointers". This is a nice way of saying that if you write to or read from a specific memory cell, your next read or write will automatically target the next cell in the memory chip (wrapping around, of course).

I'm not sure how useful and/or annoying this will be, so I'll give people updates once I have to use one chip or the other.


Logic Gates

There's some logic gate chips, which look like they mostly work with simple I/O (so they're using 0 for OFF (binary 0) and 100 for ON (binary 1)). They're all ¥1 each. I'm gonna let the datasheet do the talking about what exactly each one does, for the most part.





One cool thing about these chips: the AND, OR, and XOR gates have an extra output (the one with the dot) that gives the opposite value to what the gate would normally give out. It feels like it'd save on having to buy extra NOT gates to reverse outputs, at least!

I imagine these'd be useful for any sort of job where you have to play around with binary 'signal math' - stuff like "This output is ON only when these other two outputs are ON", that sort of thing.


Digital I/O Expander

So this was an animal new to me, but reading the datasheet, I can see how it could be useful. It basically lets you control (or read) 3 simple I/O signals from one digital I/O port - and I get the feeling that someday, I'll be happy to pay ¥1 for this rather than ¥3 for a new MC with two more simple I/O pins.

 

Come to think of it, you could probably use this to coordinate a series of three or more MCs together, as long as the ones on the simple I/O side were only sending one bit of information to the MC on the XBus end. I should make a note of this...


P.S: I noticed some of you had questions about the parts earlier - with this infodump, I'm feeling more prepared to answer those now!

idhrendur posted:

And these chips are really about a dollar each? From what I can recall from the datasheets of some microcontrollers I've used in the past couple years, that seems pricy for the feature set. But maybe they've got some features I haven't seen or are ultra-low power or something.

TooMuchAbstraction posted:

I'm surprised that such a simple and limited chip has two analog I/O pins. Usually you only get digital on something like this.

@idhrendur - It did seem pretty pricey to me, but you have to remember that exchange rates have been volatile over the past few years. For example, back in, say, 2018, 3¥ was about $0.45 US - but here in 2026, well... ¯\_(ツ)_/¯
On top of that, there's some benefits to these MCs that aren't obviously apparent. One is that they apparently consume next to no power while sleeping, which is pretty impressive in itself - that, and their simple I/O pins can handle and emit surprisingly high voltages for microelectronics (if provided with appropriate power sources). I have no clue how they do it.

@TooMuchAbstraction, I'm guessing my musings above about the simple I/O pins might be why the MC line is so popular. Of course, they did say on the MC4000 datasheet that popular demand had gotten them to start making the MC4000X, so I'm not entirely sure what to think...

NGDBSS posted:

Though to clarify, does this language allow for complex calls within an operation? As it stands it looks like the above operation requires a few steps, and depending on whether they can be nested or not would change what one can do.

[...to swap values] in the case of microcontrollers (such as here) there's always the XOR swap algorithm or its variants.

@NGDBSS - No nesting of instructions, unfortunately. It would be nice, but it doesn't look like MCs are much for indirection and recursion.
And XOR swap would be great if I had anything that looked like XOR, or any binary operation! I get that decimalized MCs are easier to use in some ways, but I still have to wonder how they got so popular here...

Aesculus posted:

Also does your boss know you've spent three hours on solitaire just today? :ohdear:

@Aesculus - You don't tell Jie, and I won't tell Jie. 😓

Quackles fucked around with this message at 22:56 on Aug 17, 2018

ally_1986
Apr 3, 2011

Wait...I had something for this...
"I should probably learn to read Chinese at some point. Right now I’m stuck with cruddy machine translation. Or David."

Good luck with that. I think you need to learn around 3000 - 4000 characters to read a newspaper. Or impress your friends back home by learning to write one, two, three, middle and tian because super easy! I tried to learn the langugae but the tones! I found the history of the language more interesting or random facts like on and off put together become switch for a light which I always thought was neatl

Eh the cheese was alright? I didn't eat much of it, I tried to call the delivery number and they said they couldn't find my address even though I saw delivery people come every day :( - Yea Pizza hut is really strange place as only one page is about pizza and KFC was the worst and made me sick. Hot pot in winter is a winner and Sichuan cuisine if you like spicy food.

If you do a good job be prepared for your company to be taken over by TenCent. I went back to Shenzhen in February and was amazed that hardly anyone uses cash and pays through Wechat or Alipay. I got an odd look when I had to pay with a credit card.

idhrendur
Aug 20, 2016

Thanks for clarifying on the price point. I do tend to be stuck in the past when I think about exchange rates. And the possibility of high voltage outputs with a low power wait is definitely interesting. I'm used to only having a sleep mode that restarts the chip.

And auto-incrementing memory addresses are great! Well, depending on the use, but I'm sure you'll be demonstrating both the good and bad soon enough.

Carbon dioxide
Oct 9, 2012

In your solitaire post there's a line that ends abruptly:

"• Onto a card of the next number up (but not of the same color) to make a stack - you can repeat this to build up a "

Anyway, I've been thinking about the issue of division. I think we can do that "the hard way", especially with more registers available.
We do need conditional loops, though.
Imagine you have 21 / 6.

Well, store 21 in a register, then in a loop subtract 6 from the register each time and increment a counter in another register. If the result of the subtraction is more than the divisor 6, repeat the loop. Otherwise, the counter contains the answer and the arithmetic register contains the remainder (result of the modulo operation).

On another note, I visited China earlier this year. Didn't really visit Shenzhen, although I passed through it on the train from Guangdong to Hong Kong. A world of difference by the way. In mainland China you can see much more of the traditional Chinese culture, and lots of locals there are surprised to see westerners. Hong Kong is truly an international city where the British influence is still clearly visible. I wonder how it is in Shenzhen? I heard a lot of people who work in Hong Kong went to live in Shenzhen because housing prices in Hong Kong are through the roof.

I picked up a handful of words while in China.
'Xie xie', pronounced something like 'tsay tsay' means thank you.
Another very handy one is 'Bu yao', pronounced boo yow. It means "do not want" and it's what you use to shake off annoying street salesmen.
And of course "Ni hao" just means hello.

Now, these are Mandarin pronounciations. In Shenzhen most people will be speaking Cantonese. They will probably understand you if you say simple things in Mandarin, especially because simple phrases sound similar enough, but they might give you strange looks, and once you get better at Chinese and start using more complicated phrases the difference might get difficult. The only good news is that phrases in Mandarin and Cantonese are written exactly the same (they use the same characters).

Oh, and the language tones. I found this example on the internet:

quote:

妈 mā mother
麻 má bother
马 mǎ horse
骂 mà scold
This means 'ma' with a flat tone means mother, 'ma' with a rising tone means bother, 'ma' with fall followed by a quick rise means 'horse' and 'ma' with a falling tone means scold.
Don't accidentally call someone's mother a horse, that's rude.

You should really visit one of the local Chinese neighbourhood markets by the way! They are quite the sight... and smell. Row after row after row of unusual vegetables and fruits, live animals in cages ready for slaughter, all kinds of meat we wouldn't even think of eating here in the west, and everyone haggling in loud voices.

Carbon dioxide fucked around with this message at 07:08 on Aug 17, 2018

Aesculus
Mar 22, 2013

Carbon dioxide posted:

You should really visit one of the local Chinese neighbourhood markets by the way! They are quite the sight... and smell. Row after row after row of unusual vegetables and fruits, live animals in cages ready for slaughter, all kinds of meat we wouldn't even think of eating here in the west, and everyone haggling in loud voices.

On that note, where did Carl manage to find a decent dumpling shop in Shenzhen? Last time I was there the street stalls were usually all corn juice and steamed buns or Chinese barbecue meats, with some assorted other restaurants. The craziest I've seen was a noodle shop that had a giant pot with a radius of at least a meter that I swear they stuffed an entire cow carcass into and kept boiling 24/7, with a combination hot pot/sushi restaurant being a close second. They were pretty good, actually.

This thread is just going to turn into the China travel thread now, isn't it? :v:

Ibblebibble
Nov 12, 2013

There's also the awkwardness of accidentally declaring that you want to kiss someone instead of saying that you want to ask them something.

问 is ask (wèn)
吻 is kiss (wěn)

Ratoslov
Feb 15, 2012

Now prepare yourselves! You're the guests of honor at the Greatest Kung Fu Cannibal BBQ Ever!

Those memory chips look like a spectacular pain in the butt.

Quackles
Aug 11, 2018

Pixels of Light.


Pulse Generator









So, uh, the spec is pretty straightforward at least. But, remember when I said that I read the manual? In actuality, turns out I sort of skimmed it around the parts that had to do with conditional execution (doing stuff only when certain conditions are met).

I'm assuming it works like it does in the boards I learned on: you'd have a test instruction, then you'll jump to another part in the code depending on if that test is true or not.





This is my first prototype. The first line (teq p0 100) is the test for whether the button is being pushed or not. Normally, the next instruction jumps to the label "loop", right before the slp - but the " – " at the front of the line means that the jump is only turned on when the test is false. (The " – " flag is what makes it conditional.)
So, when the button is pushed and the test is true, the jump is disabled (as in the pic) and the pulse is sent out.

(There's also a " + " flag I could use if I wanted the jump to happen only if the test was true.)

[ ~ ]

😑

Jie took a look at the design, then sent it back. He didn't say it was wrong - he mentioned that jumping to the end was a useful design pattern for later - but he explained something I'd completely missed about MC#000 conditionals:

You can put a conditional flag in front of any instruction on a MC. Not just jumps. You can put them on data-moving instructions, math instructions... even other tests!
Whether any particular flags trigger is based on the state of the last test instruction the MC ran, no matter how long ago that was.

So I don't need to jump to the end - I can just run the test, then flag all the instructions that would send the pulse, to only run if the test is true ( + ).





Here's the final version. The pic is taken while the button isn't pressed (so the test is false, so " + " instructions are disabled).



Moral of story: Jie has high standards and part of my job is to live up to them.

Quackles fucked around with this message at 09:35 on Aug 18, 2018

Quackles
Aug 11, 2018

Pixels of Light.


Engineer's Corner 3: The Pluses and Minuses of Conditional Execution

So after that last job, I realized I needed to brush up on the part of the manual that deals with conditional execution - which means you get to hear about it too.

The way a MC works is that you can flag any line of code with either a + or a . When the power is switched on, + and – instructions are inactive (greyed out). This stays that way until you do a test instruction.



Basic Test Instructions

The MC has a few different test instructions you can use.

teq - test if two things are equal
tgt - test if the first item is greater than the second one
tlt - test if the first item is less than the second one
    teq/tgt/tlt  value_or_location  value_or_location

tcp - comparison test (special; I'll explain below)
    tcp  value_or_location  value_or_location

"value_or_location" can be a number, a register name, or a pin name, which is pretty convenient.

For most of the tests (teq, tgt, and tlt), if the test is true, + instructions turn on, and instructions turn off and go grey. If the test is false, it's the other way around: + instructions go grey and turn off, and instructions turn on.
This stays that way until you run another test.



tcp: the Three-Way Test

tcp is special, though. It compares the value of whatever's put in it, but it's got three possible outcomes - it seems like it could be good for saving lines of code.

• Item 1 < Item 2: instructions on, + instructions off
• Item 1 > Item 2: + instructions on, instructions off
• Item 1 = Item 2: Both + and instructions off!!

That last outcome is the only way you can reset a MC to the condition state it starts in when you first switch it on, by the way.

(At this point, I'd post some example code for a good use of tcp, but I honestly can't think of something that fits the bill! What I will do, though, is if it comes up in an assignment, I'll point it out and make a big point about why it's the best instruction for the job. Deal? 😁)

Quackles fucked around with this message at 09:32 on Aug 18, 2018

NGDBSS
Dec 30, 2009






Quackles posted:

Jie took a look at the design, then sent it back. He didn't say it was wrong - he mentioned that jumping to the end was a useful design pattern for later - but he explained something I'd completely missed about MC#000 conditionals:

You can put a conditional flag in front of any instruction on a MC. Not just jumps. You can put them on data-moving instructions, math instructions... even other tests!
Whether any particular flags trigger is based on the state of the last test instruction the MC ran, no matter how long ago that was.

So I don't need to jump to the end - I can just run the test, then flag all the instructions that would send the pulse, to only run if the test is true ( + ).
It sounds like he's taking a page out of Edsger Dijkstra's book about avoiding goto as much as possible. There's actually a theorem on the subject that states that a program only needs three tools to deal with computable functions - sequence (one thing after another), selection (choosing which direction to proceed based on conditionals), and iteration (repeated execution so long as something holds, eg the while loop). Some of the most strident criticisms against goto have been obsoleted by now, but regardless you can accomplish much the same thing with a while loop and a switch to run subprograms based on some flag variable (ie, iteration + selection).

Carbon dioxide
Oct 9, 2012

Little challenge for those who haven't played this yet:

Figure out how you can program a logical OR and a logical AND using only the teq operation and the + / - modifiers.

So: If acc equals zero AND dat equals 10, send 100 to p1.
And: If acc equals zero OR dat equals 10, send 100 to p1.

It's surprisingly simple once you get it.

Dire Lemming
Jan 19, 2016
If you don't coddle Nazis flat Earthers then you're literally as bad as them.

Carbon dioxide posted:

Little challenge for those who haven't played this yet:

Figure out how you can program a logical OR and a logical AND using only the teq operation and the + / - modifiers.

So: If acc equals zero AND dat equals 10, send 100 to p1.
And: If acc equals zero OR dat equals 10, send 100 to p1.

It's surprisingly simple once you get it.

I'm guessing its just this
AND
teq acc 0
+ teq dat 10
+ mov 100 p1
OR
teq acc 0
- teq dat 10
+ mov 100 p1

Carbon dioxide
Oct 9, 2012

Yup!

Quackles
Aug 11, 2018

Pixels of Light.


Take an Orbital Selfie! Trips Start at Just R89,999!



Even in our modern age, no matter how good Bayesian analysis gets, no matter how much machine learning we throw at the problem, it looks like a few spam emails will always get through.

Might as well answer reader questions while I have the time.

Carbon dioxide posted:

In your solitaire post there's a line that ends abruptly:

"• Onto a card of the next number up (but not of the same color) to make a stack - you can repeat this to build up a "

@Carbon dioxide - ...aaaa bigger stack of cards. Whoops. I've fixed my earlier post - thanks for catching that!


Aesculus posted:

On that note, where did Carl manage to find a decent dumpling shop in Shenzhen? Last time I was there the street stalls were usually all corn juice and steamed buns or Chinese barbecue meats, with some assorted other restaurants. The craziest I've seen was a noodle shop that had a giant pot with a radius of at least a meter that I swear they stuffed an entire cow carcass into and kept boiling 24/7, with a combination hot pot/sushi restaurant being a close second. They were pretty good, actually.

@Aesculus - Holy moly, the cow thing sounds amazing.
Anyway, the dumpling shop turned out to be a dumpling stall, actually. The vendor guy was also selling (imitation?) shark fin soup, too (we never got whether it was real shark or not made clear). Everything was delicious.
5 stars, would eat there again.


NGDBSS posted:

It sounds like [Jie's] taking a page out of Edsger Dijkstra's book about avoiding goto as much as possible.

@NGDBSS - You're probably right. I get the feeling Jie's been mostly throwing me easy jobs to get me ready to work on more complex projects - and sending the job back was his way of making sure I'd get introduced to MC conditionals properly.


ally_1986 posted:

I think you need to learn around 3000 - 4000 characters to read a newspaper.

Carbon dioxide posted:

Now, these are Mandarin pronounciations. In Shenzhen most people will be speaking Cantonese. They will probably understand you if you say simple things in Mandarin, [...] but they might give you strange looks, and once you get better at Chinese and start using more complicated phrases the difference might get difficult.

Oh, and the language tones. [...]
Don't accidentally call someone's mother a horse, that's rude.

I feel a lot better about not knowing Chinese.

Quackles
Aug 11, 2018

Pixels of Light.


Light-Up Signs



Looks like Joe's come up with something! I hadn't heard of the Solid Steel Gamer before today, but she seems pretty cool from her bio. Can you imagine at some live event with however many hundred of her fans holding up animated signs? That'd be pretty freakin' intimidating!

This is also notable as the first time I've had to optimize my designs for anything in particular. In this case, per Joe's hint, I'm going to try to make the signs as cheaply as possible.







Well, this is an interesting design problem. Up until now, I'd had one, or two, outputs to work with. Now I have five - and each MC only has two simple I/O pins.
Now, I could just brute-force this by throwing 3 MC4000s in there, wiring it up, and calling it a day, but the total cost would be ¥9 (or, as Carl might put it, "bloody expensive").

So: There's gotta be a cheaper way to do this.

[ ~ ]





This is my first shot at it. I noticed some interesting patterns in the output signal patterns for the sign: click-0 and click-1 are the reverse of each other, and only one of drink-0 through drink-2 are on at any given time.
Meaning: this is the perfect time to try out some of those logic gates I got access to the other day.

The left MC just drives the click outputs. It creates a simple pulse for click-0, and then the NOT gate below it reverses it to send to click-1.
The right MC is in charge of all the drink outputs. The secret here is that drink-1, arguably the most complex output of the three, is only on when drink-0 and drink-2 are off. So, the MC pushes the right output to drink-0 and drink-2 and lets an OR gate sort out the rest: normally, the OR gate would be on when either of drink-0 or drink-2 are on - but I'm using the reversed output (with the dot), so instead the OR gate is off when drink-0 or drink-2 are on, and on when they're both off.

The thing is, all those logic gates still cost money. So instead of a third MC (¥3), I've got two logic gates (¥2), for a total cost of ¥8.

I think I might be able to get it down to ¥7 if I make the left MC drive click-0 and click-1 from different output pins, and lose the NOT gate entirely. I'll have to check if the code'll fit, though.

When I mentioned this to Joe, he said, "Bet you can't get it down to ¥6!"
This is why Joe's in Sales. :rolleyes:

[ ~ ~ ]





¥7 came pretty easily - the code on the left MC does indeed fit. However, I was talking about other potential optimizations, and someone in the ChipOverflow chat room said they thought they could actually get the design down to ¥6. For real.
Of course, they went AFK without saying how to do it, and then someone else on ChipOverflow gave me an earful because I called the wires on the board ‘wires’. (Apparently they are ~🎉 “traces" 🎉~. Sigh…)

I'm going to try to take a decent shot at getting the sign to ¥6, now that I know that it's (probably) possible. And I'll keep the chat open. Whoever it was said they were gonna be back soon...

[ ~ ~ ~ ]

It's been three hours. They haven't been back. The ¥6 version really really hasn't worked out.



Here's what I figured out when trying to make the ¥6 version:

• Using two MC4000s is out, because that's ¥6 already and I have 4 pins and 5 nonidentical outputs.
• Therefore: Use a MC6000 (¥5), and one of those Digital I/O Expander things (¥1) to push output to all three drink pins from one XBus pin.

• I can't toggle the click wires on and off more than once in the MC's script or I'll eat up all my code space, so I'm gonna have to have a loop of some sort to tell how far into the cycle we are. The accumulator will be a counter for this.

• The script pulses p0 once, and pulses p1 once. Each of these times uses 3 lines each (mov 100 p#, slp 1, mov 0 p#).
• The script has four places where it tests to see if the counter is at the right value, then updates the drink pins. This uses 2 lines each time (teq acc #, + mov ### x3).
• The script also needs a line that increments acc so it works as a counter (add 1), and two lines that roll it back to 0 when it's at the maximum value (teq acc #, + mov 0 acc). That's 3 more lines.

• We have 14 lines to work with, and we've used 2 x 3 + 4 x 2 + 3 = 17.



I cannot think of any way to cut out 3 lines of code in this. Barring some sort of conditional logic epiphany, or chat guy coming back and explaining themselves, I'm calling this project done. Finished. Finito. ¥7 version it is.




For all that I spent spinning my wheels at the end there, the finished product looks pretty cool.



Anyway, MC assembly sucks and I have a headache. I'm gonna ask David what the popular drinks are in this part of China (and invite him to go get one.)

Ratoslov
Feb 15, 2012

Now prepare yourselves! You're the guests of honor at the Greatest Kung Fu Cannibal BBQ Ever!

I've heard good things about baijiu.

Okay, well, I've heard things about baijiu.

Aesculus
Mar 22, 2013

Quackles posted:

Anyway, the dumpling shop turned out to be a dumpling stall, actually. The vendor guy was also selling (imitation?) shark fin soup, too (we never got whether it was real shark or not made clear). Everything was delicious.
5 stars, would eat there again.

I hope your stomach is okay :ohdear:

Regarding the lightup signs, it might be possible with SPOILER instructions and a DX300 to get it down to ¥6 but I haven't tried.
Also fun fact: The characters on the sign (literally "add oil") is a chant/cheer that roughly works out as "Harder!" or "Faster!" or "More!" depending on context. I guess these signs are supposed to help fans cheer her on during a game?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
I managed to save one line on your proposed solution by combining the "is it time to reset the accumulator?" check with one of the other tests, but saving any more seems like it might require some new hardware, or perhaps discovering something new about the hardware you currently have available...

Omobono
Feb 19, 2013

That's it! No more hiding in tomato crates! It's time to show that idiota Germany how a real nation fights!

For pasta~! CHARGE!

I've managed to fit everything in 14 lines
8 lines for the drinking loop, 5 lines for the clicking loop, one slp instruction at the end.

E: although I think one of the instructions I used wasn't shown yet.

Suggestions:
I'm fairly sure you need the ACC register for the drink, but the DAT suffices for the click.
The light-up sign has a loop long exactly 10 cycles.
If you send two values before the slp instructions only the last one counts.
Why are you checking for all four cases?

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
This is the kind of thing where I'd usually look into using memory chips. Like, you could represent the DRINK animation as 100, 010, 001, 010, 100, etc. Feed that to a digital I/O splitter and you're done...except that without an MC in the circuit there's no clock, so your animation would be crazy fast. Also the memory chip stores an irritating 14 values, while our animation sequence has a period of 4 values, so there's two values you'd have to skip somehow.

Hell, the period of the entire pattern (click + drink) is 10. You could allocate 1 digit to the click animations with a NOT gate to cycle them, one digit for drink-0, and one digit for drink-2. But you'd need some fairly complex conditionals to convert everything.

Quackles
Aug 11, 2018

Pixels of Light.


Holy Crap, It Works!

Omobono posted:

I've managed to fit everything in 14 lines
8 lines for the drinking loop, 5 lines for the clicking loop, one slp instruction at the end.

Suggestions:
I'm fairly sure you need the ACC register for the drink, but the DAT suffices for the click.
The light-up sign has a loop long exactly 10 cycles.
If you send two values before the slp instructions only the last one counts.
Why are you checking for all four cases?

THANK YOU! All four of those suggestions helped me solve it. I was able to create a ¥6 version.





Here's what's going on in all of this:

acc is still a counter, but it goes from 0 to 9 now instead of 0 to 4, and turns over every time unit instead of every 2 time units.

The first six lines manage the drink outputs. Normally, 001 (drink-0) is pushed to the expander (no tests passed - default case). However, if acc is 6 or more, 010 (drink-1) is pushed there instead and we run another test - in the final test, if acc is 7 or 8, 100 (drink-2) is pushed to overwrite the other values.

The next five lines handle the click outputs. dat is used to store 100 or 0, and the three lines in between the two mov dat p# instructions invert it. By putting it in between the two output lines, you can get the value and its inverse output in the same cycle without having to use a not gate.

Finally, add 1 increments the accumulator, but the fact that the cycle is exactly 10 time units lets me be clever. dgt 0 removes all but the last digit of the value of the accumulator - which is basically saying that it takes the accumulator modulo 10. If the accumulator is 0-9, nothing happens. If it's 10, it goes down to 0 again.

And then we have the obligatory slp.

This exercise has helped me think in assembly better. Thank you again!


P.S: A few fun facts and misc. comments:

• The new design uses about 3x as much power as the old one (496 units vs. 171 units for the ¥7 version), but replacement batteries are the fans' problem...

TooMuchAbstraction posted:

This is the kind of thing where I'd usually look into using memory chips. [...] Feed that to a digital I/O splitter and you're done...except that without an MC in the circuit there's no clock, so your animation would be crazy fast.

@TooMuchAbstraction - Good idea, but memory chips don't output automatically. There's gotta be a MC in there somewhere to pull the data. And, like you said, clock speeds.


Aesculus posted:

I hope your stomach is okay :ohdear:

🤔 What? I'm fine.

Aesculus posted:

Also fun fact: The characters on the sign (literally "add oil") is a chant/cheer that roughly works out as "Harder!" or "Faster!" or "More!" depending on context. I guess these signs are supposed to help fans cheer her on during a game?

@Aesculus - That makes sense. Maybe it's got something to do with the name of her sponsored sports drink, whatever it is.

Carbon dioxide
Oct 9, 2012

I get RSI from looking at that animated sign.

OAquinas
Jan 27, 2008

Biden has sat immobile on the Iron Throne of America. He is the Master of Malarkey by the will of the gods, and master of a million votes by the might of his inexhaustible calamari.
That "send two values only last one counts" just tripped me up--very sneaky and/or clever use of that. I was wondering how you got that second drink-1 peak without a solid line of drink-1 or another conditional, then I read that line and it clicked.

Quackles
Aug 11, 2018

Pixels of Light.


Bring Out the Baron!

It looks like me and David weren't the only ones at a bar last night! Joe's been having some success at his job - now it's my turn to make these... drinking game thingies.
(Joe seems to favor entertainment industry or entertainment-adjacent contracts from what I've seen of him so far. I looked up Baron von Schnapps and they're a... they market as a 'hip' sort of brand. Young people with perfect hair holding cocktail glasses, buncha commercials on Youku Tudou*... the works.)

*"Youku Tudou" = think YouTube, but Chinese.







There's no obvious design issues that come to mind just from looking at the board. There's two simple inputs and one XBus output (the display), so probably one MC4000 should be enough to drive it - as long as there's enough space in the code (there probably is). I'll make a prototype and see how things go.

[ ~ ]





Good news and bad news. Good news: This design works, and works really well. It's cheap (¥3 + the display), and reasonably efficient (268 power drawn per run on average).
The code is straightforward: if the point button is pressed, it adds 1 to the counter (the accumulator). If the foul button is pressed, it subtracts 2. If the counter is below 0, it sets it to 0. It updates the display and then sleeps.

Now for the bad news. Joe forwarded on an email from Team Baron (that's what the brand group calls themselves - very catchy) regarding additional specifications for the design. They want the device to go as low-power as possible. Something about “a long-lasting quality” or “a long-lasting buzz” being a planned slogan.

Before I dive into trying to rework my design, I want to make clear why this is probably a bad idea for them:
(1) This sounds like a complete stretch.
(2) Based on the simulation, it looks like your garden-variety button battery could power this thing uninterrupted for a solid day, already - so no one will notice the difference.
and, (3), this will almost certainly increase the price.

The way this'll probably end is with the balanced version and the low-power version being quoted to Team Baron - then they'll get to pick which design actually goes to the factory.

So, now for the interesting question. How do you optimize a design for low power usage?
It turns out that my simulator has a profiler built in. It's a software feature that tracks how often any given expression is run during a test of a chip. This is the profile for the existing design after a test run:



The yellow bar shows how often each instruction was used in the sim. It's really obvious which instructions were running all the time - the two tests and the instruction that updates the display. Next step: trying to figure out a way to cut down on how many instructions are used. Two possibilities come to mind:

(1) What if the first test checked if any button was being pushed, and the second test checked which? This way, the second test could be skipped if the first one comes up empty.
The catch with this is that you can't just wire both buttons into one pin - I'd have to add an OR gate or something to be able to test both signals at once.

(2) What if the display is only updated when the counter is? This one kind of feeds into (1), but the display update instruction currently runs every time the chip cycles. Cutting it out would be a really easy way to save some energy.

Will report back when I have something.

[ ~ ~ ]





This is my attempt at putting in both of the improvements I listed above. It's not perfect, but I think it's a step in the right direction (235 avg. power used vs. the old design's 268).

I did end up putting in an OR gate, so p1 (first pin tested) is now on if either button is pushed. I couldn't find a way to get the conditional flags to line up so that the 'display' instruction only runs if a button was pushed, so I ended up just having the no-button-pushed path jump to the end.
(It turns out you can put labels on the same line as an instruction.)

The new design only lets me test for [some button pressed] or [foul button pressed], so I always add 1 to the counter if a button's been pushed (most of the time, the button pressed 'll be "point" so this is more efficient as a default). If the foul button is pressed (testing p0), it then subtracts 3 ( acc + 1 - 3 = acc - 2) and then tests that the counter didn't go below 0. Then it displays.

It's a good design, but I do feel that it's not as efficient as it could be. "acc + 1 - 3 " is not the smoothest way to subtract 2 from something. On top of that... with the original design, at least three powered instructions** would run every time unit (the two tests and the display update). With this design, at least two will run every time unit (the first test and either the jump or the counter math).

The new design is more efficient, but it feels like a really smooth-running design would just have a single powered instruction (the first test), and nothing else if it turns out no buttons are being pressed. It feels like you'd need some sort of three-way test to pull it off, though - one branch for the point button, one branch for the foul button, and one branch for nothing.

I'll keep working at it, but any improvements would probably have to come from building a new design, rather than incrementally improving this one. I have a feeling.

**(slp is an instruction, but it doesn't consume any power.)


[ ~ ~ ~ ]





I owe Carl a favor.

Remember how back when I was talking about conditional execution I mentioned that tcp was a special three-way branching test? Well, Carl showed me a design pattern that looks to be really, really useful for dealing with multiple inputs. It's all based on how an input expander works. (Datasheet back here)

Basically: an input expander takes three simple I/Os and gives you a three-digit number. Each digit is either 0 or 1, and corresponds to whether the simple I/O pin associated with the digit is ON or OFF. The secret is: the three-digit number is also... a number. And with tcp, you can find out if a number is greater, lesser, or exactly the same compared to a reference value.

Carl pointed out that, as I'd noted above, my program had 3 'paths':

• One path ( + in this version) for the 'foul' button.
• One path ( – in this version) for the 'point' button. The 'foul' button path also falls onto this path if the counter isn't below 0 (the instruction that resets the counter to 0 can't be a '–' instruction 'cause then you'd 'fall through' to it after an addition and reset the counter— so it has to be a '+' instruction and the below-0 test shunts onto the '–' path when things are normal).
• One path (+/– turned off) for when neither button is pushed.

So, if I wanted to use tcp to split execution three ways, it means that the expander's output value for "foul button pushed" would have to to be greater than the value output for "nothing's happening" (which has to go in the middle for tcp to turn off + and –), which should be greater than the output value for "point button pushed".

This is where the NOT gate comes in, feeding the expander ON when the point button is OFF. The resulting possible input states look like this:

• Point button pushed = (blank)-OFF-OFF to expander = 0
• Neither button pushed = (blank)-OFF-ON to expander = 1
• Foul button pushed = (blank)-ON-ON to expander = 11



So, you do the tcp of the expander value with 1.
If it's 0, then it's less than 1, you get , you know the point button has been pushed, and you add and update the display.
If it's 11, then it's greater than 1, you get +, you know the foul button is pushed, and you subtract, test for below-0, and update the display.
If it's 1 exactly, then neither button is on, + and are both off, and you fall through to the only other instruction that doesn't have a conditional flag, which is the slp.

And that's how it works.

[ ~ ~ ~ ~ ]

We ended up giving Team Baron a choice between all three options:

• My first design: ¥3 - 268 power
• My second design: ¥4 - 235 power (88% of the original)
• Carl's design: ¥5 - 170 power (63% of the original)

Guess which quote they picked?

Yup. The ¥3 version. Once again, replacement batteries are the fans' problem.



On the bright side, they did send over a lovely thank-you gift! Off to try some now.


P.S.: When me and David were out last night, the most popular drink was beer. David got some sort of rice wine he called huangjiu - and the brand he got came in an honest-to-god clay pot!! The picture below is not David's drink - I didn't have the presence of mind to take a photo - and is instead from the Internet.



The jars in the pic are apparently for aging the stuff, so getting your drink brought to you in a miniature one feels kind of like receiving a shot of fine whiskey in a shot-glass-size oaken barrel. Go figure...!

Quackles fucked around with this message at 11:19 on Aug 21, 2018

Aesculus
Mar 22, 2013

Be glad you don't have to optimize for clock cycles on variable size inputs :smithicide:

whitehelm
Apr 20, 2008

You don't need the expander for this, just hook up foul and point to p0 and p1 directly, then change the first line to "tcp p0 p1". Same three branches, no expensive extra chips.

sincx
Jul 13, 2012

furiously masturbating to anime titties
This LP is extremely relevant to my current circumstances and I am subscribing to your newsletter.

Only registered members can see post attachments!

Quackles
Aug 11, 2018

Pixels of Light.


Shenzhen Days: Saying Stuff Better



Tilly's checked in again. This episode has helped sort out a few things I kinda wondered about. Like the ¥ thing. The first time I saw that in my simulator, I was like, "wait, the region for this isn't set to Japan, is it?" (It was not.)
I almost even made a remark about it in one of my earlier posts - the Light-Up Signs one, I think - but it got dropped during a rewrite.

Also, I realize this might make me look a little bit ignorant, but one thing I did not know until I read this is that Hong Kong has its own currency. (I had thought it used the Yuan, but I guess not... it's almost certainly a history-related thing.) It's really interesting!

So, to summarize: y'all might think ¥ is only for yen, but right, y'aint. XD

Anyway, reader comments time.

whitehelm posted:

You don't need the expander for this, just hook up foul and point to p0 and p1 directly, then change the first line to "tcp p0 p1". Same three branches, no expensive extra chips.

Oof. How did we miss this?
This is one of the things that makes this job hard, actually - it's easy to optimize for just one metric (such as power), but hard to do it for two at once (like power and cost) - because it's not always easy to see when you've done all you can vs. when more is possible.


sincx posted:

This LP is extremely relevant to my current circumstances and I am subscribing to your newsletter.



Congratulations on your trip! I'm rooting for you, whatever you end up doing.

Quackles
Aug 11, 2018

Pixels of Light.


Rubbish Audio Thing



Before I say anything else, you should probably look at the spec. And the ad.







So. That's the HARMONIC MAXIMIZATION ALGORITHM. Let me be perfectly clear, based on this formula, what this thing does. It doesn’t care about the actual frequency (pitch) of the sound at all. It does only one thing:
If the sound is soft, or not too loud, it does almost nothing. But if the sound is sufficiently loud, the device makes it louder. The only difference is the increased contrast between softer sounds, and louder sounds. That is literally it. The device doesn’t do anything else.
(To be fair, though, the promoters are at least using the word 'maximization' correctly.)

Anyway, let's get to work. The first half of Carl's favor is him not having anything to do with the construction of this.

[ ~ ]





There was a grand total of one design issue with the device: all three inputs/outputs are simple I/O and there's only two simple I/O pins on a MC. This is fixable, though - since the maximize button is an on-off switch, an output expander can work as a handy simple-to-XBus converter. Aside from that, it's just a matter of turning the HARMONIC MAXIMIZATION ALGORITHM into code.

[ ~ ~ ]

Bonus: After the Baron incident (thanks @whitehelm 😅), I've decided to challenge myself and make optimized versions of my designs if I have a bit of spare time. In this case, I decided to try to write a version of the MC with as few lines of code as possible.



The revised version has the same wiring as the original, but two changes to the code:

(1) In the first version, the MC would move the audio sample to audio-out with a stop at acc if maximize was on, but move it directly out if maximize was off. This took 3 lines for the two different versions of the 'move' code.
This version always moves the sample into acc first, using only the same two lines of code to move it around.

(2) I did a bit of algebra on the HARMONIC MAXIMIZATION ALGORITHM.
(audio_in - 50) x 4 + 50 = audio_in x 4 - 50 x 4 + 50 = audio_in x 4 - 200 + 50 = audio_in x 4 - 150.
It's the same formula, but it only uses two math instructions instead of three.

That's as optimized (for lines of code) as you can get, I think. It turns out, by the way, that the revised version is slightly more power-efficient on average than the original, probably because of (2).
Time to send the design off.



...
I felt sorry for Joe when he got the Solitaire game taken off his work tablet.
I don't feel as sorry about what happened to his speakers, for some reason.

KirbyKhan
Mar 20, 2009



Soiled Meat
Joe is the best.

Ratoslov
Feb 15, 2012

Now prepare yourselves! You're the guests of honor at the Greatest Kung Fu Cannibal BBQ Ever!

This is kind of a terrible puzzle, but as a bit of comedy it's top-notch.

Adbot
ADBOT LOVES YOU

The_White_Crane
May 10, 2008

Quackles posted:

Shenzhen Days: Saying Stuff Better

The best advice I heard for an English speaker emulating a Chinese "zh" was to use the sound that is in the middle of "pleasure" or "leisure". Though I expect that depends on what your particular dialect of English is.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply