Goto Chapter: Top 1 2 3 4 5 6 A Bib Ind
[Top of Book] [Contents] [Previous Chapter] [Next Chapter]

[MathJax on]

6 Examples of Applications based on `NCurses.BrowseGeneric`
6.1 The Operation `Browse`
6.1-1 Browse
6.2 Matrix Display
6.2-1 NCurses.BrowseDenseList
6.2-2 Browse
6.3 Character Table Display
6.3-1 Browse
6.3-2 BrowseDecompositionMatrix
6.4 Table of Marks Display
6.4-1 Browse
6.5 Table of Contents of AtlasRep
6.5-1 BrowseAtlasInfo
6.6 Access to GAP Manuals–a Variant
6.6-1 BrowseGapManuals
6.7 Overview of Bibliographies
6.7-1 BrowseBibliography
6.7-2 BrowseBibliographyGapPackages
6.7-3 BrowseMSC
6.8 Profiling GAP functions–a Variant
6.8-1 BrowseProfile
6.9 Variables defined in GAP packages–a Variant
6.9-1 BrowsePackageVariables
6.10 Configuring User preferences–a Variant
6.10-1 BrowseUserPreferences
6.11 Overview of GAP Data
6.11-1 BrowseGapData
6.11-2 BrowseGapDataAdd
6.12 Navigating in a Directory Tree
6.12-1 BrowseDirectory
6.13 A Puzzle
6.13-1 BrowsePuzzle
6.14 Peg Solitaire
6.14-1 PegSolitaire
6.15 Rubik's Cube
6.15-1 BrowseRubiksCube
6.16 Changing Sides
6.16-1 BrowseChangeSides
6.17 Sudoku
6.17-1 Sudoku.Init
6.17-2 Sudoku.Place
6.17-3 Sudoku.RandomGame
6.17-4 Sudoku.SimpleDisplay
6.17-5 Sudoku.DisplayString
6.17-6 Sudoku.OneSolution
6.17-7 Sudoku.UniqueSolution
6.17-8 PlaySudoku
6.17-9 Sudoku.HTMLGame
6.18 Utility for GAP Demos
6.18-1 LoadDemoFile

### 6 Examples of Applications based on `NCurses.BrowseGeneric`

This chapter introduces the operation `Browse` (6.1-1) and lists several examples how the function `NCurses.BrowseGeneric` (4.3-1) can be utilized for rendering GAP related data or for playing games. Each section describes the relevant GAP functions and briefly sketches the technical aspects of the implementation; more details can be found in the GAP files, in the `app` directory of the package.

Only Section 6.4 describes a standard application in the sense of the introduction to Chapter 4, perhaps except for a special function that is needed to compare table entries. The other examples in this chapter require some of the programming described in Chapter 5.

The GAP examples in this chapter use the "replay" feature of `NCurses.BrowseGeneric` (4.3-1), see Section 4.1. This means that the `NCurses.BrowseGeneric` (4.3-1) based function is called between two calls of `BrowseData.SetReplay` (5.4-2). If you want to paste these examples into the GAP session with the mouse then do not paste the final `BrowseData.SetReplay` (5.4-2) call, since `NCurses.BrowseGeneric` (4.3-1) would regard the additional input as a user interrupt.

#### 6.1 The Operation `Browse`

##### 6.1-1 Browse

`‣ Browse`( obj[, arec] ) | ( operation )

This operation displays the GAP object obj in a nice, formatted way, similar to the operation `Display` (Reference: Display). The difference is that `Browse` is intended to use `ncurses` facilities.

Currently there are methods for matrices (see `Browse` (6.2-2)), for character tables (see `Browse` (6.3-1)) and for tables of marks (see `Browse` (6.4-1)).

#### 6.2 Matrix Display

The GAP library provides several `Display` (Reference: Display) methods for matrices. In order to cover the functionality of these methods, Browse provides the function `NCurses.BrowseDenseList` (6.2-1) that uses the standard facilities of the function `NCurses.BrowseGeneric` (4.3-1), i. e., one can scroll in the matrix, searching and sorting are provided etc.

The idea is to customize this function for different special cases, and to install corresponding `Browse` (6.1-1) methods. Examples are methods for matrices over finite fields and residue class rings of the rational integers, see `Browse` (6.2-2).

The code can be found in the file `app/matdisp.g` of the package.

##### 6.2-1 NCurses.BrowseDenseList

`‣ NCurses.BrowseDenseList`( list, arec ) | ( function )

Returns: nothing.

Let list be a dense list whose entries are lists, for example a matrix, and let arec be a record. This function displays list in a window, as a two-dimensional array with row and column positions as row and column labels, respectively.

The following components of arec are supported.

`header`

  If bound, the value must be a valid value of the `work.header` component of a browse table, see `BrowseData.IsBrowseTable` (4.2-3); for example, the value can be a list of strings. If this component is not bound then the browse table has no header.

`footer`

  If bound, the value must be a valid value of the `work.footer` component of a browse table, see `BrowseData.IsBrowseTable` (4.2-3); for example, the value can be a list of strings. If this component is not bound then the browse table has no footer.

`convertEntry`

  If bound, the value must be a unary function that returns a string describing its argument. The default is the operation `String` (Reference: String). Another possible value is `NCurses.ReplaceZeroByDot`, which returns the string `"."` if the argument is a zero element in the sense of `IsZero` (Reference: IsZero), and returns the `String` (Reference: String) value otherwise. For each entry in a row of list, the `convertEntry` value is shown in the browse table.

`labelsRow`

  If bound, the value must be a list of row label rows for list, as described in Section `BrowseData.IsBrowseTable` (4.2-3). The default is `[ [ "1" ], [ "2" ], ... ]`.

`labelsCol`

  If bound, the value must be a list of column label rows for list, as described in Section `BrowseData.IsBrowseTable` (4.2-3). The default is `[ [ "1", "2", ... ] ]`.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

##### 6.2-2 Browse

`‣ Browse`( list ) | ( method )

Returns: nothing.

Several methods for the operation `Browse` (6.1-1) are installed for the case that the argument is a list of lists. These methods cover a default method for lists of lists and the `Display` (Reference: Display) methods for matrices over finite fields and residue class rings of the rational integers. Note that matrices over finite prime fields, small extension fields, and large extension fields are displayed differently, and the same holds for the corresponding `Browse` (6.1-1) methods.

    gap> n:= [ 14, 14, 14, 14 ];;
    gap> input:= Concatenation( n, n, n, "Q" );;  # ``do nothing and quit''
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, Integers ) );
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, GF(3) ) );
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, GF(4) ) );
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, Integers mod 6 ) );
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, GF( NextPrimeInt( 2^16 ) ) ) );
    gap> BrowseData.SetReplay( input );
    gap> Browse( RandomMat( 10, 10, GF( 2^20 ) ) );
    gap> BrowseData.SetReplay( false );

#### 6.3 Character Table Display

The GAP library provides a `Display` (Reference: Display) method for character tables that breaks the table into columns fitting on the screen. Browse provides an alternative, using the standard facilities of the function `NCurses.BrowseGeneric` (4.3-1), i. e., one can scroll in the matrix of character values, searching and sorting are provided etc.

The `Browse` (6.1-1) method for character tables can be called instead of `Display` (Reference: Display). For convenience, one can additionally make this function the default `Display` (Reference: Display) method for character tables, by assigning it to the `Display` component in the global record `CharacterTableDisplayDefaults.User`, see Reference: Printing Character Tables; for example, one can do this in one's `gaprc` file, see Reference: The gap.ini and gaprc files. (This can be undone by unbinding the component `CharacterTableDisplayDefaults.User.Display`.)

The function `BrowseDecompositionMatrix` (6.3-2) can be used to display decomposition matrices for Brauer character tables.

##### 6.3-1 Browse

`‣ Browse`( tbl[, options] ) | ( method )

This method displays the character table tbl in a window. The optional record options describes what shall be displayed, the supported components and the default values are described in Reference: Printing Character Tables.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> if TestPackageAvailability( "CTblLib" ) = true then
    >      BrowseData.SetReplay( Concatenation(
    >         # scroll in the table
    >         "DRULdddddrrrrrlluu",
    >         # select an entry and move it around
    >         "seddrruuuddlll",
    >         # search for the pattern 135 (six times)
    >         "/135", [ NCurses.keys.ENTER ], "nnnnn",
    >         # deselect the entry, select the first column
    >         "qLsc",
    >         # sort and categorize by this column
    >         "sc",
    >         # select the first row, move down the selection
    >         "srdddd",
    >         # expand the selected category, scroll the selection down
    >         "xd",
    >         # and quit the application
    >         "Q" ) );
    >      Browse( CharacterTable( "HN" ) );
    >      BrowseData.SetReplay( false );
    > fi;

