What's next after scrypt? I have been reading about the LiteCoin, and how it uses a hashing function (scrypt) that is not able to be mined by ASICs.  As a side-effect of this, it has been said that people with GPUs will move to Litecoin, as the ASICs take over bitcoin mining.  I'm wondering, are there any hashing functions that are resistant to GPUs as well as ASICs?  It would be nice to have a crypto-currency based on those, so I could use my CPU to do mining, without having to buy an expensive graphics card to keep up.
Let me describe when a hash function can (not) be calculated efficiently by using ASICs or GPUs:

ASICs: I'm speaking of simple in design, cheap ASICs, because in theory you can design an ASIC for every digital function. Simple ASICs are mostly designed for linear workflows. So they do not use loops (or loops with a hardcoded count), no recursion and a very limited memory requirements and local memory access (payload size is known). So the designer has to know the exact digital formulas. Imagine them as a calculator for mathematics terms (no jumps, every input/output as variable).

GPUs: They are good when it comes to small functions which are executed very often and having medium memory usage. Recursion doesn't work very well and complex, non-parallelized functions aren't handled in an efficient way.

So if you want to design a hash function that doesn't work well on either of them, use a complex function with high random memory access. Also make sure that the hash function does not contain parallel small parts (good for GPUs). Use data dependencies to ensure this. Please consider that it is always possible to build better more expensive ASICs for every function. So it's about cheap ASIC development VS complexity of the hash function.

Explanation of some used therms:


Complexity: doesn't mean theoretical complexity Here it's about the length of the description, the number of function calls / jumps and dynamic behavior (non hardcoded loop counts / memory requirements)
Recursion: a function calls itself one or multiple times, so a stack structure is required.
Data dependency: To calculate the next subresult (e.g. when using loops), you need the previous subresult (e.g. from the last loop body execution).