Wednesday, December 26, 2007

本日下午茶 : Irish Coffee DIY

DSCI0001.JPG

愛爾蘭咖啡的特色就是烤杯。烤杯的目的在於把烈酒裡面的酒精成分揮發掉,留下酒香的精華,所以基本上愛爾蘭咖啡是沒有很濃的酒味的,今天下午我來試做看看吧。我選用的基底是瓜地馬拉的花神+Brikka做出來的偽Espresso,其實花神不太適合作成這種混合口味的咖啡,不過手上只剩下這個就試試看吧=P。

DSCI0002.JPG

正統Irish理論上是該用鮮奶油的,不過手邊哪可能沒事情就生罐鮮奶油出來?所以用打泡杯打出奶泡來代替。首先先將杯子裡面放入適當的糖(我是用Bajans焦糖,不過這種感覺上不太好,下次換一種品牌),然後混入大約0.5oz的酒。我用的基底酒是Johnnie Walker, 42.5Vol%。普通來講要做IRISH的話通常基底酒濃度至少要40%以上,不然會燒不起來。

DSCI0003.JPG

我只有一隻手沒辦法邊烤邊拍照。基本上烤杯是先一邊旋轉一邊烤下緣,然後等白色蒸氣大量冒出的時候把火移到杯口點火。DSCI0004.JPG

雖然不明顯,不過看到杯子裡面小小的藍色火光了嗎?在杯內燃燒的時候要一直旋轉晃動杯子,這樣才能維持燃燒需要的酒精蒸氣。等到燒完了,杯子裡面的酒精也應該揮發的差不多了,火就會停了。

DSCI0005.JPG

看起來基底咖啡已經煮好了。其實這次試驗出來感覺Brikka不是很適合煮基底,也許該換個方法來避免太重的苦澀味。Johnnie Walker本身就已經有澀味了,加上這種基底可能會有點太重。

DSCI0006.JPG

最後把基底分層,打上奶泡跟牛奶分層,今天下午茶愛爾蘭咖啡就完工了。基本上弄一份這種東西大約要十分鐘左右,成本還不算高,有興趣的可以自己試試看喔。

Monday, September 10, 2007

ACM換新家了

http://icpcres.ecs.baylor.edu/onlinejudge/
不過看起來server挺不穩的 -_-

還在摸索從哪裡submit code....

Tuesday, May 08, 2007

ACM101-The Blocks Problem

Level : 35/100
Concept : Basic Data Structure, Link List Theory, and.... clear mind.
Noticeable Point :
  1. Some complex and reusable code can be extracted as a inline function.
  2. Modularize helps a lot.
Method :
  • Main concept of this solution is not hard. First, we make a structure of each block with these elements :
    1. box* uplink and box* downlink, these two pointer points to upper and lower block in the pile. If uplink == NULL means it is the top of the pile. If downlink == NULL means it is the lowest block in the pile, or alone, and IT STAND ON THE ORIGINAL PLACE.
    2. static int BoxID. This indicates where the original place is, and the number of the block. In fact, by the problem saying, if a block.downlink = NULL, it MUST on its original place, as BoxID.
    3. Constructor and Destructor, which are supposed to control BoxID.
  • Define the function respectively. For example, we can draw a blueprint of procedure that "Move Over" does. First, we find that it need a function to clear all boxes above target, so we must make a clearup(). The procedure is simple, clearup() both target and destination, move target to the top of destination. Then, we must make clearup(), how it does? we find that we need a function to get the top box's position, so we must make a box* gettop(). Do this again and again we will get every function ready. In my works, I have made MoveOnto(), MoveOver(), PileOnto(), PileOver(), gettop(), clearup().
  • Then assemble these components up. It is not very easy to debug, we must do a hard labor to make sure these works fine. Then, output module seems not complex, do it and debut this patiently... yes you will need lots of patient.

ACM100-The 3n+1 Problem

Level : 12/100
Concept : None
Noticeable Points :

  1. Output order must be same to input order
  2. swap is NOT default function of GCC
Method : Brute, anyway :)

The 3n+1 problem

Traditional Chinese Version(Lucky's ACM)

Tuesday, March 20, 2007

Be aware NULL point access violation!

A typical error message such like "Can't write in 0x00000000, access violated.", and mostly be seen with 0x00000000. It is meaningful, and often point to wrong coding habits.

It is very common to distinguish if a new was successfully deploy a memory for a pointer by its return value. As usual, new will return a pointer pointing to a allocated memory which is successfully initialized and ready to be used. If new failed to deploy the memory, it will return NULL back to the pointer. So it is reliable to code in such way :

if(!(ptr = new foo[n]))
ReportErrorAndTerminate("Fail of memory deploying!");

In fact, if we added if to EVERY new, everything will go all right -- except annoying coding style and full of padding code. In old style C, LongJmp/SetJmp had been used in this case. In modern C++, that is catch&try method.

try{
ptr = new foo[n];
ptr2 = new foo2[n];
...
...
}

catch(std::bad_alloc)
{
...
... //necessary process
...
}

catch(...)
{
...
...//catch unknown exceptions
...
}

That's the way how try and catch works. OK, lets recall the topic, why this error message occurs? It is because of bad coding habit and misunderstanding the process of full program. For example, if we forget add if over new :

ptr = new foo[n];

when new returns NULL(means fail to deploy memory), then any operation to the memory that ptr refers :

*ptr = foo("This thing!");

It will occur NULL pointer access violation, and pop-up an error message box with "0x00000000".

In fact, not only new but all pointer-associated operator will return NULL when operating encounters failure -- even most of coder will make this behavior as default. Use try and catch to avoid such case.


Monday, January 01, 2007

Usage of auto_ptr, and about Proxy Class technique

This example is incorrect

auto_ptr <char>pChar;
pChar.reset(new char[20]);

In fact, the standard version of auto_ptr can not handle the pointer with array, because when the auto_ptr destructed, it express "delete something" rather then "delete[] something". I think anyone who slightly understand what different of delete and delete[] will point out it will cause memory leak. But how can we enjoy the convenience of auto_ptr, and use array correctly?

There is a trick(technique?) called "proxy class technique". What proxy class stand for? If we need to operate on something, but the operation is not compatible on this, we can make a class to "warp up" this object, and make it compatible to the operation. For example, since auto_ptr is not suitable for a pointer with array, why not we just wrap this pointer up?

struct proxychar
{
char* target; //this is the object.
proxychar(int n){target = new char[n];}
~proxychar(){delete[] target;}
};

auto_ptr<proxychar> pPC;
pPC.reset(new proxychar(20) );

pPC->target[0] = 'H';
pPC->target[1] = 'i';
pPC->target[2] = '\0';
cout << pPC->target;

Ok, it seems working fine. When pPC is being destroyed, it will call up the destructor of proxychar, and it will delete[] target.

This is a application of proxy class technique, and this technique have other use. In this case, this trick plays well =').