Testing Concurrent Programs

Writing correct concurrent programs is harder than writing sequential ones. This is because the set of potential risks and failure modes is larger – anything that can go wrong in a sequential program can also go wrong in a concurrent one, and with concurrency comes additional hazards not present in sequential programs such as race conditions, data races, deadlocks, missed signals, and livelock.


Testing concurrent programs is also harder than testing sequential ones. This is trivially true: tests for concurrent programs are themselves concurrent programs. But it is also true for another reason: the failure modes of concurrent programs are less predictable and repeatable than for sequential programs. Failures in sequential programs are deterministic; if a sequential program fails with a given set of inputs and initial state, it will fail every time. Failures in concurrent programs, on the other hand, tend to be rare probabilistic events.


Because of this, reproducing failures in concurrent programs can be maddeningly difficult. Not only might the failure be rare, and therefore not manifest itself frequently, but it might not occur at all in certain platform configurations, so that bug that happens daily at your customer’s site might never happen at all in your test lab. Further, attempts to debug or monitor the program can introduce timing or synchronization artifacts that prevents the bug from appearing at all. As in Heisenberg’s uncertainty principle, observing the state of the system may in fact change it.


So, given all this depressing news, how are we supposed to ensure that concurrent programs work properly? The same way we manage complexity in any other engineering endeavor – attempt to isolate the complexity.


Structuring programs to limit concurrent interactions


It is possible to write functioning programs entirely with public, static variables. Mind you, it’s not a good idea, but it can be done – it’s just harder, and more fragile. The value of encapsulation is that it makes it possible to analyze the behavior of a portion of a program without having to review the code for the entire program.


Similarly, by encapsulating concurrent interactions in a few places, such as workflow managers, resource pools, work queues, and other concurrent objects, it becomes simpler to analyze and test concurrent programs. Once the concurrent interactions are encapsulated, you can focus the majority of your testing efforts primarily on the concurrency mechanisms themselves.


Concurrency mechanisms, such as shared work queues, often act as conduits for moving objects from one thread to another. These mechanisms contain sufficient synchronization to protect the integrity of their internal data structures, but the objects being passed in and out belong to the application, not the work queue, and the application is responsible for the thread-safety of these objects. You can make these domain objects thread-safe (making them immutable is often the easiest and most reliable way to do so), but there is often another option: make them effectively immutability.


Effectively immutable objects are those which are not necessarily immutable by design – they may have mutable state – but which the program treats as if they were immutable after they are published where they might be accessed by other threads. In other words, once you put a mutable object into a shared data structure, where other threads might then have access to it, make sure that it is not modified again by any thread. The judicious use of Immutability and effective immutability limit the range of potentially incorrect concurrent actions by limiting mutability to a few core classes that can be strenuously unit-tested.


Listing 1 shows an example of how effective immutability can greatly simplify testing. The client code submits a request to a work manager, in this case an Executor, to factor a large number. The calculation is represented as a Callable<BigInteger[]>, and the Executor returns a Future<BigInteger[]> representing the calculation. The client code then waits on the Future for the result.


The FactorTask class is immutable, and therefore thread-safe, so no additional testing is required to prevent unwanted concurrent interactions. But FactorTask returns an array, and arrays are mutable. Shared mutable state needs to be guarded with synchronization, but because the application code is structured so that once the array of BigIntegers is returned by the FactorTask its contents are never modified, the client and task code can “piggyback” on the synchronization implicit in the Executor framework and do not need to provide additional synchronization when accessing the array of factors. If it were possible that any thread might modify the contents of the array of factors after it was created, this technique would not work.


    ExecutorService exec = …
class FactorTask implements Callable<BigInteger[]> {
private final BigInteger number;

public FactorTask(BigInteger number) {
this.number = number;
}

public BigInteger[] call() throws Exception {
return factorNumber(number);
}
}

Future<BigInteger[]> future = exec.submit(new FactorTask(number));
// do some stuff
BigInteger[] factors = future.get();



