2007年8月12日日曜日

ちっちゃなテトリス

結局遊べるところまで完成させてしまいました。短期集中連載第2弾とでも呼びましょうか。

これと全く同じものをHSPコンテスト2007へ投稿しました。ので、いつも通り利用・改造・転載など自由ですが、これの改造をHSPコンテスト2007へ投稿することはご遠慮ください。

関連:stick命令をgetkey命令で実装する
fujidigさんによるバグの指摘
#include "hsptv.as"

// 独自stick定義モジュール
#undef stick
#module modStick

// getkeyキーコード
#const GETKEY_LEFT          37
#const GETKEY_UP            38
#const GETKEY_RIGHT         39
#const GETKEY_DOWN          40
#const GETKEY_Z             'Z'
#const GETKEY_X             'X'

#deffunc _initStick
    dim KEY_CODE, 6
    KEY_CODE(0) = GETKEY_XGETKEY_ZGETKEY_DOWNGETKEY_RIGHTGETKEY_UPGETKEY_LEFT
    return

#deffunc _stick var vTarget, int NO_TRIGGER, int CHECK_MODE, local tmp
    vTarget = 0
    repeat 6; = length(KEY_CODE)           // start.ax軽量化のために定数化
        getkey tmp, KEY_CODE(cnt)
        vTarget = vTarget << 1 | tmp
    loop
    if (CHECK_MODE == WIN_ACTIVE_CHECK_ON) & (ginfo_act == -1){
        // HSPウィンドウがアクティブでない
        prev = vTarget
        vTarget = 0
    } else {
        tmp = vTarget
        vTarget &= (-1 ^ prev) | NO_TRIGGER
        prev = tmp
    }
    return
#define global stick(%1%2=0%3=1_stick %1%2%3
#global
    _initStick       // 配列の初期化
// 独自stick定義モジュールここまで

#const global BLOCK_SIZE 32
#const global BLOCK_HSIZE BLOCK_SIZE / 2
#const global BLOCK_COLOR_MAX 8
#const global AREA_WIDTH  10
#const global AREA_HEIGHT 15
#const global AREA_WIDTH2 AREA_WIDTH * BLOCK_SIZE
#const global AREA_HEIGHT2 BLOCK_SIZE * AREA_HEIGHT
#const global AREA_X ( 640 - AREA_WIDTH2 ) / 2
#const global AREA_Y ( 480 - AREA_HEIGHT2 ) / 2
#const HIGHSCORE_MAX 6

#enum STATE_NORMAL = 1
#enum STATE_BLINK
#enum STATE_GAMEOVER

#module
//
// 指定した色でブロックを描く
#deffunc draw_block int x, int y, int c, int mode
    hsvcolor 191 * c / BLOCK_COLOR_MAX255255 - 155 * ( mode != 0 )
    boxf AREA_X + BLOCK_SIZE * x, AREA_Y + BLOCK_SIZE * y, AREA_X + BLOCK_SIZE * ( x + 1 ) - 2AREA_Y + BLOCK_SIZE * ( y + 1 ) - 2
    return
//
// エリアを再描画
#deffunc draw_area var map
    color
    boxf AREA_XAREA_YAREA_X + AREA_WIDTH2 - 1AREA_Y + AREA_HEIGHT2 - 1
    repeat AREA_HEIGHT
        y = cnt
        repeat AREA_WIDTH
            p = peek( map, y * AREA_WIDTH + cnt )
            if p : draw_block cnt, y, p
        loop
    loop
    return
//
// チェックされた行を塗りつぶす
#deffunc blink_sellines var check
    repeat AREA_HEIGHT
        if peek( check, cnt ) {
            boxf AREA_XAREA_Y + BLOCK_SIZE * cntAREA_X + AREA_WIDTH2 - 1AREA_Y + BLOCK_SIZE * ( cnt + 1 ) - 1
        }
    loop
    return