Implementation remarks: The first part of the code in the `Browse` (6.1-1) method for character tables is almost identical with the code for extracting the data to be displayed from the input data in the GAP library function `CharacterTableDisplayDefault`. The second part of the code transforms these data into a browse table. Character names and (if applicable) indicator values are used as row labels, and centralizer orders, power maps, and class names are used as column labels. The identifier of the table is used as the static header. When an irrational entry is selected, a description of this entry is shown in the dynamic footer.

The standard modes in `BrowseData` (5.4-1) (except the `help` mode) have been extended by three new actions. The first two of them open pagers giving an overview of all irrationalities in the table, or of all those irrationalities that have been shown on the screen in the current call, respectively. The corresponding user inputs are the I and the i key. (The names assigned to the irrationalities are generated column-wise. If one just scrolls through the table, without jumping, then these names coincide with the names generated by the default `Display` (Reference: Display) method for character tables; this is in general not the case, for example when a row-wise search in the table is performed.) The third new action, which is associated with the p key, toggles the visibility status of the column label rows for centralizer orders and power maps.

An individual `minyx` function does not only check whether the desired table fits into the window but also whether a table with too high column labels (centralizer orders and power maps) would fit if these labels get collapsed via the p key. In this case, the labels are automatically collapsed, and the p key is disabled.

In order to keep the required space small also for large character tables, caching of formatted matrix entries is disabled, and the strings to be displayed are computed on demand with a `Main` function in the `work` component of the browse table. For the same reason, the constant height one for all table rows is set in advance, so one need not inspect a whole character if only a few values of it shall be shown.

Special functions are provided for sorting (concerning the comparison of character values, which can be integers or irrationalities) and categorizing the table by a column (the value in the category row involves the class name of the column in question).

The code can be found in the file `app/ctbldisp.g` of the package.

##### 6.3-2 BrowseDecompositionMatrix

`‣ BrowseDecompositionMatrix`( modtbl[, b][, options] ) | ( function )

This method displays the decomposition matrix of (the b-th block of) the Brauer character table modtbl in a window. The arguments are the same as for `LaTeXStringDecompositionMatrix` (Reference: LaTeXStringDecompositionMatrix).

The positions of the ordinary and modular irreducible characters are shown in the labels of the rows and columns, respectively, that are indexed by these characters. When an entry in the decomposition matrix is selected then information about the degrees of these characters is shown in the table footer.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> BrowseData.SetReplay( Concatenation(
    >         # select the first entry
    >         "se",
    >         # scroll in the table
    >         "drrrr",
    >         # keep the table open for a while
    >         [ 14, 14, 14, 14, 14 ],
    >         # and quit the application
    >         "Q" ) );
    gap> BrowseDecompositionMatrix( CharacterTable( "J1" ) mod 2 );
    gap> BrowseData.SetReplay( false );

The code can be found in the file `app/ctbldisp.g` of the package.

#### 6.4 Table of Marks Display

The GAP library provides a `Display` (Reference: Display) method for tables of marks that breaks the table into columns fitting on the screen. Similar to the situation with character tables, see Section 6.3, but with a much simpler implementation, Browse provides an alternative based on the function `NCurses.BrowseGeneric` (4.3-1).

`Browse` (6.1-1) can be called instead of `Display` (Reference: Display) for tables of marks, cf. Reference: Printing Tables of Marks.

##### 6.4-1 Browse

`‣ Browse`( tom[, options] ) | ( method )

This method displays the table of marks tom in a window. The optional record options describes what shall be displayed, the supported components and the default values are described in Reference: Printing Tables of Marks.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> if TestPackageAvailability( "TomLib" ) = true then
    >      BrowseData.SetReplay( Concatenation(
    >         # scroll in the table
    >         "DDRRR",
    >         # search for the (exact) value 100 (three times)
    >         "/100",
    >         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.RIGHT ],
    >         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.DOWN ],
    >         [ NCurses.keys.RIGHT, NCurses.keys.ENTER ], "nn",
    >         # no more occurrences of 100, confirm
    >         [ NCurses.keys.ENTER ],
    >         # and quit the application
    >         "Q" ) );
    >      Browse( TableOfMarks( "A10" ) );
    >      BrowseData.SetReplay( false );
    >    fi;

Implementation remarks: Rows and columns are indexed by their positions. The identifier of the table is used as the static header, there is no footer.

In order to keep the required space small also for large tables of marks, caching of formatted matrix entries is disabled, and the strings to be displayed are computed on demand with a `Main` function in the `work` component of the browse table. For the same reason, the constant height one for the table rows is set in advance. (For example, the table of marks of the group with identifier `"O8+(2)"`, with 11171 rows and columns, can be shown with `Browse` (6.1-1) in a GAP session requiring about 100 MB.)

The code can be found in the file `app/tomdisp.g` of the package.

#### 6.5 Table of Contents of AtlasRep

The GAP package AtlasRep (see [WPN+19]) is an interface to a database of representations and related data. The table of contents of this database can be displayed via the function `DisplayAtlasInfo` (AtlasRep: DisplayAtlasInfo) of this package. The Browse package provides an alternative based on the function `NCurses.BrowseGeneric` (4.3-1); one can scroll, search, and fetch data for later use.

##### 6.5-1 BrowseAtlasInfo

`‣ BrowseAtlasInfo`( [listofnames][,] ["contents", sources][,] [...] ) | ( function )

`‣ BrowseAtlasInfo`( gapname[, std][, ...] ) | ( function )

Returns: the list of "clicked" info records.

This function shows the information available via the GAP package AtlasRep in a browse table, cf. Section AtlasRep: Accessing Data via AtlasRep in the AtlasRep manual.

The optional arguments can be used to restrict the table to core data or data extensions, or to show an overview for one particular group. The arguments are the same as for `DisplayAtlasInfo` (AtlasRep: DisplayAtlasInfo), see the documentation of this function for details. (Note that additional conditions such as `IsPermGroup` (Reference: IsPermGroup) can be entered also in the case that no gapname is given. In this situation, the additional conditions are evaluated for the "second level tables" that are opened by "clicking" on a table row or entry.)

When one "clicks" on one of the table rows or entries then a browse table with an overview of the information available for this group is shown, and "clicking" on one of the rows in these tables adds the corresponding info record (see `OneAtlasGeneratingSetInfo` (AtlasRep: OneAtlasGeneratingSetInfo)) to the list of return values of `BrowseAtlasInfo`.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

The following example shows how `BrowseAtlasInfo` can be used to fetch info records about permutation representations of the alternating groups A_5 and A_6: We search for the group name `"A5"` in the overview table, and the first cell in the table row for A_5 becomes selected; hitting the Enter key causes a new window to be opened, with an overview of the data available for A_5; moving down two rows and hitting the Enter key again causes the second representation to be added to the result list; hitting Q closes the second window, and we are back in the overview table; we move the selection down twice (to the row for the group A_6), and choose the first representation for this group; finally we leave the table, and the return value is the list with the data for the two representations.

    gap> d:= [ NCurses.keys.DOWN ];;  r:= [ NCurses.keys.RIGHT ];;
    gap> c:= [ NCurses.keys.ENTER ];;
    gap> BrowseData.SetReplay( Concatenation(
    >        "/A5",         # Find the string A5 ...
    >        d, d, r,       # ... such that just the word matches,
    >        c,             # start the search,
    >        c,             # click the table entry A5,
    >        d, d,          # move down two rows,
    >        c,             # click the row for this representation,
    >        "Q",           # quit the second level table,
    >        d, d,          # move down two rows,
    >        c,             # click the table entry A6,
    >        d,             # move down one row,
    >        c,             # click the first row,
    >        "Q",           # quit the second level table,
    >        "Q" ) );       # and quit the application.
    gap> if IsBound( BrowseAtlasInfo ) and IsBound( AtlasProgramInfo ) then
    >      SetUserPreference( "AtlasRep", "AtlasRepMarkNonCoreData", "" );
    >      tworeps:= BrowseAtlasInfo();
    >    else
    >      tworeps:= [ fail ];
    >    fi;
    gap> BrowseData.SetReplay( false );
    gap> if fail in tworeps then
    >      Print( "no access to the Web ATLAS\n" );
    >    else
    >      Print( List( tworeps, x -> x.identifier[1] ), "\n" );
    >    fi;
    [ "A5", "A6" ]

