Ring 1.9 での変更点は?

Ring 1.9 公開版の新機能と変更点を学びます。

新機能と変更一覧

Ring 1.9 の新機能!

  • 新規ゲーム : Gold Magic 800
  • ゲームの追加
  • Ring ノートパッドの改善
  • StdLib の改善
  • BigNumber ライブラリ
  • RingPostgreSQL 拡張機能
  • クラウド経由でのウェブアプリケーション配布
  • RingQt の改善
  • メモリ管理の改善
  • 拡張機能におけるコード生成器の更新
  • その他多数の改善

新規ゲーム : Gold Magic 800

これまでにないパズルゲームです。

体験版 (18 レベルまで) とゲームのソースコードが付属しています。

Steam ページ (44 レベル) : https://store.steampowered.com/app/939200/Gold_Magic_800/

レベルの選択ができます。

Gold Magic 800 - スクリーンショット 2

このスクリーンショットはレベル (1) です。

Gold Magic 800 - スクリーンショット 3

Gold Magic 800 レベルエディタです。

Gold Magic 800 レベルエディタ

ゲームの追加

このゲームを Ring アプリケーションとして追加しました。

  1. 2048 ゲーム
  2. Memory ゲーム
  3. Wise Quadrat ゲーム
  4. Tessera ゲーム
  5. Othello ゲーム

このスクリーンショットは Android 版 2048 ゲームです。

2048 ゲーム

このスクリーンショットは Tessera ゲームです。

Tessera ゲーム

このスクリーンショットは Othello ゲームです。

Othello ゲーム

Ring ノートパッドの改善

  1. 新規スタイル
  2. 新規モード
  3. 開いたファイルをタブ UI で切り替え
  4. バッチファイルの実行に対応
Ring Notepad

StdLib の改善

  1. List2Code() 関数を StdLib へ追加しました。

この関数は Ring リストを実行中に Ring ソースコードへ変換することでソースファイルを保存できるようにします。

リストは文字列、数値または部分リストを有しています。

用例:

load "stdlibcore.ring"
aList = 1:10
? list2Code(aList)

実行結果:

[
        1,2,3,4,5,6,7,8,9,10
]
  1. Str2ASCIIList() および ASCIIList2Str() 関数を StdLib へ追加しました。

これらの関数を使用すると、文字列と数値リスト間で各項目が 1 バイト ASCII コードから成る文字列表現へ変換します。

これにより、バイト文字列を ASCII リストに変換してリストの数値に対する演算ができるようにします (XOR など)。

用例:

load "stdlibcore.ring"

cStr = "MmMm"

aList = Str2ASCIILIST(cStr)
? aList

cStr2 = ASCIIList2Str(aList)
? cStr2
? len(cStr2)

実行結果:

77
109
77
109

MmMm
4

BigNumber ライブラリ

BigNumber ライブラリで非常に大きい数の算術演算ができます。

用例:

load "bignumber.ring"

num1 = "62345678901234567891678345123456789"    ### 大なり
num2 =  "1237894567890123419871236545"          ### 小なり
num3 =     "64"                                 ### 小なりを割る
num4 = "765432"
num5 =      "3"                                 ### 累乗

? "Add big numbers:"
a1 = new BigNumber(num1)        a1.Print()
a2 = new BigNumber(num2)        a2.Print()
a3 = a1 + a2                    a3.Print() ? nl

? "Substract big numbers:"
a1 = new BigNumber(num1)        a1.Print()
a2 = new BigNumber(num2)        a2.Print()
a3 = a1 - a2                    a3.Print() ? nl

? "Multiply big numbers:"
a1 = new BigNumber(num1)        a1.print()
a2 = new BigNumber(num2)        a2.print()
a3 = a1 * a2                    a3.print() ? nl

? "Divide big numbers:"
a1 = new BigNumber(num1)        a1.print()
a2 = new BigNumber(num2)        a2.print()
a3 = a1 / a2                    a3.print() ? nl