//
// テトリミノを描く
#deffunc draw_tetrimino int block_type, int block_color, int _x, int _y, int mode
    repeat 4
        y = _y + cnt
        if ( AREA_HEIGHT <= y )|( y < 0 ) : continue
        _cnt = cnt
        repeat 4
            x = _x + cnt
            if ( AREA_WIDTH <= x ) : break
            if block_type >> ( _cnt * 4 + cnt ) & 1 {
                draw_block x, y, block_color + 1, mode
            }
        loop
    loop
    return
//
// マップにブロックを固定
#deffunc fix_to_map var map, int block_type, int block_color, int _x, int _y
    repeat 4
        y = _y + cnt
        _cnt = cnt
        repeat 4
            x = _x + cnt
            if block_type >> ( _cnt * 4 + cnt ) & 1 {
                if (x < 0)|(AREA_WIDTH <= x)  : continue
                if (y < 0)|(AREA_HEIGHT <= y) : continue
                poke map, y * AREA_WIDTH + x, block_color + 1
            }
        loop
    loop
    return
//
// 消せる行をチェックし、変数へ結果を返す
#deffunc check_del_lines var map, var check
    ret = 0
    repeat AREA_HEIGHT
        i = 1
        _cnt = cnt
        repeat AREA_WIDTH
            if peek( map, _cnt * AREA_WIDTH + cnt ) == 0 {
                i = 0
                break
            }
        loop
        poke check, cnt, i
        ret += i
    loop
    return ret
//
// nLine行目を消し、上にあるラインを下へ落とす
#deffunc del_line var map, int nLine
;   if ( nLine < 0 ) | ( AREA_HEIGHT <= nLine ) : return -1
    if nLine > 0 {
        memcpy map, map, nLine * AREA_WIDTHAREA_WIDTH0
    }
    memset map, 0AREA_WIDTH0
    return; 0
//
// 指定した行をすべて削除
#deffunc del_sellines var map, var check
    i = AREA_HEIGHT - 1
    repeat AREA_HEIGHT1
        if peek( check, AREA_HEIGHT - cnt ) {
            del_line map, i
        } else {
            i--
        }
    loop
    return; 0
//
// テトリミノが壁やブロックと衝突するか検出
#defcfunc hit_check var map, int block_type, int _x, int _y
    ret = 0
    repeat 4
        y = _y + cnt
        _cnt = cnt
        repeat 4
            x = _x + cnt
            if block_type >> ( _cnt * 4 + cnt ) & 1 {
                if ( x < 0 ) | ( AREA_WIDTH <= x ) | ( AREA_HEIGHT <= y ) {
                    ret = 1
                    break
                }
                if y >= 0 : if peek( map, y * AREA_WIDTH + x ) {
                    ret = 1
                    break
                }
            }
        loop
        if ret : break
    loop
    return ret
#global

    cls 1
    randomize

    hsptv_up -1""

    dim block_type, 47 // Zが時計回り
    block_type( 00 ) = $0660$0660$0660$0660 // ■
    block_type( 01 ) = $2222$00F0$4444$0F00 // |
    block_type( 02 ) = $0270$0232$0072$0262 // ┤
    block_type( 03 ) = $0360$0462$06C0$4620 // s
    block_type( 04 ) = $0630$0264$0C60$2640 // z
    block_type( 05 ) = $2260$0470$0644$0E20 // 「
    block_type( 06 ) = $4460$0740$0622$02E0 // └

    dim  high_score, HIGHSCORE_MAX
    sdim ranker_name, 50HIGHSCORE_MAX
    sdim map, AREA_WIDTH * AREA_HEIGHT
    sdim line_check, AREA_HEIGHT

    sqarea_x = AREA_XAREA_X + AREA_WIDTH2AREA_X + AREA_WIDTH2AREA_X
    sqarea_y = AREA_YAREA_YAREA_Y + AREA_HEIGHT2AREA_Y + AREA_HEIGHT2

    ;pos ginfo_winx : mes "Gameover"
    ;gameover_width = ginfo_mesx : gameover_height = ginfo_mesy
#const gameover_width 64
#const gameover_height 18
#const fall_limit 17
    gmode GMODE_ALPHA, , , 192

*restart
    gosub *reload_highscore
    memset map, 0AREA_WIDTH * AREA_HEIGHT
    next_type = rnd(7)
    state = STATE_NORMAL
    score = 0
    gosub *create_new_tetrimino

*main
    stick keys, 8
    if state == STATE_BLINK {
        state_limit--
        if state_limit == 0 {
            state = STATE_NORMAL
            del_sellines map, line_check
            gosub *create_new_tetrimino
        }
    }
    if state == STATE_GAMEOVER {
        if state_limit : state_limit--
        if state_limit == 1 : hsptv_up score, ""
        if ( state_limit == 0 ) & ( keys >> 4 & 1 ) : goto *restart
    }
    if state == STATE_NORMAL {
        gosub *move_tetrimino
    }
    gosub *draw
    wait 2
    goto *main

*draw
    redraw 0
    draw_area map
    gosub *draw_score
    gosub *draw_next
    if state == STATE_NORMAL {
        gosub *draw_ghost
        draw_tetrimino block_type( moving_rot, moving_type ), moving_type, moving_x, moving_y, 0
    }
    if state == STATE_BLINK {
        c = 255 * ( state_limit / 3 \ 2 )
        color c, c, c
        blink_sellines line_check
    }
    if state == STATE_GAMEOVER {
        color
        gsquare -1, sqarea_x, sqarea_y
        x = AREA_X + ( AREA_WIDTH2 - gameover_width ) / 2
        y = AREA_Y + ( AREA_HEIGHT2 - gameover_height ) / 2
        color 100100100
        pos x+2, y+2
        mes "Gameover"
        color 255255255
        pos x, y
        mes "Gameover"
        if ( state_limit == 0 ) {
            pos x-50, y+40 : mes "push Z key to restart"
        }
    }
    redraw 1
    return

*draw_next
    color
    boxf BLOCK_HSIZEBLOCK_HSIZEBLOCK_HSIZE * 9 - 1BLOCK_HSIZE  * 11 - 1
    pos BLOCK_HSIZEBLOCK_HSIZE
    draw_tetrimino block_type( 0, next_type ), next_type, -410
    return

*draw_score
    color
    boxf BLOCK_HSIZEBLOCK_SIZE * 6BLOCK_HSIZE * 9 - 1BLOCK_HSIZE * 29 - 1
    color 255255255
    pos BLOCK_HSIZE + 6BLOCK_SIZE * 6 + 9
    mes strf"score:%08d", score )
    mes "--------------"
    repeat HIGHSCORE_MAX
        mes "" + ( cnt + 1 ) + ":" + ranker_name( cnt )
        mes strf"      %08d", highscore(cnt) )
    loop
    return

*move_tetrimino
    if state != STATE_NORMAL : return

    // 横方向の移動
    next_moving_x = moving_x + ( keys >> 2 & 1 ) - ( keys & 1 )
    if hit_check( map, block_type( moving_rot, moving_type ), next_moving_x, moving_y ) == 0 {
        moving_x = next_moving_x
    }

    // 縦方向の移動
    fall_count += 1 + 3 * ( keys >> 3 & 1 )
    if fall_count >= fall_limit {
        fall_count = 0
        if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y + 1 ) == 0 {
            moving_y++
        } else {
            // これ以上落下できないので、今の位置に固定
            fix_to_map map, block_type( moving_rot, moving_type ), moving_type, moving_x, moving_y
            gosub *check_delete
        }
    }
    if keys & 2 {
        moving_y = ghost_y
        fall_count = fall_limit
    }

    // 回転処理
    if keys & %110000 {
        next_rot = moving_rot + (keys >> 4 & 1) - (keys >> 5 & 1) & 3
        if hit_check( map, block_type( next_rot, moving_type ), moving_x, moving_y ) == 0 {
            moving_rot = next_rot
//          fall_count--
        }
    }
    return