Implementation remarks: The first browse table shown has a static header, no footer and row labels, one row of column labels describing the type of data summarized in the columns.

Row and column separators are drawn as grids (cf. `NCurses.Grid` (2.2-8)) composed from the special characters described in Section 2.1-6, using the component `work.SpecialGrid` of the browse table, see `BrowseData` (5.4-1).

When a row is selected, the "click" functionality opens a new window (via a second level call to `NCurses.BrowseGeneric` (4.3-1)), in which a browse table with the list of available data for the given group is shown; in this table, "click" results in adding the info for the selected row to the result list, and a message about this addition is shown in the footer row. One can choose further data, return to the first browse table, and perhaps iterate the process for other groups. When the first level table is left, the list of info records for the chosen data is returned.

For the two kinds of browse tables, the standard modes in `BrowseData` (5.4-1) (except the `help` mode) have been extended by a new action that opens a pager giving an overview of all data that have been chosen in the current call. The corresponding user input is the Y key.

This function is available only if the GAP package AtlasRep is available.

The code can be found in the file `app/atlasbrowse.g` of the package.

#### 6.6 Access to GAP Manuals–a Variant

A Browse adapted way to access several manuals is to show the hierarchy of books, chapters, sections, and subsections as collapsible category rows, and to regard the contents of each subsection as a data row of a matrix with only one column.

This application is mainly intended as an example with table cells that exceed the screen, and as an example with several category levels.

##### 6.6-1 BrowseGapManuals

`‣ BrowseGapManuals`( [start] ) | ( function )

This function displays the contents of the GAP manuals (the main GAP manuals as well as the loaded package manuals) in a window. The optional argument start describes the initial status, admissible values are the strings `"inline/collapsed"`, `"inline/expanded"`, `"pager/collapsed"`, and `"pager/expanded"`.

In the `inline` cases, the parts of the manuals are shown in the browse table, and in the `pager` case, the parts of the manuals are shown in a different window when they are "clicked", using the user's favourite help viewer, see Reference: Changing the Help Viewer.

In the `collapsed` cases, all category rows are collapsed, and the first row is selected; typical next steps are moving down the selection and expanding single category rows. In the `expanded` cases, all category rows are expanded, and nothing is selected; a typical next step in the `inline/expanded` case is a search for a string in the manuals. (Note that searching in quite slow: For viewing a part of a manual, the file with the corresponding section is read into GAP, the text is formatted, the relevant part is cut out from the section, perhaps markup is stripped off, and finally the search is performed in the resulting strings.)

If no argument is given then the user is asked for selecting an initial status, using `NCurses.Select` (3.1-2).

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
    gap> BrowseData.SetReplay( Concatenation(
    >        "xdxd",                             # expand a Tutorial section
    >        n, "Q" ) );                         # and quit
    gap> BrowseGapManuals( "inline/collapsed" );
    gap> BrowseData.SetReplay( Concatenation(
    >        "/Browse", [ NCurses.keys.ENTER ],  # search for "Browse"
    >        "xdxddxd",                          # expand a section
    >        n, "Q" ) );                         # and quit
    gap> BrowseGapManuals( "inline/collapsed" );
    gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header showing the name of the currently selected manual, no footer, no row or column labels, and exactly one column of fixed width equal to the screen width. The category rows are precomputed, i. e., they do not arise from a table column; this way, the contents of each data cell can be computed on demand, as soon as it is shown on the screen, in particular the category hierarchy is computed without reading the manuals into GAP. Also, the data rows are not cached. There is no return value. The heights of many cells are bigger than the screen height, so scrolling is a mixture of scrolling to the next cell and scrolling inside a cell. The different initial states are realized via executing different initial steps before the table is shown to the user.

For the variants that show the manuals in a pager, the code temporarily replaces the `show` function of the default viewer `"screen"` (see Reference: Changing the Help Viewer) by a function that uses `NCurses.Pager` (3.1-4). Note that in the case that the manual bit in question fits into one screen, the default `show` function writes this text directly to the screen, but this is used already by the browse table.

The implementation should be regarded as a sketch.

For example, the markup available in the text file format of GAPDoc manuals (using Esc sequences) is stripped off instead of being transferred to the attribute lines that arise, because of the highlighting problem mentioned in Section 2.2-3.

Some heuristics used in the code are due to deficiencies of the manual formats.

For the inline variant of the browse table, the titles of chapters, sections, and subsections are not regarded as parts of the actual text since they appear already as category rows; however, the functions of the GAP help system deliver the text together with these titles, so these lines must be stripped off afterwards.

The category hierarchy representing the tables of contents is created from the `manual.six` files of the manuals. These files do not contain enough information for determining whether several functions define the same subsection, in the sense that there is a common description text after a series of manual lines introducing different functions. In such cases, the browse table contains a category row for each of these functions (with its own number), but the corresponding text appears only under the last of these category rows, the data rows for the others are empty. (This problem does not occur in the GAPDoc manual format because this introduces explicit subsection titles, involving only the first of several function definitions.)

Also, index entries and sectioning entries in `manual.six` files of manuals in GAPDoc format are not explicitly distinguished.

The code can be found in the file `app/manual.g` of the package.

#### 6.7 Overview of Bibliographies

The function `BrowseBibliography` (6.7-1) can be used to turn the contents of bibliography files in BibTeX or BibXMLext format (see GAPDoc: The BibXMLext Format) into a Browse table, such that one can scroll in the list, search for entries, sort by year, sort and categorize by authors etc.

The default bibliography used by `BrowseBibliography` (6.7-1) is the bibliography of GAP related publications, see [GAP]. The Browse package contains a (perhaps outdated) version of this bibliography. One can get an updated version as follows.

`wget -N http://www.gap-system.org/Doc/Bib/gap-publishednicer.bib`

The columns of the Browse table that is shown by `BrowseBibliography` (6.7-1) can be customized, two examples for that are given by the functions `BrowseBibliographySporadicSimple` (AtlasRep: BrowseBibliographySporadicSimple) and `BrowseBibliographyGapPackages` (6.7-2).

The function `BrowseMSC` (6.7-3) shows an overview of the AMS Mathematics Subject Classification codes.

##### 6.7-1 BrowseBibliography

`‣ BrowseBibliography`( [bibfiles] ) | ( function )

Returns: a record as returned by `ParseBibXMLExtFiles` (GAPDoc: ParseBibXMLextFiles).

This function shows the list of bibliography entries in the files given by bibfiles, which may be a string or a list of strings (denoting a filename or a list of filenames, respectively) or a record (see below for the supported components).

If no argument is given then the file `bibl/gap-publishednicer.bib` in the Browse package directory is taken, and `"GAP Bibliography"` is used as the header.

Another perhaps interesting data file that should be available in the GAP distribution is `doc/manualbib.xml`. This file can be located as follows.

    gap> file:= Filename( DirectoriesLibrary( "doc" ), "manualbib.xml" );;

Both BibTeX format and the XML based extended format provided by the GAPDoc package are supported by `BrowseBibliography`, see Chapter GAPDoc: Utilities for Bibliographies.

In the case of BibTeX format input, first a conversion to the extended format takes place, via `StringBibAsXMLext` (GAPDoc: StringBibAsXMLext) and `ParseBibXMLextString` (GAPDoc: ParseBibXMLextString). Note that syntactically incorrect entries are rejected in this conversion –this is signaled with `InfoBibTools` (GAPDoc: InfoBibTools) warnings– and that only a subset of the possible LaTeX markup is recognized –other markup appears in the browse table except that the leading backslash is removed.

In both cases of input, the problem arises that in visual mode, currently we can show only ASCII characters (and the symbols in `NCurses.lineDraw`, but these are handled differently, see Section 2.1-6). Therefore, we use the function `SimplifiedUnicodeString` (GAPDoc: SimplifiedUnicodeString) for replacing other unicode characters by ASCII text.

The return value is a record as returned by `ParseBibXMLExtFiles` (GAPDoc: ParseBibXMLextFiles), its `entries` component corresponds to the bibliography entries that have been "clicked" in visual mode. This record can be used as input for `WriteBibFile` (GAPDoc: WriteBibFile) or `WriteBibXMLextFile` (GAPDoc: WriteBibXMLextFile), in order to produce a bibliography file, or it can be used as input for `StringBibXMLEntry` (GAPDoc: StringBibXMLEntry), in order to produce strings from the entries, in various formats.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> # sort and categorize by year, scroll down, expand a category row
    gap> BrowseData.SetReplay( "scrrscsedddddxdddddQ" );
    gap> BrowseBibliography();;
    gap> # sort & categorize by authors, expand all category rows, scroll down
    gap> BrowseData.SetReplay( "scscXseddddddQ" );
    gap> BrowseBibliography();;
    gap> # sort and categorize by journal, search for a journal name, expand
    gap> BrowseData.SetReplay( Concatenation( "scrrrsc/J. Algebra",
    >        [ NCurses.keys.ENTER ], "nxdddQ" ) );
    gap> BrowseBibliography();;
    gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header (showing the number of entries, which can vary when the table is restricted), no footer and row labels; one row of column labels is given by the descriptions of the table columns (authors, title, year, journal, MSC code).

Row and column separators are drawn as grids (cf. `NCurses.Grid` (2.2-8)) composed from the special characters described in Section 2.1-6, using the component `work.SpecialGrid` of the browse table, see `BrowseData` (5.4-1).

For categorizing by authors (or by MSC codes), the sort parameter `"split rows on categorizing"` is set to `"yes"`, so the authors (codes) are distributed to different category rows, hence each entry appears once for each of its authors (or its MSC codes) in the categorized table. When a data row or an entry in a data row is selected, "click" adds the corresponding bibliographhy entry to the result.

The width of the title column is preset; usually titles are too long for one line, and the contents of this column is formatted as a paragraph, using the function `FormatParagraph` (GAPDoc: FormatParagraph). For the authors and journal columns, maximal widths are prescribed, and `FormatParagraph` (GAPDoc: FormatParagraph) is used for longer entries.

For four columns, the sort parameters are defined as follows: The authors and MSC code columns do not become hidden when the table is categorized according to this column, sorting by the year yields a descending order, and the category rows arising from these columns and the journal column show the numbers of the data rows that belong to them.

Those standard modes in `BrowseData` (5.4-1) where an entry or a row of the table is selected have been extended by three new actions, which open a pager showing the BibTeX, HTML, and Text format of the selected entry, respectively. The corresponding user inputs are the vb, vh, and vt. If the MSC code column is available then also the user input vm is admissible; it opens a pager showing the descriptions of the MSC codes attached to the selected entry.

This function requires some of the utilities provided by the GAP package GAPDoc (see [LN07]), such as `FormatParagraph` (GAPDoc: FormatParagraph), `NormalizeNameAndKey` (GAPDoc: NormalizeNameAndKey), `NormalizedNameAndKey` (GAPDoc: NormalizedNameAndKey), `ParseBibFiles` (GAPDoc: ParseBibFiles), `ParseBibXMLextFiles` (GAPDoc: ParseBibXMLextFiles), `ParseBibXMLextString` (GAPDoc: ParseBibXMLextString), `RecBibXMLEntry` (GAPDoc: RecBibXMLEntry), and `StringBibAsXMLext` (GAPDoc: StringBibAsXMLext).

The code can be found in the file `app/gapbibl.g` of the package.

The browse table can be customized by entering a record as the argument of `BrowseBibliography`, with the following supported components.

`files`

  a nonempty list of filenames containing the data to be shown; there is no default for this component.

`filesshort`

  a list of the same length as the `files` component, the entries are strings which are shown in the `"sourcefilename"` column of the table (if this column is present); the default is the list of filenames.

`filecontents`

  a list of the same length as the `files` component, the entries are strings which are shown as category values when the table is categorized by the `"sourcefilename"` column; the default is the list of filenames.

`header`

  is the constant part of the header shown above the browse table, the default is the first filename.

`columns`

  is a list of records that are valid as the second argument of `DatabaseAttributeAdd` (A.1-5), where the first argument is a database id enumerator created from the bibliography entries in the files in question. Each entry (and also the corresponding identifier) of this database id enumerator is a list of records obtained from `ParseBibXMLextFiles` (GAPDoc: ParseBibXMLextFiles) and `RecBibXMLEntry` (GAPDoc: RecBibXMLEntry), or from `ParseBibFiles` (GAPDoc: ParseBibFiles), such that the list elements are regarded as equal, in the sense that their fingerprints (see below) are equal. The records in the `columns` list are available for constructing the desired browse table, the actual appearance is controlled by the `choice` component described below. Columns showing authors, title, year, journal, MSC code, and filename are predefined and need not be listed here.

`choice`

  a list of strings denoting the `identifier` components of those columns that shall actually be shown in the table, the default is `[ "authors", "title", "year", "journal", "mrclass" ]`.

`fingerprint`

  a list of strings denoting component names of the entries of the database id enumerator that is constructed from the data (see above); two data records are regarded as equal if the values of these components are equal; the default is `[ "mrnumber", "title", "authorAsList", "editorAsList", "author" ]`.

`sortKeyFunction`

  either `fail` or a function that takes a record as returned by `RecBibXMLEntry` (GAPDoc: RecBibXMLEntry) and returns a list that is used for comparing and thus sorting the records; the default is `fail`, which means that the rows of the table appear in the same ordering as in the source files.

##### 6.7-2 BrowseBibliographyGapPackages

`‣ BrowseBibliographyGapPackages`( ) | ( function )

Returns: a record as returned by `BrowseBibliography` (6.7-1).

This function collects the information from the `*.bib` and `*bib.xml` files in those subdirectories of installed GAP packages which contain the package documentation, and shows it in a Browse table, using the function `BrowseBibliography` (6.7-1).

This function is experimental. The result is not really satisfactory, for the following reasons.

- Duplicate entries may occur, due to subtle differences in various source files.

- The source files may contain more than what is actually cited in the package manuals.

- It may happen that some `*.bib` or `*bib.xml` file is accidentally distributed with the package but is not intended to serve as package bibliography.

- The heuristics for rewriting LaTeX code is of course not perfect; thus strange symbols may occur in the Browse table.

##### 6.7-3 BrowseMSC

`‣ BrowseMSC`( [version] ) | ( function )

Returns: nothing.

This function shows the valid MSC codes in a browse table that is categorized by the `..-XX` and the `...xx` codes. (Use X for expanding all categories or x for expanding the currently selected category.) Due to the categorization, only two columns of the table are visible, showing the codes and their descriptions.

If version is given then it must be one of the numbers 2010 or 2020, meaning that the MSC2010 or MSC2020 codes are shown; the default for version is 2020.

#### 6.8 Profiling GAP functions–a Variant

A Browse adapted way to evaluate profiling results is to show the overview that is printed by the GAP function `DisplayProfile` (Reference: DisplayProfile) in a Browse table, which allows one to sort the profiled functions according to the numbers of calls, the time spent, etc., and to search for certain functions one is interested in.

##### 6.8-1 BrowseProfile

`‣ BrowseProfile`( [functions][,] [mincount, mintime] ) | ( function )

The arguments and their meaning are the same as for the function `DisplayProfile` (Reference: DisplayProfile), in the sense that the lines printed by that function correspond to the rows of the list that is shown by `BrowseProfile`. Initially, the table is sorted in the same way as the list shown by `BrowseProfile`; sorting the table by any of the first five columns will yield a non-increasing order of the rows.

The threshold values mincount and mintime can be changed in visual mode via the user input e. If mouse events are enabled (see `NCurses.UseMouse` (2.2-10)) then one can also use a mouse click on the current parameter value shown in the table header in order to enter the mode for changing the parameters.

