Guest User

Untitled

a guest
May 20th, 2018
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. RGF
  2. ===
  3.  
  4.  
  5. RGF stands fo Recording Game Format. It could be thought of as an extension
  6. to SGF but first note that RGF is _NOT_ backwards compatible to SGF.
  7. To parse an RGF file without using any of the new properties
  8. some modifications to an existing SGF parser might be needed.
  9. So "Extension" would not the most "accurate" word.
  10.  
  11.  
  12. New syntax specification:
  13. -------------------------
  14. The order of properties within a node MUST be preserved.
  15. Inside a node there may be more than one property with the same name and it
  16. may also contain conflicting properties.
  17.  
  18.  
  19. Intended Purpose:
  20. -----------------
  21. The RGF format is intented to be used to allow accurate recording of "game
  22. streams". A game stream should reflect an accurate recording of all
  23. performed changes during the recording time. Hence it is not intended to be
  24. changed after its creation (it is not strictly forbidden either though).
  25.  
  26. If additional variations are added later they could be added on a separate
  27. node outside of the game stream since they are not really part of the
  28. "recording" and timing informations will probably not be important. If
  29. timing informations are important then an additional stream should be
  30. created (since it is based on a new recording). The parts of the tree where
  31. timing informations are not important (i.e. subtrees with no streaming
  32. game-info node) should ideally stick to the classical SGF syntax.
  33.  
  34.  
  35. New properties (they SHOULD only be used inside a "game stream"):
  36. -----------------------------------------------------------------
  37. GS[SOURCE]: Defines a game stream (game-info type).
  38.     SOURCE <string> is the source to be used for the timing of the stream.
  39.     If SOURCE is empty then normal time is used for timing (starting at 0).
  40.     If SOURCE is a web address the media at that address is used for timing
  41.     (this SHOULD be handled very carful if at all to avoid abuses).
  42.     If SOURCE is a filename that file is used for timing (it SHOULD be
  43.     restricted to files in the same directory, again to avoid abuses).
  44.     If the corresponding SOURCE cannot be read properly it should be
  45.     considered as if SOURCE was empty.
  46.  
  47.     TODO: maybe specify further global information here, like the total time.
  48.  
  49. TS[TIME]: Defines timestamps for the preceeding property (resp. node).
  50.     The preceeding property resp. node is called timestamped property (resp. node).
  51.     TIME <double> is a time in seconds. It SHOULD always be non-negative
  52.     and SHOULD NEVER exceed the final time of the corresponding SOURCE
  53.     (if SOURCE is non-empty).
  54.     If a property is not followed by a TS[TIME] we associate TIME=-1 to it
  55.     and consider it to be an "initial", non-timestamped PROPERTY. The
  56.     initial properties SHOULD be consistent with the classical SGF format
  57.     (in particular no conflicts or repetitions).
  58.     Properties for a given node MUST be sorted chronologically (increasing),
  59.     in particular by TIME. Two TIME's from two different nodes SHOULD NEVER be equal
  60.    (except TIME=-1). The TS property SHOULD be ignored if no GS was defined for
  61.    the corresponding game-info node.
  62.    When viewing a the RGF file properties are added resp. overwritten according to
  63.    their timestamp. Later timestamped properties SHOULD override the arguments of
  64.    earlier properties. Except if the argument is a list in which case the new
  65.    arguments are added to that list instead. Also if the property is "C" (comment)
  66.    the new comments are added to the old one.
  67.    Considering this any other conflicts between properties SHOULD
  68.    NEVER occur at any point of time when "following" a game stream.
  69.    So in case of a conflict the RP property has to be used to avoid the conflict.
  70.  
  71.    TODO: what about introducing a convention for the "final" TIME? E.g.
  72.    TIME=-2 (but then it would not be ordered chronologically according to
  73.    the ordering of the real numbers... ^^). All modifications made later on
  74.    could be added to the final time the same way initial changes were just
  75.    "prepended" to the recording.
  76.  
  77. RP[PROPERTY:ARGUMENTS]: Removes the corresponding property or just one list entry of it.
  78.    PROPERTY <string> is the property to be removed/reduced.
  79.    ARGUMENTS is either empty or a comma separated list of arguments with the same type as
  80.    the arguments of the PROPERTY. If ARGUMENTS is empty the whole property is removed.
  81.    If PROPERTY is empty the whole node is removed
  82.    (this SHOULD occur at most once for each stream insde a given node).
  83.    If both PROPERTY and ARGUMENTS are not empty then the list entries
  84.    from ARGUMENTS are removed from PROPERTY. Each entry in ARGUMENTS SHOULD
  85.    be present in the current PROPERTY.
  86.  
  87. RC[CHARS]: Removes the last CHARS <integer> characters from the comments.
  88.  
  89. VT[NAME]: Adds a visual trigger NAME <string>. The handling is up to the
  90.    corresponding applications except for some standard commands below.
  91.    VT SHOULD only effect how the game tree is _displayed_. It SHOULD NOT
  92.    reflect any changes made to the "classical" SGF game tree during
  93.    recording. Each trigger SHOULD be invertible using either
  94.    the same trigger or other triggers.
  95.  
  96.    Here are some basic NAMEs for visual triggers:
  97.        VT[N]: Jump to this node (most important visual trigger).
  98.               Note that the current node position also changes in other
  99.               cases (e.g. when we make a move).
  100.               This trigger is used when the node position is "manually" changed
  101.               (e.g. during naviagion) and to select the initial node position.
  102.  
  103.    Further possible examples might be:
  104.        Switch to the score/edit/etc tool
  105.        mark a stone to be dead/alive in the score tool
  106.  
  107. TODO: maybe add commands for pause/unpause during a recording...
  108.  
  109.  
  110. Example:
  111. --------
  112.  
  113. (;GM[1]FF[4]CA[UTF-8]ST[2]
  114. RU[Japanese]SZ[19]HA[2]KM[0.00]
  115. PW[White]PB[Black]AB[pd][dp]PL[W]
  116.  (
  117.    ;GS[]AN[Jonas]
  118.    ;TS[0]W[pp]TS[0]
  119.    ;TS[3.1]B[dd]TS[3.1]
  120.    ;TS[6.1]W[qf]TS[6.1]
  121.    ;TS[10.3]B[od]TS[10.3]
  122.    ;TS[13.6]W[rd]TS[13.6]
  123.  )
  124.  
  125.  (
  126.    ;GS[review.mp3]AN[Jonas]
  127.    (
  128.        ;W[pp]VT[N]TS[0]
  129.        ;B[dd]VT[N]TS[0.2]
  130.        ;W[qf]VT[N]TS[0.4]
  131.        (
  132.            ;B[od]VT[N]TS[0.6]C[This was a mistake.]TS[7.3]
  133.            ;W[rd]VT[N]TS[7.8]C[...this situation]TS[28.9]
  134.        )
  135.        (
  136.            ;TS[9.2]B[nc]TS[9.2]C[You should play here for example.]TS[12.1]
  137.            ;TS[13]W[rd]TS[13]
  138.            ;TS[14]B[qc]TS[14]
  139.            ;TS[15]W[qi]TS[15]C[Joseki.]TS[22]C[So this is better than...]TS[25.2]
  140.        )
  141.    )
  142.    (
  143.        ;TS[41]AB[pp]TS[41]AB[qp]TS[42]AB[pq]TS[43]AB[qq]TS[44]C[This is an ugly dumpling...]TS[50.2]C[So let's remove it]TS[52]AE[pp]TS[53]AE[qp]TS[54]AE[pq]TS[55]AE[qq]TS[56]
  144.         ;TS[51]W[or]TS[51]
  145.     )
  146.   )
  147.  
  148. )
  149.  
  150.  
  151.  
  152.  
  153. RGT/RGZ:
  154. ========
  155. If an RGF file contains at least one media file the RGF file and all media
  156. files may be stored in a tar file (extracting to the the current
  157. directory). The resulting file file can be given the extension .rgt.
  158.  
  159. If it is further compressed using gzip (.tar.gz) it may be given the
  160. extension .rgz.
  161.  
  162.  
  163.  
  164.  
  165. /*
  166.     RUDIMENTARY PSEUDO-CODE PROTOTYPE
  167.    
  168.     Jonas Jermann <jjermann2@gmail.com>
  169.     (limited/no experience in Java Script and/or software architecture)
  170. */
  171.  
  172.  
  173.  
  174.  
  175. /*  Action
  176.     ------
  177.     Contains all information needed to add a new property and/or node to the game tree.
  178.     It is usually derived from an event from the "go board area" or from the "go variation tree area".
  179.     Another case is when loading (and building up) an RGF file.
  180. */
  181. function Action() {
  182.     this.position; /* node position where to insert the property. This is an array of GameTree (Array) indices,
  183.                       describing how to go through the GameTree up to a certain "node position". */
  184.     this.time; /* time=-1 or time=null or time=undefined (I prefer the last one) if no timestamp */
  185.     this.property; /* Property to be added/changed (see the sgf spec and rgf.txt) */
  186.     this.arguments; /* arguments of the property. */
  187. }
  188.  
  189.  
  190.  
  191.  
  192. /*  GameTree
  193.     --------
  194.     (Already exists?). For storing SGF and RGF trees.
  195.     When modifying/editing the tree a clear distinction should be made between
  196.     modifications to a game stream subtree and normal editing for the remaining parts...
  197.     It also has methods to get the "initial"/starting situation, but no "stream" control is done here...
  198. */
  199. function GameTree(subtree) {
  200. };
  201. GameTree.prototype = inherit(Array.prototype);
  202. GameTree.prototype.constructor = GameTree;
  203. GameTree.prototype.exportToRGF = function() {
  204.     /* exports to RGF. Should provide/ask some options... */
  205. };
  206. GameTree.prototype.exportToSGF = function() {
  207.     /* exports to SGF.
  208.        This leaves the question what to do with the game stream parts.
  209.        One idea is to use the initial or final SGF tree for each game stream.
  210.        Another is to let the user decide at which time he is in each game stream (and
  211.        store this information somewhere). And when exporting use the corresponding
  212.        times as a basis to get the SGF tree/file. */
  213. };
  214. GameTree.prototype.applyAction = function(action,type) {
  215.     /* successively apply all Actions to the Gametree and return the (ordered) list
  216.        of inverse Actions.
  217.              
  218.        There are basically two types: Recording (type=forward or backward) and Editing (type=edit).
  219.        The intention is to use Editing for non game-stream parts and Recording for game-stream parts.
  220.        type=forward:  the actions are assumed to be sorted chronologically,
  221.                       corresponding timestamped properties are inserted from left to right.
  222.                       e.g. this[1][3][4][last_array_length]=";TS[2.1]" (or "C[hi, gg]TS[0.1]")
  223.        type=backward: the actions are assumed to be sorted backward chronologically,
  224.                       corresponding timestamped properties are inserted from right to left.
  225.        type=edit:     apply the property in a classical way (might remove/modify things). */
  226. };
  227.  
  228. GameTree.prototype.getInitialSGFTree = function(game_stream_node) {
  229.     /* Calculates the initial SGF game tree as described in rgf.txt.
  230.        Might e.g. return a list of Actions... */
  231. };
  232. GameTree.prototype.getInitialEditingProperties = function() {
  233.     /* Self-explanatory... */
  234. };
  235.  
  236.  
  237.  
  238.  
  239. /*  EditingProperties
  240.     -----------------
  241.     Stores all required information to give a visual representation of the current situation
  242.     (i.e. go board, variation trees, etc). Note that a different editing mode would most probably
  243.     also change the behaviour/availability of editor tools. But this is a separate issue.
  244.     If we want to record different editing modes we have to keep track of them as well, so this
  245.     should be stored somewhere. Current solution is "this" (probably there are better ways)...
  246. */
  247. function EditingProperties() {
  248.     this.current_position; /* where in the tree are we edditing at the moment,
  249.                               this could be stored as an array of array indices, telling us
  250.                               how to "go through" the GameTree Array... */
  251.     this.editing_mode; /* move, edit/mark/etc, score, print layout, ... */
  252.     /* some other editing properties (?) */
  253. }
  254.  
  255.  
  256. /*  Stream (TODO)
  257.     ------
  258.     with additionall "time callback", "query options", time controls etc.
  259.     This should already be defined in JPlayer or HTML5...
  260.     Actually a callback is not really needed since we regularly update the DisplayStreamWidget anyway,
  261.     maybe using the time information from the stream. But maybe it is still a good idea to use callbacks... */
  262. function Stream() {
  263.     /* ... */
  264.     this.current_time;
  265.     this.playback_speed; /* maybe, to allow fast play */
  266. }
  267. /*  StreamPlayer (TODO)
  268.     ------------
  269.     Do we need an object for the media player?
  270. */
  271. function StreamPlayer { }
  272. /*  RGFParser (TODO)
  273.     ---------
  274.     For parsing RGF and SGF files, almost the same as SGFParser but also supports/parses timestamps
  275.     of properties accordingly (i.e. we consider the timestamp to be part of a property and not a
  276.     "usual" property of itself), see rgf.txt...
  277.     It extends resp. replaces the SGFParser.
  278. */
  279. function RGFParser() {
  280.     /* builds up and returns a GameTree()... */
  281. }
  282.  
  283.  
  284. /*  DisplayBoardWidget
  285.     ------------------
  286.     Something is probably responsible for the _visual representation_ of the current go boaard and its tools (?).
  287.     Probably depends on editing_mode...
  288. */
  289. function DisplayBoardWidget() { }
  290. /*  DisplayVariationsWidget
  291.     -----------------------
  292.     Dito for the variation tree.
  293. */
  294. function DisplayVariationsWidget() { }
  295.  
  296.  
  297.  
  298.  
  299. /*  DisplayStreamWidget
  300.     -------------------
  301.     Contains all necessary information to display an individual stream (given as an argument).
  302.     When it created it will usually only consider the corresponding (game) subtree of the whole tree
  303.     (and thus "forget" the rest).
  304. */
  305. function DisplayStreamWidget(game_stream_node) {
  306.     this.display_board_widget=new DisplayBoardWidget(); /* responsible for the actual drawing (?) */
  307.     this.display_variations_widget= new DisplayVariationsWidget(); /* dito */
  308.     this.gametree=new GameTree(game_stream_node); /* stores all information for this stream, could export to RGF from it */
  309.     this.sgftree=gametree.getInitialSGFTree(); /* stores only relevant SGF data for the current time, could export to SGF from it, might be part of RGFTree?? */
  310.     this.editing_properties=gametree.getInitialEditingProperties(); /* this will be changed automatically based on "visual triggers" during display... */
  311.     this.stream = getStream(); /* associated "stream". It should be loaded according to the argument of GS in the gametree... */
  312.     this._action_list_future; /* has something to do with time, it keeps track of the "to-be-done" actions, allows easy advance(time_step) */
  313.     this._action_list_past; /* has something to do with time, it keeps track of the "already-done" actions, allows easy reverse(time_step) */
  314. }
  315. DisplayStreamWidget.prototype.getStream() {
  316.     /* creates a Stream object corresponding to the GS property of the rgftree */
  317. };
  318. DisplayStreamWidget.prototype.play = function() {
  319.     stream.play();
  320.     /* make sure that "this" is updated regularly and update the visual representation... */
  321. };
  322. DisplayStreamWidget.prototype.stop = function() {
  323.     stream.stop()
  324.     /* stop playback, update the visual representations. Maybe: leave the DisplayStreamWidget and return to the EditWidget... */
  325. };
  326. DisplayStreamWidget.prototype.pause = function() {
  327.     stream.pause();
  328.     /* pause playback, update the visual representation. */
  329. };
  330. DisplayStreamWidget.prototype.applyActions(action_list) {
  331.     action_list.each(function(action) {
  332.         if (action.property="VT") {
  333.             if (action.argument="N") {
  334.                 editing_properties.current_position=action.position;
  335.             } else {
  336.             }
  337.         } else {
  338.             editing_properties.current_position=action.position;
  339.             sgftree.applyAction(action,"edit");
  340.         }
  341.     });
  342. }
  343. /*  user controled, jumps to time in Stream, updates the trees and then the board drawing */
  344. DisplayStreamWidget.prototype.seek = function(time) {
  345.     if (time>=currentediting_properties.current_time) {
  346.         advance(time-currentediting_properties.current_time);
  347.     } else {
  348.         reverse(currentediting_properties.current_time-time);
  349.     }
  350. };
  351. DisplayStreamWidget.prototype.advance = function(time_step) {
  352.     /*  apply all Actions in _action_list_future up to time+time_step,
  353.         store the corresponding inverse Actions in _action_list_past.
  354.         This function should be called quite regularly to give a proper
  355.         update of the "progress bar" and to keep in sync with the stream.
  356.        
  357.         One very precise way to do this is to use a callback function from
  358.         the stream, triggered by the "next" event, or just by some maximal time_step
  359.         (if time_step is bigger than max_time_step). The second condition
  360.         would be used to update the progress bar (since no new Action will happen
  361.         in that case). */
  362.  
  363.     /* this most probably needs fixing... */
  364.     var i=0;
  365.     while (_action_list_future[i].time<editing_properties.current_time+time_step) {
  366.         i=i+1;
  367.     }
  368.     if (_action_list_future[i].time<editing_properties.current_time+time_step) {
  369.         /* apply to sgftree for displaying and store the inverse Actions in the _action_list_past */
  370.         _action_list_past=_action_list_past.concat(applyActions(_action_list_future.slice(0,i)));
  371.     }
  372.     updateDrawing();
  373. };
  374. DisplayStreamWidget.prototype.reverse = function(time_step) {
  375.     /* analogous to advance but we go time_step backward... */
  376.     var i=0;
  377.     while (_action_list_past[i].time>editing_properties.current_time-time_step) {
  378.         i=i+1;
  379.     }
  380.     if (_action_list_past[i].time>editing_properties.current_time-time_step) {
  381.         _action_list_future=_action_list_future.concat(applyActions(_action_list_past.slice(0,i)));
  382.     }
  383.     updateDrawing();
  384. };
  385. /*  updates the visual representation (display_board_widget and display_variations_widget)
  386.     according to sgftree and the editing properties. */
  387. DisplayStreamWidget.prototype.updateDrawing = function() {
  388.     display_board_widget.update(sgftree,editing_properties);
  389.     display_variations_widget.update(sgftree,editing_properties);
  390. };
  391. DisplayStreamWidget.prototype.detach = function() {
  392.     /* TODO: creates new SGF subtree from sgftree and inserts it in the existing BIIG tree,
  393.        at the same level as the current stream node,
  394.        => then leaves(!) DisplayStreamWidget going into SGFEditorWidget at the new positon */
  395. };
  396. DisplayStreamWidget.prototype.exportToRGF = function() {
  397.     /* exports the stream subtree to RGF */
  398.     gametree.exportToRGF();
  399. };
  400. DisplayStreamWidget.prototype.exportToSGF = function() {
  401.     /* epxorts sgftree to SGF; */
  402.     sgftree.exportToSGF();
  403. };
  404. DisplayStreamWidget.prototype.exportToOgg = function() {
  405.     /* creates a "real" movie out of the game stream... */
  406. };
  407.  
  408.  
  409.  
  410.  
  411. /* TODO: EditWidget DisplayWidget and RecordingWidget interplay, applyAction needs access to editing properties... */
  412.  
  413. /*  EditWidget
  414.     ----------
  415.     (already exists) classical sandbox editor, maybe also used for games (spectators), maybe also used for games (players)
  416. */
  417. function EditWidget() {
  418.     /* usual existing parameters/functions */
  419.     this.display_board_widget=new DisplayBoardWidget();
  420.     this.display_variations_widget= new DisplayVariationsWidget();
  421.     this.gametree;
  422.     this.editing_properties; /* see above, note that these _are_ changed by the user... */
  423.     this._action_list_future; /* (optional) has nothing to do with time, just to be able to redo */
  424.     this._action_list_past; /* (optional) has nothing to do with time, just to be able to undo */
  425. }
  426. EditWidget.prototype.updateDrawing = function() {
  427.     display_board_widget.update(gametree,editing_properties);
  428.     display_variations_widget.update(gametree,editing_properties);
  429. };
  430.  
  431. EditWidget.prototype.jump_to_node = function(position) {
  432.     editing_properties.current_position=position;
  433.     updateDrawing();
  434. };
  435. EditWidget.prototype.jump_to_stream = function(stream_node) {
  436.     editing_properties.current_position=stream_node;
  437.     /* most probably the editor window will look slightly different, when we are over a
  438.        game stream node. One idea is to directly create/jump to a DisplayStreamWidget... */
  439.     updateDrawing();
  440. };
  441. EditWidget.prototype.play_stream = function(stream_node) {
  442.     /* Creates/Jumps to a DisplayStreamWidget(stream_node). Also see jump_to_stream. */
  443. };
  444. EditWidget.prototype.insertGameTree = function(rgftree,position) {
  445.     /* Adds rgftree to position of the given gametree. */
  446. };
  447.  
  448. EditWidget.prototype.startRecording = function() {
  449.     /* First creates a copy of the variation tree corresponding to the current position and uses
  450.        it to start a RecordingWidget. */
  451. };
  452. EditWidget.prototype.stopRecording = function() {
  453.     /* Inserts the so far created rgf GameTree at the position where the recording was started.
  454.        Should this be defined/done in RecordingWidget? */
  455. EditWidget.prototype.pauseRecording = function() {}; /* maybe, needs some additional work to make this possible */
  456. EditWidget.prototype.resumeRecording = function() {}; /* dito */
  457.  
  458. EditWidget.prototype.applyActions(action_list) {
  459.     action_list.each(function(action) {
  460.         /* no VT property should occur anyway for non game stream parts... */
  461.         editing_properties.current_position=action.position;
  462.         gametree.applyAction(action,"edit");
  463.     });
  464. }
  465.  
  466. EditWidget.prototype.undo() {
  467.     /* This could be done in a similar fashion as "reverse" in DisplayStreamWidget */
  468. }
  469. EditWidget.prototype.redo() {
  470.     /* This could be done in a similar fashion as "advance" in DisplayStreamWidget */
  471. }
  472. EditWidget.prototype.changeEditingMode = function(new_mode) {
  473.     /* editing, moving, scoring, etc... */
  474.     editing_properties.editing_mode=new_mode;
  475.     updateDrawing();
  476. }
  477. EditWidget.prototype.exportToRGF = function() {
  478.     gametree.exportToRGF();
  479. };
  480. EditWidget.prototype.exportToSGF = function() {
  481.     gametree.exportToSGF();
  482. };
  483.  
  484.  
  485.  
  486.  
  487. /*  RecordingWidget
  488.     ---------------
  489.     Handles the recording of a lecture to a supplied game stream gametree.
  490. */
  491. function RecordingWidget(new_gametree) {
  492.     this.gametree=new_gametree;
  493.     this.rgftree; /* additional tree to keep track of the recording data. When the recording is finnished this tree will be inserted
  494.                      in the big (overall) gametree... */
  495.     this.stream; /* should be initialized for time control/etc */
  496.     /* this._action_list_future: as before, but this time the time matters but for recording we actually don't need it!
  497.        this._action_list_past: dito */
  498. }
  499.  
  500. /* inherited from EditWidget... */
  501. RecordingWidget.prototype = inherit(EditWidget.prototype);
  502. RecordingWidget.prototype.constructor = RecordingWidget;
  503.  
  504. /* ...but override some functions. E.g.: */
  505. RecordingWidget.prototype.updateVariationTreeDrawing = function() {
  506.     /* as above, only now we actually see the current variation tree */
  507.  
  508. RecordingWidget.prototype.applyActions(action_list) {
  509.     action_list.each(function(action) {
  510.         if (action.property="VT") {
  511.             if (action.argument="N") {
  512.                 editing_properties.current_position=action.position;
  513.             } else {
  514.             }
  515.             rgftree.applyAction(action,"forward");
  516.         } else {
  517.             editing_properties.current_position=action.position;
  518.             gametree.applyAction(action,"edit");
  519.             rgftree.applyAction(action,"forward");
  520.         }
  521.     });
  522. }
Add Comment
Please, Sign In to add comment