*check_delete
    check_del_lines map, line_check
    if stat {
        score += stat * stat * 10
        state = STATE_BLINK
        state_limit = 12
    } else {
        gosub *create_new_tetrimino
    }
    return

*draw_ghost
    repeat
        if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y + cnt ) {
            ghost_y = moving_y + cnt - 1
            break
        }
    loop
    if ghost_y > moving_y {
        draw_tetrimino block_type( moving_rot, moving_type ), moving_type, moving_x, ghost_y, 1
    }
    return

*create_new_tetrimino
    moving_x = AREA_WIDTH / 2 - 2// 動かしているテトリミノの位置(左上)
    moving_y = -2
    moving_rot = 0          // 動かしているテトリミノの回転
    moving_type = next_type // 動かしているテトリミノの種類(兼色の種類)
    next_type = rnd(7)
    if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y ) {
        // ゲームオーバー
        state = STATE_GAMEOVER
        state_limit = 20
        gosub *reload_highscore
    }
    return

*reload_highscore
    repeat HIGHSCORE_MAX
        hsptv_getrank highscore(cnt), ranker_name(cnt), s, cnt
    loop
    return

2007年8月11日土曜日

テトリミノを表示する

段階的学習!がちょっと面白そうだったので作成。
こうしたテクニックはショートプログラムでも利用できそうです。#const global BLOCK_SIZE 24
#const global BLOCK_COLOR_MAX 8
#const TETRIMINO_TYPE_MAX 7

#module
//
// 指定した色でブロックを描く
#deffunc draw_block int x, int y, int c
    hsvcolor 191 * c / BLOCK_COLOR_MAX255255
    boxf BLOCK_SIZE * x, BLOCK_SIZE * y, BLOCK_SIZE * ( x + 1 ) - 2BLOCK_SIZE * ( y + 1 ) - 2
    return
//
// テトリミノを描く
#deffunc draw_tetrimino int tetrimino_pattern, int block_color, int _x, int _y
    repeat 4
        y = _y + cnt
        _cnt = cnt
        repeat 4
            x = _x + cnt
            if tetrimino_pattern >> ( _cnt * 4 + cnt ) & 1 {
                draw_block x, y, block_color
            }
        loop
    loop
    return
#global

    // テトリミノパターンの準備
    dim tetrimino_pattern, 4TETRIMINO_TYPE_MAX
    tetrimino_pattern( 00 ) = $0033$0033$0033$0033 // □
    tetrimino_pattern( 01 ) = $2222$00F0$2222$00F0 // |
    tetrimino_pattern( 02 ) = $0232$0072$0262$0270 // ┤
    tetrimino_pattern( 03 ) = $0036$0231$0036$0231 // s
    tetrimino_pattern( 04 ) = $0063$0132$0063$0132 // z
    tetrimino_pattern( 05 ) = $0047$0322$0071$0113 // ┘
    tetrimino_pattern( 06 ) = $0017$0223$0074$0311 // └

    tetrimino_rotation = 0
    tetrimino_type = 0
    game_speed = 30
    need_to_draw = 1
    title "←・→でテトリミノの種類を変更"

*main
    gosub *calc
    gosub *draw
    wait 2
    goto *main

*calc
    stick keys
    v = ( keys >> 2 & 1 ) - ( keys & 1 )
    if v {
        // テトリミノの種類を変更
        need_to_draw = 1
        tetrimino_type += v
        if tetrimino_type < 0 {
            tetrimino_type = TETRIMINO_TYPE_MAX - 1
        } else : if tetrimino_type >= TETRIMINO_TYPE_MAX {
            tetrimino_type = 0
        }
    }

    count++
    if count == game_speed {
        // テトリミノの回転
        count = 0
        need_to_draw = 1
        tetrimino_rotation = ( tetrimino_rotation + 1 ) & 3
    }
    return

*draw
    if need_to_draw {
        need_to_draw = 0
        redraw 0
        color : boxf
        draw_tetrimino tetrimino_pattern( tetrimino_rotation, tetrimino_type ), tetrimino_type, 00
        redraw 1
    }
    return