When a row or an entry in a row is selected, "click" shows the code of the corresponding function in a pager (see `NCurses.Pager` (3.1-4)) whenever this is possible, as follows. If the function was read from a file then this file is opened, if the function was entered interactively then the code of the function is shown in the format produced by `Print` (Reference: Print); other functions (for example GAP kernel functions) cannot be shown, one gets an alert message (see `NCurses.Alert` (3.1-1)) in such a case.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> n:= [ 14, 14, 14, 14, 14 ];;  # ``do nothing''
    gap> ProfileOperationsAndMethods( true );    # collect some data
    gap> ConjugacyClasses( PrimitiveGroup( 24, 1 ) );;
    gap> ProfileOperationsAndMethods( false );
    gap> BrowseData.SetReplay( Concatenation(
    >        "scso",                                 # sort by column 1,
    >        n,
    >        "rso",                                  # sort by column 2,
    >        n,
    >        "rso",                                  # sort by column 3,
    >        n,
    >        "q",                                    # deselect the column,
    >        "/Centralizer", [ NCurses.keys.ENTER ], # search for a function,
    >        n, "Q" ) );                             # and quit
    gap> BrowseProfile();
    gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header, which shows the current values of mincount and mintime, and a dynamic footer, which shows the sums of counts and timings for the rows in the table (label `TOTAL`) and if applicable the sums for the profiled functions not shown in the table (label `OTHER`). There are no row labels, and the obvious column labels. There is no return value.

The standard modes in `BrowseData` (5.4-1) (except the `help` mode) have been modified by adding a new action for changing the threshold parameters mincount and mintime (user input e). The way how this in implemented made it necessary to change the standard "reset" action (user input !) of the table; note that resetting (a sorting or filtering of) the table must not make those rows visible that shall be hidden because of the threshold parameters.

The code can be found in the file `app/profile.g` of the package.

#### 6.9 Variables defined in GAP packages–a Variant

A Browse adapted way to list the variables that are defined in a GAP package is to show the overview that is printed by the GAP function `ShowPackageVariables` (Reference: ShowPackageVariables) in a Browse table.

##### 6.9-1 BrowsePackageVariables

`‣ BrowsePackageVariables`( pkgname[, version][, arec] ) | ( function )

Returns: nothing.

The arguments can be the same as for `ShowPackageVariables` (Reference: ShowPackageVariables), that is, pkgname is the name of a GAP package, and the optional arguments version and arec are a version number of this package and a record used for customizing the output, respectively.

Alternatively, the second argument can be the output `info` of `PackageVariablesInfo` (Reference: PackageVariablesInfo) for the package in question, instead of the version number.

`BrowsePackageVariables` opens a browse table that shows the global variables that become bound and the methods that become installed when GAP loads the package pkgname.

The table is categorized by the kinds of variables (new or redeclared operations, methods, info classes, synonyms, other globals). The column "Doc.?" distinguishes undocumented and documented variables, so one can use this column as a filter or for categorizing. The column "Filename" shows the names of the package files. Clicking a selected row of the table opens the relevant package file at the code in question.

The idea behind the argument `info` is that using the same arguments as for `ShowPackageVariables` (Reference: ShowPackageVariables) does not allow one to apply `BrowsePackageVariables` to packages that have been loaded before the Browse package. Thus one can compute the underlying data `info` first, using `PackageVariablesInfo` (Reference: PackageVariablesInfo), then load the Browse package, and finally call `BrowsePackageVariables`.

For example, the overview of package variables for Browse can be shown by starting GAP without packages and then entering the following lines.

    gap> pkgname:= "Browse";;
    gap> info:= PackageVariablesInfo( pkgname, "" );;
    gap> LoadPackage( "Browse" );;
    gap> BrowsePackageVariables( pkgname, info );

If the arguments are the same as for `ShowPackageVariables` (Reference: ShowPackageVariables) then this function is actually called, with the consequence that the package gets loaded when `BrowsePackageVariables` is called. This is not the case if the output of `PackageVariablesInfo` (Reference: PackageVariablesInfo) is entered as the second argument.

#### 6.10 Configuring User preferences–a Variant

A Browse adapted way to show and edit GAP's user preferences is to show the overview that is printed by the GAP function `ShowUserPreferences` (Reference: ShowUserPreferences) in a Browse table.

##### 6.10-1 BrowseUserPreferences

`‣ BrowseUserPreferences`( package1, package2, ... ) | ( function )

Returns: nothing.

The arguments are the same as for `ShowUserPreferences` (Reference: ShowUserPreferences), that is, calling the function with no argument yields an overview of all known user preferences, and if one or more strings package1, ... are given then only the user preferences for these packages are shown.

`BrowseUserPreferences` opens a browse table with the following columns:

"Package"

  contains the names of the GAP packages to which the user preferences belong,

"Pref. names"

  contains the names of the user preferences, and

"Description"

  contains the `description` texts from the `DeclareUserPreference` (Reference: DeclareUserPreference) calls and the default values (if applicable), and the actual values.

When one "clicks" on one of the table rows or entries then the values of the user preference in question can be edited. If a list of admissible values is known then this means that one can choose from this list via `NCurses.Select` (3.1-2), otherwise one can enter the desired value as text.

The values of the user preferences are not changed before one closes the browse table. When the table is left and if one has changed at least one value, one is asked whether the changes shall be applied.

    gap> d:= [ NCurses.keys.DOWN ];;
    gap> c:= [ NCurses.keys.ENTER ];;
    gap> BrowseData.SetReplay( Concatenation(
    >        "/PackagesToLoad",  # enter a search string,
    >        c,                  # start the search,
    >        c,                  # edit the entry (a list of choices),
    >        " ", d,             # toggle the first four values,
    >        " ", d,             #
    >        " ", d,             #
    >        " ", d,             #
    >        c,                  # submit the values,
    >        "Q",                # quit the table,
    >        c ) );              # choose "cancel": do not apply the changes.
    gap> BrowseUserPreferences();
    gap> BrowseData.SetReplay( false );

The code can be found in the file `app/userpref.g` of the package.

#### 6.11 Overview of GAP Data

The GAP system contains several data collections such as libraries of groups and character tables. Clearly the function `NCurses.BrowseGeneric` (4.3-1) can be used to visualize interesting information about such data collections, in the form of an "overview table" whose rows correspond to the objects in the collection; each column of the table shows a piece of information about the objects. (One possibility to create such overviews is given by `BrowseTableFromDatabaseIdEnumerator` (A.2-2).)

##### 6.11-1 BrowseGapData

`‣ BrowseGapData`( ) | ( function )

Returns: the return value of the chosen application if there is one.

The function `BrowseGapData` shows the choices in the list `BrowseData.GapDataOverviews`, in a browse table with one column. When an entry is "clicked" then the associated function is called, and the table of choices is closed.

The idea is that each entry of `BrowseData.GapDataOverviews` describes an overview of a data collection.

The Browse package provides overviews of

- the current AMS Mathematics Subject Classification codes (see `BrowseMSC` (6.7-3)),

- the contents of the AtlasRep package [WPN+19] (only if this package is loaded, see Section 6.5),

- the Conway polynomials in GAP (calls `BrowseConwayPolynomials()`),

- profile information for GAP functions (see Section 6.8),

- the list of GAP related bibliography entries in the file `bibl/gap-publishednicer.bib` of the Browse package (see Section 6.7),

- the GAP manuals (see Section 6.6),

- GAP operations and methods (calls `BrowseGapMethods()`),

- the installed GAP packages (calls `BrowseGapPackages()`),

- GAP's user preferences (see Section 6.10),

- the contents of the TomLib package [NMP13] (only if this package is loaded, see Section A.4),

Other GAP packages may add more overviews, using the function `BrowseGapDataAdd` (6.11-2). For example, there are overviews of

- the bibliographies in the ATLAS of Finite Groups [CCN+85] and in the ATLAS of Brauer Characters [JLPW95] (see `BrowseBibliographySporadicSimple` (AtlasRep: BrowseBibliographySporadicSimple)),

- atomic irrationalities that occur in character tables in the ATLAS of Finite Groups [CCN+85] or the ATLAS of Brauer Characters [JLPW95] (see Section `BrowseCommonIrrationalities` (CTblLib: BrowseCommonIrrationalities)),

- the differences between the versions of the character table data in the CTblLib package (see Section `BrowseCTblLibDifferences` (CTblLib: BrowseCTblLibDifferences)),

- the information in the GAP Character Table Library (see Section `BrowseCTblLibInfo` (CTblLib: BrowseCTblLibInfo)),

- an overview of minimal degrees of representations of groups from the ATLAS of Group Representations (see Section `BrowseMinimalDegrees` (AtlasRep: BrowseMinimalDegrees)).

Except that always one table cell is selected, the full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
    gap> # open the overview of Conway polynomials
    gap> BrowseData.SetReplay( Concatenation( "/Conway Polynomials",
    >      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "srdddd", n, "Q" ) );
    gap> BrowseGapData();;
    gap> # open the overview of GAP packages
    gap> BrowseData.SetReplay( Concatenation( "/GAP Packages",
    >      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "/Browse",
    >      [ NCurses.keys.ENTER ], "n", n, "Q" ) );
    gap> BrowseGapData();;
    gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a static header, a dynamic footer showing the description of the currently selected entry, no row or column labels, and exactly one column of fixed width equal to the screen width. If the chosen application has a return value then this is returned by `BrowseGapData`, otherwise nothing is returned. The component `work.SpecialGrid` of the browse table is used to draw a border around the list of choices and another border around the footer. Only one mode is needed in which an entry is selected.

The code can be found in the file `app/gapdata.g` of the package.

##### 6.11-2 BrowseGapDataAdd

`‣ BrowseGapDataAdd`( title, call[, ret], documentation ) | ( function )

This function extends the list `BrowseData.GapDataOverviews` by a new entry. The list is used by `BrowseGapData` (6.11-1).

title must be a string of length at most 76; it will be shown in the browse table that is opened by `BrowseGapData` (6.11-1). call must be a function that takes no arguments; it will be called when title is "clicked". ret, if given, must be `true` if call has a return value and if `BrowseGapData` (6.11-1) shall return this value, and `false` otherwise. documentation must be a string that describes what happens when the function call is called; it will be shown in the footer of the table opened by `BrowseGapData` (6.11-1) when title is selected.

#### 6.12 Navigating in a Directory Tree

A natural way to visualize the contents of a directory is via a tree whose leaves denote plain files, and the other vertices denote subdirectories. Browse provides a function based on `NCurses.BrowseGeneric` (4.3-1) for displaying such trees; the leaves correspond to the data rows, and the other vertices correspond to category rows.

##### 6.12-1 BrowseDirectory

`‣ BrowseDirectory`( [dir] ) | ( function )

Returns: a list of the "clicked" filenames.

If no argument is given then the contents of the current directory is shown, see `DirectoryCurrent` (Reference: DirectoryCurrent). If a directory object dir (see `Directory` (Reference: Directory)) is given as the only argument then the contents of this directory is shown; alternatively, dir may also be a string which is then understood as a directory path.

The full functionality of the function `NCurses.BrowseGeneric` (4.3-1) is available.

    gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
    gap> BrowseData.SetReplay( Concatenation(
    >        "q",                                  # leave the selection
    >        "X",                                  # expand all categories
    >        "/filetree", [ NCurses.keys.ENTER ],  # search for "filetree"
    >        n, "Q" ) );                           # and quit
    gap> dir:= DirectoriesPackageLibrary( "Browse", "" )[1];;
    gap> if IsBound( BrowseDirectory ) then
    >      BrowseDirectory( dir );
    >    fi;
    gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a static header, no footer, no row or column labels, and exactly one data column. The category rows are precomputed, i. e., they do not arise from a table column. The tree structure is visualized via a special grid that is shown in the separator column in front of the table column; the width of this column is computed from the largest nesting depth of files. For technical reasons, category rows representing empty directories are realized via "dummy" table rows; a special `ShowTables` function guarantees that these rows are always hidden.

When a data row or an entry in this row is selected, "click" adds the corresponding filename to the result list. Initially, the first row is selected. (So if you want to search in the whole tree then you should quit this selection by hitting the q key.)

The category hierarchy is computed using `DirectoryContents` (Reference: DirectoryContents).

This function is available only if the GAP package IO (see [Neu07]) is available, because the check for cycles uses the function `IO_stat` (IO: IO_stat) from this package.

The code can be found in the file `app/filetree.g` of the package.

#### 6.13 A Puzzle

We consider an m by n rectangle of squares numbered from 1 to m n - 1, the bottom right square is left empty. The numbered squares are permuted by successively exchanging the empty square and a neighboring square such that in the end, the empty cell is again in the bottom right corner.

7 | 13 | 14 | 2
1 | 4 | 15 | 11
6 | 8 | 3 | 9
10 | 5 | 12 |

The aim of the game is to order the numbered squares via these moves.

For the case m = n = 4, the puzzle is (erroneously?) known under the name "Sam Loyd's Fifteen", see [Bog] and [OR] for more information and references.

##### 6.13-1 BrowsePuzzle

`‣ BrowsePuzzle`( [m, n[, pi]] ) | ( function )

Returns: a record describing the initial and final status of the puzzle.

This function shows the rectangle in a window.

The arguments m and n are the dimensions of the rectangle, the default for both values is 4. The initial distribution of the numbers in the squares can be prescribed via a permutation pi, the default is a random element in the alternating group on the points 1, 2, ..., m n - 1. (Note that the game has not always a solution.)

In any case, the empty cell is selected, and the selection can be moved to neighboring cells via the arrow keys, or to any place in the same row or column via a mouse click.

The return value is a record with the components `dim` (the pair `[ m, n ]`), `init` (the initial permutation), `final` (the final permutation), and `steps` (the number of transpositions that were needed).

    gap> BrowseData.SetReplay( Concatenation(
    >        BrowsePuzzleSolution.steps, "Q" ) );
    gap> BrowsePuzzle( 4, 4, BrowsePuzzleSolution.init );;
    gap> BrowseData.SetReplay( false );

An implementation using only mouse clicks but no key strokes is available in the GAP package XGAP (see [CN04]).

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual `minyx` function. Only one mode is needed in which one cell is selected, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only the four moves via the arrow keys and mouse clicks are admissible.

Some standard `NCurses.BrowseGeneric` (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file `app/puzzle.g` of the package.

#### 6.14 Peg Solitaire

Peg solitaire is a board game for one player. The game board consists of several holes some of which contain pegs. In each step of the game, one peg is moved horizontally or vertically to an empty hole at distance two, by jumping over a neighboring peg which is then removed from the board.

We consider the game that in the beginning, exactly one hole is empty, and in the end, exactly one peg is left.

##### 6.14-1 PegSolitaire

`‣ PegSolitaire`( [format][,] [nrholes][,] [twoModes] ) | ( function )

This function shows the game board in a window.

If the argument format is one of the strings `"small"` or `"large"` then small or large pegs are shown, the default is `"small"`.

Three shapes of the game board are supported, with 33, 37, and 45 holes, respectively; this number can be specified via the argument nrholes, the default is 33. In the cases of 33 and 45 holes, the position of both the initial hole and the destination of the final peg is the middle cell, whereas in the case of 37 holes, the initial hole is in the top left position and the final peg has to be placed in the bottom right position.

If a Boolean twoModes is entered as an argument then it determines whether a browse table with one or two modes is used; the default `false` yields a browse table with only one mode.

In any case, one cell of the board is selected, and the selection can be moved to neighboring cells via the arrow keys. A peg in the selected cell jumps over a neighboring peg to an adjacent hole via the `j` key followed by the appropriate arrow key.

    gap> for n in [ 33, 37, 45 ] do
    >      BrowseData.SetReplay( Concatenation(
    >          PegSolitaireSolutions.( String( n ) ), "Q" ) );
    >      PegSolitaire( n );
    >      PegSolitaire( "large", n );
    >      PegSolitaire( n, true );
    >      PegSolitaire( "large", n, true );
    > od;
    gap> BrowseData.SetReplay( false );

For more information such as variations of the game and references, see [Köla]. Also the solutions stored in the variable `PegSolitaireSolutions` have been taken from this web page.

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual `minyx` function. In fact, two implementations are provided. The first one needs only one mode in which one cell is selected; moving the selection and jumping with the peg in the selected cell in one of the four directions are the supported user actions. The second implementation needs two modes, one for moving the selection and one for jumping.

Some standard `NCurses.BrowseGeneric` (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file `app/solitair.g` of the package.

#### 6.15 Rubik's Cube

We visualize the transformations of Rubik's magic cube in a model that is given by "unfolding" the faces and numbering them as follows.

Clockwise turns of the six layers (top, left, front, right, back, and down) are represented by the following permutations.

    gap> cubegens := [
    >   ( 1, 3, 8, 6)( 2, 5, 7, 4)( 9,33,25,17)(10,34,26,18)(11,35,27,19),
    >   ( 9,11,16,14)(10,13,15,12)( 1,17,41,40)( 4,20,44,37)( 6,22,46,35),
    >   (17,19,24,22)(18,21,23,20)( 6,25,43,16)( 7,28,42,13)( 8,30,41,11),
    >   (25,27,32,30)(26,29,31,28)( 3,38,43,19)( 5,36,45,21)( 8,33,48,24),
    >   (33,35,40,38)(34,37,39,36)( 3, 9,46,32)( 2,12,47,29)( 1,14,48,27),
    >   (41,43,48,46)(42,45,47,44)(14,22,30,38)(15,23,31,39)(16,24,32,40)
    > ];;

GAP computations analyzing this permutation group have been part of the announcements of GAP 3 releases. For a GAP 4 equivalent, see [Sch]. For more information and references (not GAP related) about Rubik's cube, see [Kölb].

##### 6.15-1 BrowseRubiksCube

`‣ BrowseRubiksCube`( [format][,] [pi] ) | ( function )

This function shows the model of the cube in a window.

If the argument format is one of the strings `"small"` or `"large"` then small or large cells are shown, the default is `"small"`.

The argument pi is the initial permutation of the faces, the default is a random permutation in the cube group, see Reference: Random.

Supported user inputs are the keys t, l, f, r, b, and d for clockwise turns of the six layers, and the corresponding capital letters for counter-clockwise turns. If the terminal supports colors, according to the global variable `NCurses.attrs.has_colors` (2.2-1), the input s switches between a screen that shows only the colors of the faces and a screen that shows the numbers; the color screen is the default.

The return value is a record with the components `inputs` (a string describing the user inputs), `init`, and `final` (the initial and final permutation of the faces, respectively). (The `inputs` component can be used for the replay feature, see the example below.)

In the following example, a word in terms of the generators is used to initialize the browse table, and then the letters in this word are used as a series of input steps, except that in between, the display is switched once from colors to numbers and back.

    gap> choice:= List( [ 1 .. 30 ], i -> Random( [ 1 .. 6 ] ) );;
    gap> input:= List( "tlfrbd", IntChar ){ choice };;
    gap> BrowseData.SetReplay( Concatenation(
    >        input{ [ 1 .. 20 ] },
    >        "s",                    # switch to number display
    >        input{ [ 21 .. 25 ] },
    >        "s",                    # switch to color display
    >        input{ [ 26 .. 30 ] },
    >        "Q" ) );;               # quit the browse table
    gap> BrowseRubiksCube( Product( cubegens{ choice } ) );;
    gap> BrowseRubiksCube( "large", Product( cubegens{ choice } ) );;
    gap> BrowseData.SetReplay( false );

Implementation remarks: The cube is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual `minyx` function. Only one mode is needed, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only the twelve moves and the switch between color and number display are admissible.

Switching between the two display formats is implemented via a function `work.Main`, so this relies on not caching the formatted cells in `work.main`.

Row and column separators of the browse table are whitespace of height and width one. The separating lines are drawn using an individual `SpecialGrid` function in the browse table. Note that the relevant cells do not form a rectangular array.

Some standard `NCurses.BrowseGeneric` (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file `app/rubik.g` of the package.

#### 6.16 Changing Sides

We consider a 5 by 5 board of squares filled with two types of stones, as follows. The square in the middle is left empty.

X | X | X | X | X
O | X | X | X | X
O | O |  | X | X
O | O | O | O | X
O | O | O | O | O

The aim of the game is to exchange the two types of stones via a sequence of single steps that move one stone to the empty position on the board. Only those moves are allowed that increase or decrease one coordinate by 2 and increase or decrease the other by 1; these are the allowed moves of the knight in chess.

This game has been part of the MacTutor system [OR00].

##### 6.16-1 BrowseChangeSides

`‣ BrowseChangeSides`( ) | ( function )

This function shows the game board in a window.

Each move is encoded as a sequence of three arrow keys; there are 24 admissible inputs.

    gap> for entry in BrowseChangeSidesSolutions do
    >      BrowseData.SetReplay( Concatenation( entry, "Q" ) );
    >      BrowseChangeSides();
    > od;
    gap> BrowseData.SetReplay( false );

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual `minyx` function. Only one mode is needed, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only moves via combinations of the four arrow keys are admissible.

The separating lines are drawn using an individual `SpecialGrid` function in the browse table.

Some standard `NCurses.BrowseGeneric` (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file `app/knight.g` of the package.

#### 6.17 Sudoku

We consider a 9 by 9 board of squares. Some squares are initially filled with numbers from 1 to 9. The aim of the game is to fill the empty squares in such a way that each row, each column, and each of the marked 3 by 3 subsquares contains all numbers from 1 to 9. A proper Sudoku game is defined as one with a unique solution. Here is an example.

| 1 | 5
9 |  |

4 |  | 6
| 5 |

5 |  |
| 2 |
3 |  |

6 |  | 4
8 |  |

8 |  |
9 |  |

| 5 | 3

| 4 |
|  | 9

|  | 5
|  | 7
1 |  |

|  | 2
8 |  |

The Browse package contains functions to create, play and solve these games. There are basic command line functions for this, which we describe first, and there is a user interface `PlaySudoku` (6.17-8) which is implemented using the generic browse functionality described in Chapter 4.

##### 6.17-1 Sudoku.Init

`‣ Sudoku.Init`( [arg] ) | ( function )

Returns: A record describing a Sudoku board or `fail`.

This function constructs a record describing a Sudoku game. This is used by the other functions described below. There a several possibilities for the argument arg.

arg is a string

  The entries of a Sudoku board are numbered row-wise from 1 to 81. A board is encoded as a string as follows. If one of the numbers 1 to 9 is in entry i then the corresponding digit character is written in position i of the string. If an entry is empty any character, except `'1'` to `'9'` or `'|'` is written in position i of the string. Trailing empty entries can be left out. Afterwards `'|'`-characters can be inserted in the string (for example to mark line ends). Such strings can be used for arg.

arg is a matrix

  A Sudoku board can also be encoded as a 9 by 9-matrix, that is a list of 9 lists of length 9, whose (i,j)-th entry is the (i,j)-th entry of the board as integer if it is not empty. Empty entries of the board correspond to unbound entries in the matrix.

arg is a list of integers

  Instead of the matrix just described the argument can also be given by the concatenation of the rows of the matrix (so, a list of integers and holes).

    gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
    >  6  47   |45  2    |89   2 1 | 4   8 7 | ");;

##### 6.17-2 Sudoku.Place

`‣ Sudoku.Place`( game, i, n ) | ( function )

`‣ Sudoku.Remove`( game, i ) | ( function )

Returns: The changed game.

Here game is a record describing a Sudoku board, as returned by `Sudoku.Init` (6.17-1). The argument i is the number of an entry, counted row-wise from 1 to 81, and n is an integer from 1 to 9 to be placed on the board. These functions change game.

`Sudoku.Place` tries to place number n on entry i. It is an error if entry i is not empty. The number is not placed if n is already used in the row, column or subsquare of entry i. In this case the component `game.impossible` is bound.

`Sudoku.Remove` tries to remove the number placed on position i of the board. It does not change the board if entry i is empty, or if entry i was given when the board game was created. In the latter case `game.impossible` is bound.

    gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
    >  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
    gap> Sudoku.Place(game, 1, 3);; # 3 is already in first row
    gap> IsBound(game.impossible);
    true
    gap> Sudoku.Place(game, 1, 2);; # 2 is not in row, col or subsquare
    gap> IsBound(game.impossible);
    false

##### 6.17-3 Sudoku.RandomGame

`‣ Sudoku.RandomGame`( [seed] ) | ( function )

Returns: A pair `[str, seed]` of string and seed.

The optional argument seed, if given, must be an integer. If not given some random integer from the current GAP session is used. This function returns a random proper Sudoku game, where the board is described by a string `str`, as explained in `Sudoku.Init` (6.17-1). With the same seed the same board is returned.

The games computed by this function have the property that after removing any given entry the puzzle does no longer have a unique solution.

    gap> Sudoku.RandomGame(5833750);
    [ " 1         2     43  2   68   72    8     6 2   1 9 8  8 3   9     \
    47 3   7  18  ", 5833750 ]
    gap> last = Sudoku.RandomGame(last[2]);
    true

##### 6.17-4 Sudoku.SimpleDisplay

`‣ Sudoku.SimpleDisplay`( game ) | ( function )

Displays a Sudoku board on the terminal. (But see `PlaySudoku` (6.17-8) for a fancier interface.)

    gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
    >  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
    gap> Sudoku.SimpleDisplay(game);
     3 |  6|8
     85|  1| 69
      9|7  | 53
    -----------
       |   |79
     6 | 47|
    45 | 2 |
    -----------
    89 |  2| 1
     4 |  8| 7
       |   |

##### 6.17-5 Sudoku.DisplayString

`‣ Sudoku.DisplayString`( game ) | ( function )

The string returned by this function can be used to display the Sudoku board game on the terminal, using `PrintFormattedString` (GAPDoc: PrintFormattedString). The result depends on the value of `GAPInfo.TermEncoding`.

    gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
    >  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
    gap> str:= Sudoku.DisplayString( game );;
    gap> PrintFormattedString( str );
                         ┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓
                         ┃   │ 3 │   ┃   │   │ 6 ┃ 8 │   │   ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃   │ 8 │ 5 ┃   │   │ 1 ┃   │ 6 │ 9 ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃   │   │ 9 ┃ 7 │   │   ┃   │ 5 │ 3 ┃
                         ┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫
                         ┃   │   │   ┃   │   │   ┃ 7 │ 9 │   ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃   │ 6 │   ┃   │ 4 │ 7 ┃   │   │   ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃ 4 │ 5 │   ┃   │ 2 │   ┃   │   │   ┃
                         ┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫
                         ┃ 8 │ 9 │   ┃   │   │ 2 ┃   │ 1 │   ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃   │ 4 │   ┃   │   │ 8 ┃   │ 7 │   ┃
                         ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                         ┃   │   │   ┃   │   │   ┃   │   │   ┃
                         ┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛

##### 6.17-6 Sudoku.OneSolution

`‣ Sudoku.OneSolution`( game ) | ( function )

Returns: A completed Sudoku board that solves game, or `fail`.

Here game must be a Sudoku board as returned by `Sudoku.Init` (6.17-1). It is not necessary that game describes a proper Sudoku game (has a unique solution). It may have several solutions, then one random solution is returned. Or it may have no solution, then `fail` is returned.

    gap> Sudoku.SimpleDisplay(Sudoku.OneSolution(Sudoku.Init("  3")));
    493|876|251
    861|542|739
    527|193|648
    -----------
    942|618|573
    156|739|482
    738|425|916
    -----------
    289|354|167
    375|961|824
    614|287|395

##### 6.17-7 Sudoku.UniqueSolution

`‣ Sudoku.UniqueSolution`( game ) | ( function )

Returns: A completed Sudoku board that solves game, or `false`, or `fail`.

Here game must be a Sudoku board as returned by `Sudoku.Init` (6.17-1). It is not necessary that game describes a proper Sudoku game. If it has several solutions, then `false` is returned. If it has no solution, then `fail` is returned. Otherwise a board with the unique solution is returned.

    gap> s := "      5  | 154 6 2 |9   5 3  |6 4      |   8     |8  9   53\
    > |     5   | 4   7  2|  91  8  ";;
    gap> sol := Sudoku.UniqueSolution(Sudoku.Init(s));;
    gap> Sudoku.SimpleDisplay(sol);
    438|219|576
    715|436|928
    962|758|314
    -----------
    694|573|281
    153|862|749
    827|941|653
    -----------
    281|695|437
    546|387|192
    379|124|865

##### 6.17-8 PlaySudoku

`‣ PlaySudoku`( [arg] ) | ( function )

Returns: A record describing the latest status of a Sudoku board.

This function allows one to solve Sudoku puzzles interactively. There are several possibilities for the optional argument arg. It can either be a string, matrix or list of holes and integers as described in `Sudoku.Init` (6.17-1), or a board as returned by `Sudoku.Init` (6.17-1). Furthermore arg can be an integer or not be given, in that case `Sudoku.RandomGame` (6.17-3) is called to produce a random game.

The usage of this function is self-explanatory, pressing the ? key displays a help screen. Here, we mention two keys with a particular action: Pressing the h key you get a hint, either an empty entry is filled or the program tells you that there is no solution (so you must delete some entries and try others). Pressing the s key the puzzle is solved by the program or it tells you that there is no or no unique solution.

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual `minyx` function. Two modes are supported, with the standard actions for quitting the table and asking for help; one cell is selected in each mode. The first mode provides actions for moving the selected cell via arrow keys, for changing the value in the selected cell, for getting a hint or the (unique) solution. (Initial entries of the matrix cannot be changed via user input. They are shown in boldface.) The second mode serves for error handling: When the user enters an invalid number, i. e., a number that occurs already in the current row or column or subsquare, then the application switches to this mode, which causes that a message is shown in the footer, and the invalid entry is shown in red and blinking; similarly, error mode is entered if a hint or solution does not exist.

The separating lines are drawn using an individual `SpecialGrid` function in the browse table, since they cannot be specified within the generic browse table functions.

Some standard `NCurses.BrowseGeneric` (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file `app/sudoku.g` of the package.

##### 6.17-9 Sudoku.HTMLGame

`‣ Sudoku.HTMLGame`( game ) | ( function )

`‣ Sudoku.LaTeXGame`( game ) | ( function )

Returns: A string with HTML or LaTeX code, respectively.

The argument of these functions is a record describing a Sudoku game. These functions return code for including the current status of the board into a webpage or a LaTeX document.

#### 6.18 Utility for GAP Demos

This application can be used with GAP if the user interface has `readline` support. The purpose is to simplify the typing during a demonstration of GAP commands.

The file format to specify GAP code for a demonstration is very simple: it contains blocks of lines with GAP input, separated by lines starting with the sequence `#%`. Comments in such a file can be added to one or several lines starting with `#%`. Here is the content of an example file `demo.demo`:

    #% Add comments after #% characters at the beginning of a line.
    #% A comment can have several lines.
    #% Here is a multi-line input block:
    g := MathieuGroup(11);;
    cl := ConjugacyClasses(g);
    #% Calling a help page
    ?MathieuGroup
    #% The next line contains a comment in the GAP session:
    a := 12;; b := 13;; # assign two numbers
    #%
    a*b;
    #%

(Single `%` in the beginning of a line will also work as separators.)

A demonstration can be loaded into a GAP session with the command

##### 6.18-1 LoadDemoFile

`‣ LoadDemoFile`( demoname, demofile[, singleline] ) | ( function )

Returns: Nothing.

This function loads a demo file in the format described above. The argument demoname is a string containing a name for the demo, and demofile is the file name containing the demo.

If the optional argument singleline is given and its value is `true`, the demo behaves differently with respect to input blocks that span several lines. By default full blocks are treated as a single input line for `readline` (maybe spanning several physical lines in the terminal). If singleline is `true` then all input lines of a block except the last one are sent to GAP and are evaluated automatically before the last line of the block is displayed.

    gap> dirs := DirectoriesPackageLibrary("Browse");;
    gap> demofile := Filename(dirs, "../app/demo.demo");;
    gap> LoadDemoFile("My first demo", demofile);
    gap> LoadDemoFile("My first demo (single lines)", demofile, true);

Many demos can be loaded at the same time. They are used with the PageDown and PageUp keys.

The PageUp key leads to a (Browse) menu which allows one to choose a demo to start (if several are loaded), to stop a demo or to move to another position in the current demo (e.g., to go back to a previous point or to skip part of a demo).

The next input block of the current demo is copied into the current input line of the GAP session by pressing the PageDown key. This line is not yet sent to GAP, use the Return key if you want to evaluate the input. (You can also still edit the input line before evaluation.)

So, in the simplest case a demo can be done by just pressing PageDown and Return in turns. But it is always possible to type extra input during a demo by hand or to change the input lines from the demo file before evaluation. It is no problem if commands are interrupted by Ctrl-C. During a demo you are in a normal GAP session, this application only saves you some typing. The input lines from the demo are put into the history of the session as if they were typed by hand.

Try it yourself with the two demos loaded in the example. This also shows the different behaviour between default and single line mode.

[Top of Book] [Contents] [Previous Chapter] [Next Chapter]
Goto Chapter: Top 1 2 3 4 5 6 A Bib Ind

generated by GAPDoc2HTML