This technique can be combined with nearly all the concurrency mechanisms in the class library, including Executor, BlockingQueue, and ConcurrentMap – by only passing effectively immutable objects to these facilities (and returning effectively immutable objects from callbacks), you can avoid much of the complexity of creating and testing thread-safe classes.


Testing concurrent building blocks


Once you’ve isolated concurrent interactions to a handful of components, you can focus your testing efforts on those components. Since testing concurrent code is difficult, you should expect to spend more time designing and executing concurrent tests than you do for sequential ones.


The factors below are some of the concepts to consider when designing and running tests for concurrent classes. They, as well as others, are covered in much greater detail in the Testing chapter of Java Concurrency in Practice.



  • Tests are probabilistic. Because the failures you are searching for are probabilistic ones, your test cases are (at best) probabilistic as well. To give yourself the maximum chance of running across the right conditions to trigger a failure, you should plan to run concurrent tests for much longer.

  • Explore more of the state space. Running tests for a longer time is not going to find the problem if you are simply retrying the same inputs and the same initial state over and over again. You want to explore more of the state space, which with concurrent programs, includes temporal considerations as well. For example, if testing insertion and removal in a queue, you’ll want to explore all the relative timings and orderings with which the two operations might be initiated.

  • Explore more interleavings. The scheduler may preempt a thread at any time, but most of the time short synchronized blocks will run to completion without preemption. This limits the likelihood that race conditions will be disclosed, as other (potentially undersynchronized) code is less likely to run while another thread is in the middle of a synchronized block. Tools like ConTest can randomly introduce yield() calls into synchronized blocks to explore more possible interleavings.

  • Match thread count to the platform. If you run as many threads as you have processors, threads will never be preempted by the scheduler, reducing the number of potential interactions between active and waiting threads. Similarly, if you run many more threads than you have processors, you reduce the number of potential interactions between active threads. Tailoring thread count so that the number of runnable threads at any time is a small multiple of the processor count will often result in a more interesting variety of interleavings.

  • Avoid introducing timing or synchronization artifacts. Tests for concurrent data structures often involve having some threads inserting elements while other threads remove them, and asserting things like “everything that went in came out”, “nothing that didn’t go in came out”, and “everything came out in the right order.” The obvious way to code such tests involves maintaining data structures shared across the test threads, which will themselves require synchronization. But if the test program does its own synchronization, it may perturb the timing or scheduling with which the component being tested runs, masking potential negative interactions.

All this sounds like a lot of work, and it is. But by limiting the scope of concurrent interactions to a few widely-used, well-tested components, you greatly reduce the amount of effort required to test an application. And, by reusing existing tested library components, such as the classes in the java.util.concurrent package, you further reduce your testing burden.


Evan Almighty 王牌天神

Evan Almighty 王牌天神