2007年8月8日水曜日

バイナリデータの検索

本家BBSに投稿した、とっても基本的な線形検索のアルゴリズム。わざとモジュール化していません。

// 文字列でやっているが、文字列以外のバイナリデータでも原理は同じ。
    sTarget = "Hot Soup Processor"  // 検索されるバイナリデータ(この中から検索するバイナリデータを探す)
    sSerch  = "oce"                 // 検索するバイナリデータ

    // ここから検索処理。
    // バイナリデータではstrlenは使えないので、何らかの方法で大きさを調べてください。
    repeat strlen( sTarget ) - ( strlen( sSerch ) - 1 )
        _cnt = cnt : iResult = cnt
        repeat strlen( sSerch )
            if peek( sTarget, _cnt + cnt ) != peek( sSerch, cnt ) { // peekで1バイトずつ比較する
                iResult = -1
                break
            }
        loop
        if ( iResult >= 0 ) : break                     // 見つかったので検索終了
    loop
    // 検索処理ここまで。

    if ( iResult >= 0 ) {
        // バイナリデータが見つかった場合
        sdim sMarker, strlen( sTarget ) + 1
        memset sMarker, ' ', strlen( sTarget )
        memset sMarker, '^', strlen( sSerch ), iResult  // 見つけた文字列の部分にマークする

        mes sTarget
        mes sMarker
        mes sSerch + "を" + iResult + "バイトめに見つけました。"
        mes "instr()の結果(" + instr( sTarget, 0, sSerch ) + ")と一緒でしょ?"
    } else {
        // バイナリデータが見つからなかった場合
        mes "見つかりませんでした。"
    }
    stop

2007年8月4日土曜日

HSファイルからHTMLヘルプを作成する

HSP3.1から同梱されなくなったHTMLヘルプを作成するスクリプト。
命令一覧は作成しません。