? "Divide big numbers: by very small number"
a1 = new BigNumber(num1)        a1.print()
a2 = new BigNumber(num3)        a2.print()
a3 = a1 / a2                    a3.print() ? nl

? "Power of big number:"
a1 = new BigNumber(num1)        a1.print()
a2 = new BigNumber(num5)        a2.print()
a3 = a1 ^ a2                    a3.print() ? nl

実行結果:

Add big numbers:
62345678901234567891678345123456789
1237894567890123419871236545
62345680139129135781801764994693334


Substract big numbers:
62345678901234567891678345123456789
1237894567890123419871236545
52345687663340000001554925252220244


Multiply big numbers:
62345678901234567891678345123456789
1237894567890123419871236545
77177377243260150103462178714197454736432472780119682305154005


Divide big numbers:
62345678901234567891678345123456789
1237894567890123419871236545
50364288


Divide big numbers: by very small number
62345678901234567891678345123456789
64
974151232831790123307474142554012


Power of big number:
62345678901234567891678345123456789
3
242336636261471172092347146031727004 (実行結果は次行へ続きます)
371698195628343934238988256152289508 (実行結果は次行へ続きます)
493964611043228971692389860897069

詳細情報は本取扱説明書の「BigNumber ライブラリ」をお読みください。

RingPostgreSQL 拡張機能

Ring 1.9 では RingPostgreSQL 拡張機能を使用することで PostgreSQL データベースのネイティブ対応があります。

用例:

load "postgresqllib.ring"

conninfo = "user=postgres password=sa dbname = mahdb"

exit_nicely = func conn {
        PQfinish(conn)
        shutdown(1)
}

conn = PQconnectdb(conninfo)

if (PQstatus(conn) != CONNECTION_OK)
        fputs(stderr, "Connection to database failed: "+PQerrorMessage(conn))
                call exit_nicely(conn)
ok

res = PQexec(conn, "
        DROP DATABASE mahdb;
")
if PQresultStatus(res) != PGRES_TUPLES_OK
        fputs(stderr, "Remove failed: " + PQerrorMessage(conn))
        PQclear(res)
ok
PQclear(res)


res = PQexec(conn, "CREATE DATABASE mahdb;")
if PQresultStatus(res) != PGRES_TUPLES_OK
        fputs(stderr, "Create database failed: " + PQerrorMessage(conn))
        PQclear(res)
ok


res = PQexec(conn, "
CREATE TABLE COMPANY (
                 ID INT PRIMARY KEY     NOT NULL,
                 NAME           TEXT    NOT NULL,
                 AGE            INT     NOT NULL,
                 ADDRESS        CHAR(50),
                 SALARY         REAL );
")
if PQresultStatus(res) != PGRES_TUPLES_OK
        fputs(stderr, "Create Table failed: " + PQerrorMessage(conn))
        PQclear(res)
ok
PQclear(res)

res = PQexec(conn, "
                INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
                VALUES  (1, 'Mahmoud' , 31, 'Jeddah', 10.00 ),
                                (2, 'Ahmed'   , 27, 'Jeddah', 20.00 ),
                                (3, 'Mohammed', 33, 'Egypt' , 30.00 ),
                                (4, 'Ibrahim' , 24, 'Egypt ', 40.00 );
")
if PQresultStatus(res) != PGRES_TUPLES_OK
        fputs(stderr, "Insert Table failed: " + PQerrorMessage(conn))
        PQclear(res)
ok
PQclear(res)

res = PQexec(conn, "
           select * from COMPANY
")
if PQresultStatus(res) != PGRES_TUPLES_OK
        fputs(stderr, "Select failed: " + PQerrorMessage(conn))
        PQclear(res)
        call exit_nicely(conn)
ok


nFields = PQnfields(res)
for i = 1 to nFields
                ? PQfname(res, i-1)
next

? copy("*",60)

for i = 1 to PQntuples(res)
        for j=1 to nFields
                see PQgetvalue(res, i-1, j-1) + " "
        next
        see nl
next

PQclear(res)

PQfinish(conn)

実行結果:

id
name
age
address
salary
************************************************************
1 Mahmoud  31 Jeddah  10
2 Ahmed    27 Jeddah  20
3 Mohammed 31 Egypt   30
4 Ibrahim  24 Egypt   40

詳細情報は本取扱説明書の「PostgreSQL ライブラリ」をお読みください。

クラウド経由でのウェブアプリケーション配布

これは新規プロジェクトの作成方法、およびクラウドサービスである Heroku で Ring のウェブアプリケーションを配布する方法を解説するためのチュートリアルです。

デモ : http://testring.herokuapp.com/

プロジェクト : https://github.com/ring-lang/RingWebAppOnHeroku

Heroku ウェブサイト : https://www.heroku.com/

クラウドでの Ring ウェブアプリケーション

詳細情報は本取扱説明書の「クラウド経由でのウェブアプリケーションの配布方法」をお読みください。

RingQt の改善

  1. このクラスを RingQt へ追加しました。
  • QDrag
  • QMimeData
  • QDropEvent
  • QDragMoveEvent
  • QDragEnterEvent
  • QDragLeaveEvent
  • QClipboard
  • QChildEvent
  • QGeoPositionInfo
  • QGeoCoordinate
  • QGeoAddress
  • QGeoAreaMonitorInfo
  • QGeoAreaMonitorSource
  • QGeoCircle
  • QGeoPositionInfoSource
  • QGeoRectangle
  • QGeoShape
  • QGeoSatelliteInfo
  • QGeoSatelliteInfoSource
  • QNmeaPositionInfoSource
  • QAxWidget
  • QTextStream
  • QPrinterInfo
  • QPrintPreviewWidget
  • QPrintPreviewDialog
  • QPageSetupDialog
  • QAbstractPrintDialog
  • QPrintDialog
  1. このクラスを更新しました。
  • QAllEvents クラス : 新規イベント (ChildAdded, ChildPolished, ChildRemoved)
  • QPainter クラス : 座標点の Ring リストを扱えるようにするためにメソッドを更新 (drawConvexPloygon, drawPoints, drawPolyline)
  • QVariant : オブジェクトの作成時、様々な仮引数を扱うための追加のバージョン。
  • QAxBase : dynamicCall() and querySubObject() メソッドの異なるバージョン。

この用例は QPrintPreviewDialog クラスの用法です。

用例:

load "guilib.ring"

new qApp {
        win1 = new qwidget() {
                setwindowtitle("Printer Preview Dialog")
                setgeometry(100,100,800,880)
                printer1 = new qPrinter(0)
                show()
                oPreview = new qPrintPreviewDialog(printer1) {
                        setParent(win1)
                        move(10,10)
                        setPaintrequestedevent("printPreview()")
                        exec()
                }
        }
        exec()
}

func printPreview
        printer1  {
                painter = new qpainter() {
                        begin(printer1)
                        myfont = new qfont("Times",50,-1,0)
                        setfont(myfont)
                        drawtext(100,100,"Test - Page (1)")
                        printer1.newpage()
                        drawtext(100,100,"Test - Page (2)")
                        printer1.newpage()
                        myfont2 = new qfont("Times",14,-1,0)
                        setfont(myfont2)
                        for x = 1 to 30
                                drawtext(100,100+(20*x),"Number : " + x)
                        next
                        endpaint()
                }
        }

スクリーンショット:

Print Preview Dialog

メモリ管理の改善

RING_API_RETMANAGEDCPOINTER() を収録するために Ring API を 更新しました。

RING_API_RETMANAGEDCPOINTER() は C/C++ 言語で記述された Ring 拡張機能でマネージドポインタを Ring へ返します。このポインタは参照カウンタを使用している Ring VM により制御可能です。

これは RingQt の QPixMap オブジェクトなどのアンマネージドのリソース解放用コードを書く必要性を回避するには重要です。

また、コード生成器は必要に応じて拡張機能を RING_API_RETMANAGEDCPOINTER() に対応したものへ自動更新します。

文法:

RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType,
                                void (* pFreeFunc)(void *,void *))

RING_API_RETMANAGEDCPOINTER() に関する詳細情報は

本取扱説明書の「C/C++ による拡張機能の開発方法」をお読みください。

拡張機能におけるコード生成器の更新

  1. コード生成器は拡張機能で <loadfile> 命令に対応するために更新しました。
<loadfile> filename.cf

これは拡張機能構成ファイルを複数のファイルへ分割するのに便利です。

用例:

ファイル : RingQt 拡張機能の qt_module_network.cf より引用

<comment>
                                モジュール (ネットワーク)
</comment>

<loadfile> qabstractsocket.cf
<loadfile> qnetworkproxy.cf
<loadfile> qtcpsocket.cf
<loadfile> qtcpserver.cf
<loadfile> qhostaddress.cf
<loadfile> qhostinfo.cf
<loadfile> qnetworkrequest.cf
<loadfile> qnetworkaccessmanager.cf
<loadfile> qnetworkreply.cf
  1. Ring 1.9 以降ではコード生成器はクラス定義時の <managed> オプションに対応しました。

このオプションにより、生成器は C ポインタを返すために RING_API_RETMANAGEDCPOINTER() を使用します。

これにより、ガベージコレクターは C ポインタを管理対象にします。

用例:

<class>
name: QFont
para: QString, int, int, bool
managed
</class>

その他多数の改善

  1. Ring コンパイラ - ルールを (要素 -> ‘-‘ 式) から (要素 -> ‘-‘ 要素) へ変更。
  2. Ring VM - エラーメッセージの改善。
  3. isNULL() 関数のコードを改善。 - ポインタの検査のために更新。
  4. ringvm_evalinscope() 関数のコードを改善。 - トレースライブラリで使用。
  5. Space() 関数のコードを改善。
  6. Hex() および Dec() 関数のコードを改善。
  7. Download() 関数のコードを改善。
  8. SubStr() 関数のコードを改善。
  9. Unsigned() 関数のコードを改善。
  10. Chdir() 関数のコードを改善。
  11. Tempname() 関数のコードを改善。
  12. HashTable コードを改善。 - 新規キー (strdup() の代わりの ring_strdup() 関数の使用)。
  13. 新規関数 : SRandom() - 乱数生成器の初期化。
  14. 新規関数 : IsPointer()
  15. IsPointer() 関数があるため IsList() は C ポインタで True を返さなくなりました。
  16. ringvm_see() 関数に関連した ? 演算子の更新しました。
  17. Ring のテストとして Linux と macOS (Windows だけではない) でのスクリプトの実行。
  18. RingAllegro を Allegro 5.1 から Allegro 5.2 へ更新。
  19. RingAllegro へシェーダー関数を追加。
  20. RingAllegro へジョイスティック関数を追加。
  21. RingLibSDL へネットワーク関数を追加。
  22. 2D ゲームエンジン - Text クラス - 事前に Font オブジェクトの用法を確認してください。
  23. 2D ゲームエンジン - ジョイスティックへの自動対応。
  24. 必要時、 RingLibCurl はCURLOPT_COPYPOSTFIELDS を自動的に使用するように更新しました。
  25. Ring ノートパッド - 前を検索 (Find Previous) 機能。
  26. Ring ノートパッド - 標準スタイル。
  27. Ring ノートパッド - ファイルの名前に非英語文字 (日本語、アラビア語など) を使用可能にするため対応。
  28. フォームデザイナー - ツールボックスアイコンの絶妙な調整。
  29. フォームデザイナー - QAllEvents クラス - マウスのダブルクリックイベント。
  30. ファイルの検索 - 置換および全て置換 (Replace and Replace All) オプション。
  31. 変換結果の改善のために Qt クラスコンバーターを更新。
  32. ring/samples/other フォルダへサンプルを追加。
  33. Ring ノートパッド, RingQt, 2D ゲームエンジンのコードリファクタリング。
  34. 取扱説明書の改善 - 現在の Ring 環境の状況を反映するために画像を多数更新。
  35. 取扱説明書の改善 - 取扱説明書へ章節を追加。