軟體:Evan Almighty(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

這是一款動作遊戲,遊戲的目標是將畫面中所有的動物都順利送至方舟中,只要玩家接觸到動物,便能將其舉起,此時如果靠近畫面右側的梯子就可以將動物順利送入方舟中。

遊戲中玩家的動作要快,因為大洪水會從底層升起,如果動作不快就會被洪水淹沒。另外還要小心跑來跑去的議員或記者,如果不小心碰觸到可是會扣一點紅心值的。玩家可以藉由跳躍來躲避他們的追趕。遊戲中玩家可以直接跳躍到上層的平台,但是無法直接下降到低層的平台,必須找尋平台的左右兩端才能下去,這常常會浪費許多時間,玩家要特別注意。遊戲中會不定時不定點出現一些物品,玩家取得後可以增加積分。



遊戲操控說明:
1.利用方向鍵中的左右鍵移動主角。
2.方向鍵中的上鍵可以進行跳躍。

下載:http://www.miniclip.com/games/evan-almighty/es/

Blobular 奇特的橘色生物

Blobular 奇特的橘色生物

軟體:Blobular(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家必須在每一個關卡中,收集所有的蔬菜或水果,例如香菇、蘋果或西瓜等等,收集完畢後才能順利過關,並且可以挑戰更艱難的下一關。玩家要注意在每一個關卡當中,都是有時間限制的喔!因此玩家收集蔬菜或水果的速度一定要加快!另外遊戲中有些地方比較狹窄,玩家可以讓體型變大的主角分裂成數個較小的型態,來順利通過狹隘的地方。



有時玩家會覺得不知道目前所在關卡何處,或是不瞭解那邊還有要收集的蔬菜或水果,此時可以利用滑鼠左鍵點擊畫面下方的「Map」,如此可以看到整個關卡的全景以及所有的物品。遊戲裏玩家要注意有些地上的尖刺,或者空中帶刺的圓盤等等,不能碰觸到它們。另外遊戲中會出現一些寶物,例如玩家如能取得鬧鐘的圖示,則可以延長限制的時間,這是幫助玩家過關的好用寶物。



遊戲操控說明:
1.利用方向鍵中的左右鍵移動主角。
2.方向鍵中的上鍵可以跳躍,下鍵可以擠過稍微窄的地方。
3.按A鍵可以讓身體便大的主角分裂成數個小顆的,S鍵可以組合成原狀。

下載:http://www.freeworldgroup.com/games6/gameindex/blobular.htm

Danger Girl 具危險性的女孩

Danger Girl 具危險性的女孩

軟體:Danger Girl(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家必須在每一個關卡中,擊退所有的外星人才能過關,並且可以挑戰更艱難的下一個關卡。玩家將可以利用女孩身邊的球,將球丟向外星人所駕駛的飛碟,有些飛碟要被球擊中數次才會掉落。飛碟掉落時記得要躲開,以免被撞及而扣生命值,另外飛碟掉落後會有金幣出現,或者有一些水果、醫藥箱,拾取金幣可以增加積分,水果和醫藥箱則可以補充生命值。

遊戲中敵人會從天空中射擊子彈,玩家必須及時躲開,才能避免遭受攻擊。除了一般敵人之外,還會有大頭目登場喔!這些大頭目的武器非常精良,玩家要小心避開,再利用時機對他們加以攻擊。遊戲操控方面,利用滑鼠移動可以控制女主角行動,按滑鼠左鍵不放開會出現瞄準游標,玩家可用來瞄準要攻擊的方向,放開左鍵後便可將球丟出。另外在沒有拿球時,按滑鼠左鍵可以跳躍,躲避敵人的攻擊。



下載:http://www.gamesheep.com/game/danger-girl/index.php?act=PlayNow

Death Village 鬼屋

Death Village 鬼屋

軟體:Death Village(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家必須引導主角到達出口處的大門,如此才能順利過關。遊戲有一個特點,就是畫面會隨著玩家滑鼠游標的移動來自動拉遠拉近,讓遊戲畫面更有變化性。遊戲的每一個關卡可是有時間限制的,因此玩家動作要快,才能夠順利過關。

遊戲中玩家並無法直接操控主角移動,而是要利用周邊的物品、鬼魂或木乃伊等等來引導他走入正確的路徑。例如玩家可以拉開門讓主角走入不同房間,可以按樓梯讓階梯暫時消失不讓主角爬上樓梯,又或者可以敲窗戶以及敲棺木讓鬼魂及木乃伊現身。不過玩家要注意一點,可以讓鬼魂驚嚇主角,但是不能讓他直接碰觸到,否則驚嚇過度遊戲就會結束。



遊戲操控方面,利用滑鼠左鍵點擊適當的位置既可。畫面中玩家的滑鼠移動時,會有一個白色手套跟著移動,當手套呈現敲打或緊握的狀態時,表示這個地方可以有動作發生。

下載:http://nigoro.jp/game/deathvillage/deathvillage.html

Super B B超人

Super B B超人

軟體:Super B(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家必須注意每關前面的說明指示,如此才能順利依照指示來達成任務而順利過關。畫面右上角會有一個線條與帶B字的圖示,B字會由左到右移動,這是代表由起點出發,而B字到最右邊時則抵達終點。在這期間玩家會遭遇到許多敵人與障礙物,玩家可以利用B超人的攻擊力量將其摧毀,如果來不及擊倒就必須趕緊躲避,以免降低生命值。

遊戲中會有一些救人質的任務,玩家除了要小心敵人的攻擊之外,還要注意關卡規定救人質的數量,一定要超過此數量否則既使超人抵達終點也不能過關。另外還要注意不要隨意攻擊,把人質都給殺光了。遊戲中提供了一些武器的升級或者暫時性的防護能力,玩家可以利用在關卡中賺取的積分來購買這些升級超人的能力,如此才能夠對抗愈來愈強大的敵人。



遊戲操控方面,利用四個方向鍵移動主角,滑鼠游標可以操控超人攻擊瞄準的地方,按左鍵可以進行攻擊。

下載:http://www.freeworldgroup.com/games6/gameindex/super-b.htm

Shield Defense 超級基地防護器

Shield Defense 超級基地防護器

軟體:Shield Defense(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家將會利用基地的防護檔板,將敵人發射的武器反彈回去,並藉此來攻擊敵人。一開始的敵人動作慢,所配備的武器也不精良,因此較好應付,但隨著遊戲的進行,敵人的數量與攻擊威力會隨之增加,移動速度也加快,玩家必須眼明手快,否則很難應付愈來愈困難的關卡。



遊戲中玩家可以利用擊毀敵人所賺取的金錢,用來購買各式不同提升武力或防禦力的武器,又或者修復基地等等,升級後玩家將有更強大的能力來對抗這些頑強的敵軍。一些特殊提升的能力相當好用,例如玩家如果購買了「Sticky Shield」之後,原本只有反彈敵方子彈的檔板,此時將具有黏住敵方一發子彈的能力,並且能隨時發射這一發子彈,如此發射方位玩家較好掌握,擊潰敵軍的效率也能大為提升。



遊戲操控方面,利用滑鼠移動來控制檔板移動,按左鍵可以發射被防護檔板所吸附的子彈(有購買才有作用。)

下載:

Summary of regular-expression constructs


Summary of regular-expression constructs































































































































































































































































































































Construct Matches
 
Characters
x The character x
\\ The backslash character
\0n The character with octal value 0n (0 <= n <= 7)
\0nn The character with octal value 0nn (0 <= n <= 7)
\0mnn The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7)
\xhh The character with hexadecimal value 0xhh
\uhhhh The character with hexadecimal value 0xhhhh
\t The tab character (‘\u0009’)
\n The newline (line feed) character (‘\u000A’)
\r The carriage-return character (‘\u000D’)
\f The form-feed character (‘\u000C’)
\a The alert (bell) character (‘\u0007’)
\e The escape character (‘\u001B’)
\cx The control character corresponding to x
 
Character classes
[abc] a, b, or c (simple class)
[^abc] Any character except a, b, or c (negation)
[a-zA-Z] a through z or A through Z, inclusive (range)
[a-d[m-p]] a through d, or m through p: [a-dm-p] (union)
[a-z&&[def]] d, e, or f (intersection)
[a-z&&[^bc]] a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]] a through z, and not m through p: [a-lq-z](subtraction)
 
Predefined character classes
. Any character (may or may not match line terminators)
\d A digit: [0-9]
\D A non-digit: [^0-9]
\s A whitespace character: [ \t\n\x0B\f\r]
\S A non-whitespace character: [^\s]
\w A word character: [a-zA-Z_0-9]
\W A non-word character: [^\w]
 
POSIX character classes (US-ASCII only)
\p{Lower} A lower-case alphabetic character: [a-z]
\p{Upper} An upper-case alphabetic character:[A-Z]
\p{ASCII} All ASCII:[\x00-\x7F]
\p{Alpha} An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit} A decimal digit: [0-9]
\p{Alnum} An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct} Punctuation: One of !”#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} A visible character: [\p{Alnum}\p{Punct}]
\p{Print} A printable character: [\p{Graph}]
\p{Blank} A space or a tab: [ \t]
\p{Cntrl} A control character: [\x00-\x1F\x7F]
\p{XDigit} A hexadecimal digit: [0-9a-fA-F]
\p{Space} A whitespace character: [ \t\n\x0B\f\r]
 
Classes for Unicode blocks and categories
\p{InGreek} A character in the Greek block (simple block)
\p{Lu} An uppercase letter (simple category)
\p{Sc} A currency symbol
\P{InGreek} Any character except one in the Greek block (negation)
[\p{L}&&[^\p{Lu}]]  Any letter except an uppercase letter (subtraction)
 
Boundary matchers
^ The beginning of a line
$ The end of a line
\b A word boundary
\B A non-word boundary
\A The beginning of the input
\G The end of the previous match
\Z The end of the input but for the final terminator, if any
\z The end of the input
 
Greedy quantifiers
X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{n} X, exactly n times
X{n,} X, at least n times
X{n,m} X, at least n but not more than m times
 
Reluctant quantifiers
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{n}? X, exactly n times
X{n,}? X, at least n times
X{n,m}? X, at least n but not more than m times
 
Possessive quantifiers
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{n}+ X, exactly n times
X{n,}+ X, at least n times
X{n,m}+ X, at least n but not more than m times
 
Logical operators
XY X followed by Y
X|Y Either X or Y
(X) X, as a capturing group
 
Back references
\n Whatever the nth capturing group matched
 
Quotation
\ Nothing, but quotes the following character
\Q Nothing, but quotes all characters until \E
\E Nothing, but ends quoting started by \Q
 
Special constructs (non-capturing)
(?:X) X, as a non-capturing group
(?idmsux-idmsux)  Nothing, but turns match flags on – off
(?idmsux-idmsux:X)   X, as a non-capturing group with the given flags on – off
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?<!X) X, via zero-width negative lookbehind
(?>X) X, as an independent, non-capturing group