祝・50投稿ヽ(´▽`)ノ

よくよく考えたらHHXのDBにはABC順に記録されているので、配列を使う必要は全くありませんでした。
もしEXE化する機会があれば処理方法を再度考え直してみたいと思います。

改良版をこちらのページから入手できます。

関連:HSファイルからHTMLヘルプを作成する(2)

// hsファイルからHTMLヘルプを作成
#include "../hsphelp/src/hhx_db.hsp"
#module
// 関数名・命令名からidを得る
#defcfunc get_id str name, local s
    s = name
    if ( peek( s, 0 ) < 'a' ) | ( 'z' < peek( s, 0 ) ) : s = strmid( s, 1strlen( s ) - 1 )
    return "s_" + s
// 関数名・命令名からファイルの通し番号(独自に定義)を得る
//   help_a.htmlを0、help_b.htmを1、…help_sp.htmを26とする
#defcfunc get_filenum str name, local s, local p
    s = name
    p = peek( s, 0 )
    if ( 'A' <= p ) & ( p <= 'Z' ) : p -= 'A' - 'a'
    if ( 'a' <= p ) & ( p <= 'z' ) {
        return p - 'a'
    } else {
        return 'z' - 'a' + 1
    }
// 通し番号からファイル名を得る
#defcfunc get_filename int num
    if ( 0 <= num ) & ( num <= 'z' - 'a' ) {
        return "help_" + strf"%c", num + 'a' ) + ".htm"
    } else {
        return "help_sp.htm"
    }
#global

    chdir dir_exe + "/hsphelp"

    gosub *load_db           // HHXのDBからデータをロードする
    gosub *init              // 前準備
    gosub *make_html_files   // HTMLファイルを作成する
    gosub *make_css_file     // CSSファイルを作成する
    dialog "finish"
    end

*load_db
    HHX_init_load_db
    if HHX_currentset_sum() ! HHX_diskset_sum() {
        mes "rebuilding db..."           // HSファイルに何かしらの変更が加わったため、DBを再構築
        HHX_init_rebuild_db DBR_WRITEDB
    } else {
        HHX_init_extract_db
    }
    return

*init
    // a ~ zと特殊文字(_, #)用のファイルを用意
    sdim file, 1024, 'z' - 'a' + 2 
    dim file_offset, 'z' - 'a' + 2 

    // HTMLのヘッダをそれぞれのファイルに書き込む
    buf = {"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"ja\" lang=\"ja\">
<head>
\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\" />
\t<meta http-equiv=\"Content-Language\" content=\"ja\" />
\t<link rel=\"stylesheet\" type=\"text/css\" href=\"hsphelp.css\" />
\t<title>HSP command help</title>
</head>
<body>
\t<h1>HSP command help</h1>\n"}

    l = strlen( buf )
    repeat 'z' - 'a' + 2
        file( cnt ) = buf
        file_offset( cnt ) = l
    loop
    return

*make_html_files
    db_num = HHX_select_all() // すべての命令・関数を検索対象とする

    repeat db_num
        c = HHX_get_next()
        db_name  = hhxdata( c, C_NAME )         // 命令・関数名
        file_num = get_filenum( db_name )       // この命令が記録されるHTMLの通し番号(独自に定義したもの)

        // 見出し(h2タグ)
        buf = "\t<h2 id=\"" + get_id( db_name ) + "\" class=\"keyword_name\">" + db_name + " " +  hhxdata( c, C_PRM ) + "\t\t[" + hhxdata( c, C_SUMMARY ) + "]</h2>\n"
        // パラメータ
        if hhxdata( c, C_PRM2 ) != "" {
            buf += "\t\t<p class=\"prm\">" + hhxdata( c, C_PRM2 ) + "</p>\n"
        }
        // 説明文
        if hhxdata( c, C_INST ) != "" {
            buf += "\t\t<h3>説明</h3><p class=\"inst\">" + hhxdata( c, C_INST ) + "</p>\n"
        }
        // 備考
        if hhxdata( c, C_NOTE ) != "" {
            buf += "\t\t<h3>備考</h3><p class=\"note\">" + hhxdata( c, C_NOTE ) + "</p>\n"
        }
        // 参照
        if hhxdata( c, C_HREF ) != "" {
            buf += "\t\t<h3>参照</h3><ul class=\"href\">"
            i = 0 : l = strlen( hhxdata( c, C_HREF ) )
            repeat
                getstr s, hhxdata( c, C_HREF ), i, ' '
                i += strsize
                buf += "\t\t\t<li><a href=\"" + get_filenameget_filenum( s ) ) + "#" + get_id( s ) + "\">" + s + "</a></li>\n"
                if l <= i : break
            loop
            buf += "\t\t</ul>"
        }
        // 水平線(次の項目との区切り)
        buf += "\n\t<hr>\n\n"

        // 配列に保存
        l = strlen( buf )
        file( file_num ) += buf
        file_offset( file_num ) += l

;       title str( 100 * double( cnt ) / db_num ) + "% finished..."
;       await 1
    loop

    // ファイルをディスクに保存
    repeat 'z' - 'a' + 2
        file( cnt ) += "</body></html>"
        file_offset( cnt ) += strlen"</body></html>" )
        bsave get_filenamecnt ), file( cnt ), file_offset( cnt )
    loop
    return

*make_css_file
    buf = {"body {
background-color : #f0e0d0 ;
}
h2 {
color : #000080 ;
font-size : large ;
font-weight : bold ;
white-space : pre ;
}
h3 {
font-weight : bold ;
}
p.prm {
color : #000080 ;
font-size : small ;
white-space : pre ;
margin-left : 70px;
}
p.inst {
margin-left : 70px;
white-space : pre ;
}
p.note {
margin-left : 70px;
}
ul.href {
margin-left : 70px;
}"}

    bsave "hsphelp.css", buf, strlen( buf )
    return

2007年7月30日月曜日

弾むリング

モジュール変数によるキャラクタの管理。
#module ring x, z, r, v_x, v_z, a_z, ang, a_ang, life, r_inner
#const DIV_NUM 14      // リングの分割数
#const LIFE_MAX 500    // 寿命の初期値

// 初期化
#modinit int _x, int _z, double _r, int _v_x, double _v_z, double _a_ang
    x = _x : z = _z : r = _r : r_inner = 0.8 * r
    v_x = _v_x : v_z = _v_z : a_z = -2.0
    ang = 0.0 : a_ang = _a_ang
    life = LIFE_MAX
    return

// リングを動かす
#modfunc move
    v_z += a_z
    x += v_x : z += v_z
    if ( z < r ) {
        z = r * 2 - z
        v_z = -v_z * 0.9
    }
    life -= 5
    ang += a_ang
    return

// リングを描く
#modfunc draw
    gmode GMODE_ALPHA, , , limit(life , 0200)
    repeat DIV_NUM
        hsvcolor cnt * 191 / DIV_NUM255255
        c = 3.14 * 2 * cnt / DIV_NUM + ang
        gs_x = x + r * cos( c ), x + r * cos( c + g ), x + r_inner * cos( c + g ), x + r_inner * cos( c )
        gs_y = ginfo_winy - z - r * sin( c ), ginfo_winy - z - r * sin( c + g ), ginfo_winy - z - r_inner * sin( c + g ), ginfo_winy - z - r_inner * sin( c )
        gsquare -1, gs_x, gs_y
    loop
    return life <= 0
#global
    g@ring = ( 3.14 * 2.0 ) / ( DIV_NUM@ring + 3 )

    dimtype mod_ring, 520
    onclick gosub *make_ring
    title "click to create rings"

*main
    redraw 0
    color : boxf
    foreach mod_ring
        move mod_ring( cnt )          // リングを移動させる
        draw mod_ring( cnt )          // リングを描く
        if stat : delmod mod_ring( cnt )   // リングが寿命を迎えていたら削除
    loop
    redraw 1
    wait 3
    goto *main

*make_ring
    switch iparam
    case 0
        newmod mod_ring, ring, 0,          rnd100 ) + 15060 + rnd50 ), rnd5 ) + 30.0, -0.1
        swbreak
    default
        newmod mod_ring, ring, ginfo_winxrnd100 ) + 15060 + rnd50 ), rnd5 ) - 70.0,  0.1
        swbreak
    swend
    return

2007年7月29日日曜日

累乗根を求める

ニュートン・ラフソン法を用いて累乗根を求めるモジュール。
もちろん打ち切り誤差が発生します。// ニュートン・ラフソン法でxのn乗根を求める
#include "hspmath.as"
#module
#defcfunc radical_root double x, double n, local x_old, local x_new
    x_new = x
    repeat
        x_old = x_new
        x_new = ( n - 1.0 + x * pow@( x_old, -n ) ) * x_old / n
        if ( absf( x_old - x_new ) < 0.00000000001 ) {
            // ある程度の精度で演算を打ち切る
            break
        }
    loop
    return x_new
#global

    repeat 3
        pos cnt * 2200
        up_cnt = cnt + 2
        repeat 152
            mes strfstrcnt ) + "の" + str( up_cnt ) + "乗根は%1.10f", radical_root( cnt, up_cnt ) )
        loop
    loop
    stop


本家のBBSにあった「xの(1/n)乗がxのn乗根」という考え方を使えば、何と1行で記述できます。#define ctype radical_root( %1%2 ) expflogf%1 ) / ( %2 ) )

2007年7月28日土曜日

(X)HTMLコンバータ β版公開

(X)HTMLコンバータのβ版ができました。よろしければお試しください。

β1 ダウンロード(133KB)
β2 ダウンロード(136KB)
β3 ダウンロード(99KB)
なおスクリプトの公開は正式版からとする予定です。

v1.0を公開しました。
変換スクリプトをこちらで公開しています。他のスクリプトはただいま整理中です。

β3からはHSPと同じフォルダに入れる必要があります。