Backslashes, escapes, and quoting


The backslash character (‘\’) serves to introduce escaped constructs, as defined in the table above, as well as to quote characters that otherwise would be interpreted as unescaped constructs. Thus the expression \\ matches a single backslash and \{ matches a left brace.

It is an error to use a backslash prior to any alphabetic character that does not denote an escaped construct; these are reserved for future extensions to the regular-expression language. A backslash may be used prior to a non-alphabetic character regardless of whether that character is part of an unescaped construct.

Backslashes within string literals in Java source code are interpreted as required by the Java Language Specification as either Unicode escapes or other character escapes. It is therefore necessary to double backslashes in string literals that represent regular expressions to protect them from interpretation by the Java bytecode compiler. The string literal “\b”, for example, matches a single backspace character when interpreted as a regular expression, while “\\b” matches a word boundary. The string literal “\(hello\)” is illegal and leads to a compile-time error; in order to match the string (hello) the string literal “\\(hello\\)” must be used.

Character Classes


Character classes may appear within other character classes, and may be composed by the union operator (implicit) and the intersection operator (&&). The union operator denotes a class that contains every character that is in at least one of its operand classes. The intersection operator denotes a class that contains every character that is in both of its operand classes.

The precedence of character-class operators is as follows, from highest to lowest:























1     Literal escape     \x
2     Grouping […]
3     Range a-z
4     Union [a-e][i-u]
5     Intersection [a-z&&[aeiou]]

Note that a different set of metacharacters are in effect inside a character class than outside a character class. For instance, the regular expression . loses its special meaning inside a character class, while the expression becomes a range forming metacharacter.

Line terminators


A line terminator is a one- or two-character sequence that marks the end of a line of the input character sequence. The following are recognized as line terminators:


  • A newline (line feed) character (‘\n’),
  • A carriage-return character followed immediately by a newline character (“\r\n”),
  • A standalone carriage-return character (‘\r’),
  • A next-line character (‘\u0085’),
  • A line-separator character (‘\u2028’), or
  • A paragraph-separator character (‘\u2029).

If UNIX_LINES mode is activated, then the only line terminators recognized are newline characters.

The regular expression . matches any character except a line terminator unless the DOTALL flag is specified.

By default, the regular expressions ^ and $ ignore line terminators and only match at the beginning and the end, respectively, of the entire input sequence. If MULTILINE mode is activated then ^ matches at the beginning of input and after any line terminator except at the end of input. When in MULTILINE mode $ matches just before a line terminator or the end of the input sequence.

Groups and capturing


Capturing groups are numbered by counting their opening parentheses from left to right. In the expression ((A)(B(C))), for example, there are four such groups:
















1     ((A)(B(C)))
2     (A)
3     (B(C))
4     (C)

Group zero always stands for the entire expression.

Capturing groups are so named because, during a match, each subsequence of the input sequence that matches such a group is saved. The captured subsequence may be used later in the expression, via a back reference, and may also be retrieved from the matcher once the match operation is complete.

The captured input associated with a group is always the subsequence that the group most recently matched. If a group is evaluated a second time because of quantification then its previously-captured value, if any, will be retained if the second evaluation fails. Matching the string “aba” against the expression (a(b)?)+, for example, leaves group two set to “b”. All captured input is discarded at the beginning of each match.

Groups beginning with (? are pure, non-capturing groups that do not capture text and do not count towards the group total.

Unicode support


This class follows Unicode Technical Report #18: Unicode Regular Expression Guidelines, implementing its second level of support though with a slightly different concrete syntax.

Unicode escape sequences such as \u2014 in Java source code are processed as described in ?3.3 of the Java Language Specification. Such escape sequences are also implemented directly by the regular-expression parser so that Unicode escapes can be used in expressions that are read from files or from the keyboard. Thus the strings “\u2014” and “\\u2014”, while not equal, compile into the same pattern, which matches the character with hexadecimal value 0x2014.

Unicode blocks and categories are written with the \p and \P constructs as in Perl. \p{prop} matches if the input has the property prop, while \P{prop} does not match if the input has that property. Blocks are specified with the prefix In, as in InMongolian. Categories may be specified with the optional prefix Is: Both \p{L} and \p{IsL} denote the category of Unicode letters. Blocks and categories can be used both inside and outside of a character class.

The supported blocks and categories are those of The Unicode Standard, Version 3.0. The block names are those defined in Chapter 14 and in the file Blocks-3.txt of the Unicode Character Database except that the spaces are removed; “Basic Latin”, for example, becomes “BasicLatin”. The category names are those defined in table 4-5 of the Standard (p. 88), both normative and informative.

Comparison to Perl 5


Perl constructs not supported by this class:




  • The conditional constructs (?{X}) and (?(condition)X|Y),



  • The embedded code constructs (?{code}) and (??{code}),



  • The embedded comment syntax (?#comment), and



  • The preprocessing operations \l \u, \L, and \U.


Constructs supported by this class but not by Perl:




  • Possessive quantifiers, which greedily match as much as they can and do not back off, even when doing so would allow the overall match to succeed.



  • Character-class union and intersection as described above.


Notable differences from Perl:




  • In Perl, \1 through \9 are always interpreted as back references; a backslash-escaped number greater than 9 is treated as a back reference if at least that many subexpressions exist, otherwise it is interpreted, if possible, as an octal escape. In this class octal escapes must always begin with a zero. In this class, \1 through \9 are always interpreted as back references, and a larger number is accepted as a back reference if at least that many subexpressions exist at that point in the regular expression, otherwise the parser will drop digits until the number is smaller or equal to the existing number of groups or it is one digit.



  • Perl uses the g flag to request a match that resumes where the last match left off. This functionality is provided implicitly by the Matcher class: Repeated invocations of the find method will resume where the last match left off, unless the matcher is reset.



  • In Perl, embedded flags at the top level of an expression affect the whole expression. In this class, embedded flags always take effect at the point at which they appear, whether they are at the top level or within a group; in the latter case, flags are restored at the end of the group just as in Perl.



  • Perl is forgiving about malformed matching constructs, as in the expression *a, as well as dangling brackets, as in the expression abc], and treats them as literals. This class also accepts dangling brackets but is strict about dangling metacharacters like +, ? and *, and will throw a PatternSyntaxException if it encounters them.


For a more precise description of the behavior of regular expression constructs, please see Mastering Regular Expressions, 2nd Edition, Jeffrey E. F. Friedl, O’Reilly and Associates, 2002.

Spikey’s Bounce Around 史碧奇解救蝴蝶冒險記

Spikey’s Bounce Around 史碧奇解救蝴蝶冒險記

軟體:Spikey’s Bounce Around(版本:N/A)
類別:動作遊戲
性質:Freeware()

【編輯/宗文】

遊戲中玩家必須引導主角,在關卡中透過打破玻璃瓶來解救被關住的蝴蝶,不過這可不簡單喔!因為除了主角的彈跳次數有限制外,許多關卡中還藏有許多危機,以及有很多敵人來干擾玩家。遊戲中如果移動次數變為零而尚有蝴蝶未救出,遊戲就會結束。另外玩家如能減少移動次數而過關,將可以獲得額外的加分。遊戲的玩法非常簡單,玩家首先移動滑鼠來設定要行進的方向,然後按滑鼠左鍵主角便會移動,不過要注意主角移動的距離有所限制,玩家如要到達較遠目標,應該分次來行動。在每一個不同關卡中,玩家要將所有蝴蝶都救出來才能過關,如要打破玻璃瓶而救出蝴蝶的話,必須將支撐玻璃瓶的植物或樹藤去除,這些都將會消耗主角移動的次數,因此玩家必須算準才能減少主角移動的次數。



遊戲中還會出現一些彈跳物品,當主角碰到這些物品時會彈跳到其他地方,另外還有許多危險物品及敵人出現,玩家要算準時間差或跳躍的角度來避開他們,否則一碰觸可是會扣能量值的。

下載:

Flames of Fury 狂怒的火焰

Flames of Fury 狂怒的火焰

軟體:Flames of Fury(版本:N/A)
類別:射擊遊戲
性質:Freeware()

【編輯/宗文】

這是一款射擊遊戲,玩家必須帶領飛龍來消滅敵人,相對的敵人也會派出大量軍隊來攻擊飛龍巢穴,玩家必須防禦它,一旦巢穴被擊毀,遊戲就會結束。遊戲中有三種困難度,建議玩家從簡單的開始挑戰,熟悉遊戲後再挑戰困難的。飛龍的巢穴可以製造各種火球,與防禦火焰(阻擋敵人直接攻擊飛龍巢穴),如有升級點數也可以在巢穴中升級各種不同飛龍的能力,另外也可以利用資源來恢復健康值。



飛龍可以發射各種不同類型的火球,不過這些火球必須有兩種資源才能製造(飛龍靠近這兩種資源提供處便能取得。),一種是藍色的氫資源,一種是紅色的硫磺資源,玩家必須尋找這兩資源,然後再回到巢穴中來合成火球。各種火球的攻擊值與消耗能源的數量都不同,端看玩家如何來做出最佳抉擇。在這個過程中敵人會不斷騷擾飛龍,以及攻擊其巢穴,所以一旦發現敵軍要攻擊巢穴時,記得趕緊回防。另外要注意這兩種資源可是會用完的,因此玩家在攻擊敵人方面要力求準確,否則能源用完時可就無法再攻擊敵人了。



在敵人方面有分為數種,底下介紹幾個敵軍的種類或建築物。一種是陸上的裝甲車,它無法攻擊我方基地,只能在一定範圍內移動攻擊飛龍。戰鬥直昇機可以靠近飛龍巢穴並攻擊它,所以一但看到戰鬥直昇機應該先摧毀它。另外還有敵軍的防禦塔,以及生產戰鬥單位的兵工廠,都是玩家要攻擊的目標。遊戲操控說明:1.利用四個方向鍵移動飛龍。2.滑鼠移動可以瞄準敵人,按滑鼠左鍵可以發射火球。3.按空白鍵可以改變火球類型。

下載: