Loading ...
Sorry, an error occurred while loading the content.

Hurray ! My very first "program" !

Expand Messages
  • Cedric Cellier
    The purpose is to parse a FEN string (a standard notation to designate chess game positions - see for instance [1] for a quick exposition). Use it in the top
    Message 1 of 16 , Jan 5, 2009
    • 0 Attachment
      The purpose is to parse a FEN string (a standard notation to designate
      chess game positions - see for instance [1] for a quick exposition).
      Use it in the top level for instance with :

      # position_of_FEN "3rr1k1/p3bppp/1p6/2p1BqNQ/3p4/1P6/n4PPP/2R1R1K1 w KqkQ e4 3 26";;

      I would apreciate any remark, whatever superficial, about anything
      from data structures, algorithm(??), (lack of) style, naming convention,
      indentation, etc, in order to fix my mistackes before they settle into
      bad habbits.

      Here it is :

      ---- 8< -- 8< -- 8< ---------------

      (* Requires str.cma *)

      (* Types and helpers *)

      exception Not_A_FEN;;
      type column = int;; (* FIXME: constrained to 0..7 *)
      type rank = int;; (* FIXME: constrained to 0..7 *)
      type location = column*rank;;
      type color = White|Black;;
      type figure = Pawn|Knight|Bishop|Rook|Queen|King;;
      type piece = color*figure;;
      type occupant = Nothing | Some of piece;;
      type side = KingSide | QueenSide;;
      type en_passant_t = None | One of location;; (* FIXME: I would appreciate not to name this type *)

      type position = {
      board: occupant array;
      trait: color;
      avl_castling: (color*side, bool) Hashtbl.t; (* Available castlings *)
      en_passant: en_passant_t;
      half_moves: int;
      full_moves: int;
      };;

      let make_empty_board () = Array.make 64 Nothing;;

      let string_of_column c = String.make 1 (char_of_int (int_of_char 'a' + c));;

      let string_of_rank l = string_of_int (l + 1);;

      let column_of_string s = int_of_char s.[0] - int_of_char 'a';;

      let rank_of_string s = int_of_char s.[0] - int_of_char '1';;

      let string_of_location (c, l) =
      string_of_column c ^ string_of_rank l;;

      let string_of_color c =
      match c with
      | White -> "white"
      | Black -> "black";;

      let string_of_figure f =
      match f with
      | Pawn -> "pawn"
      | Knight -> "knight"
      | Bishop -> "bishop"
      | Rook -> "rook"
      | Queen -> "queen"
      | King -> "king";;

      let string_of_piece (col, fig) =
      string_of_color col ^ " " ^ string_of_figure fig;;

      let string_of_occupant o =
      match o with
      | Nothing -> "empty"
      | Some p -> string_of_piece p;;

      let color_of_location (c, l) =
      match (c + l) mod 2 with
      | 0 -> Black
      | _ -> White;;

      let location_of_string str =
      (column_of_string (String.sub str 0 1), rank_of_string (String.sub str 1 1));;

      (* FEN parsing *)

      let position_of_FEN fen =
      let board_of_FEN fen =
      let board = make_empty_board()
      and figure_of_fen = function
      | 'p' -> Pawn
      | 'n' -> Knight
      | 'b' -> Bishop
      | 'r' -> Rook
      | 'q' -> Queen
      | 'k' -> King
      | _ -> raise Not_A_FEN
      and pos_to_skip c =
      let s = int_of_char c - int_of_char '0' in
      if s <= 0 || s > 8 then 0 else s
      and rank = ref 7
      and col = ref 0 in
      let next_line () =
      rank := !rank-1;
      col := 0
      and next_col s =
      col := !col + s
      and set_board o =
      if !rank < 0 || !col >= 8 then raise Not_A_FEN else
      board.(!rank*8 + !col) <- o in
      let parse_fen_char c =
      if c = '/' then next_line ()
      else let skip = pos_to_skip c in
      if skip > 0 then next_col skip
      else begin
      let down_c = Char.lowercase(c) in
      let color = if down_c == c then Black else White
      and figure = figure_of_fen down_c in
      set_board (Some (color, figure));
      next_col 1
      end in
      String.iter parse_fen_char fen;
      board

      and trait_of_FEN fen =
      if fen.[0] = 'w' then White else Black

      and en_passant_of_FEN fen =
      if 0 = String.compare fen "-" then None else One (location_of_string fen)

      and avl_castling_of_FEN fen =
      let h = Hashtbl.create 4 in
      String.iter (function
      | 'K' -> Hashtbl.add h (White, KingSide) true
      | 'k' -> Hashtbl.add h (Black, KingSide) true
      | 'Q' -> Hashtbl.add h (White, QueenSide) true
      | 'q' -> Hashtbl.add h (Black, QueenSide) true
      | '-' -> ()
      | _ -> raise Not_A_FEN) fen;
      h

      and re = Str.regexp
      "^\\(.*\\) \\([bw]\\) \\([QKqk]+\\|-\\) \\([a-h][1-8]\\|-\\) \\([0-9]+\\) \\([0-9]+\\)$" in

      if Str.string_match re fen 0 then
      {
      board = board_of_FEN (Str.matched_group 1 fen);
      trait = trait_of_FEN (Str.matched_group 2 fen);
      avl_castling = avl_castling_of_FEN (Str.matched_group 3 fen);
      en_passant = en_passant_of_FEN (Str.matched_group 4 fen);
      half_moves = int_of_string (Str.matched_group 5 fen);
      full_moves = int_of_string (Str.matched_group 6 fen);
      }
      else raise Not_A_FEN;;

      -------------- >8 -- >8 -- >8 ----

      [1] http://en.wikipedia.org/wiki/Forsyth-Edwards_Notation
    • Dario Teixeira
      Hi, I haven t looked at the whole code yet, but there are two things that immediately pop out: a) The type type en_passant_t = None | One of location;; Can
      Message 2 of 16 , Jan 5, 2009
      • 0 Attachment
        Hi,

        I haven't looked at the whole code yet, but there are two things that
        immediately pop out:

        a) The type

        type en_passant_t = None | One of location;;

        Can better be written as

        type en_passant_t = location option

        b) All those ;; at the end are superfluous and ugly. Remember:
        in almost all circumstances you only need the ;; to terminate
        statements in the top-level.

        Cheers,
        Dario Teixeira
      • Mathias Kende
        ... I don t know if this is what your fixme asks for, but your types occupant and en_passant_t could be defined using the builtin option type as : type
        Message 3 of 16 , Jan 5, 2009
        • 0 Attachment
          Le lundi 05 janvier 2009 à 21:17 +0100, Cedric Cellier a écrit :
          > (* Requires str.cma *)
          >
          > (* Types and helpers *)
          >
          > exception Not_A_FEN;;
          > type column = int;; (* FIXME: constrained to 0..7 *)
          > type rank = int;; (* FIXME: constrained to 0..7 *)
          > type location = column*rank;;
          > type color = White|Black;;
          > type figure = Pawn|Knight|Bishop|Rook|Queen|King;;
          > type piece = color*figure;;
          > type occupant = Nothing | Some of piece;;
          > type side = KingSide | QueenSide;;
          > type en_passant_t = None | One of location;; (* FIXME: I would
          > appreciate not to name this type *)

          I don't know if this is what your fixme asks for, but your types
          occupant and en_passant_t could be defined using the builtin option type
          as :
          type occupant = piece option;;
          type en_passant_t = location option;;

          Which will both use the keywords None and Some as constructors (and you
          ca avoid defining en_passant_t if you wish so);;

          Mathias
        • Cedric Cellier
          -[ Mon, Jan 05, 2009 at 12:24:55PM -0800, Dario Teixeira ]---- ... I _knew_ there was something already defined ! :) I also changed Nothing | Some into option.
          Message 4 of 16 , Jan 5, 2009
          • 0 Attachment
            -[ Mon, Jan 05, 2009 at 12:24:55PM -0800, Dario Teixeira ]----
            > type en_passant_t = None | One of location;;
            >
            > Can better be written as
            >
            > type en_passant_t = location option

            I _knew_ there was something already defined ! :)
            I also changed Nothing | Some into option.
            Thanx !

            > b) All those ;; at the end are superfluous and ugly. Remember:
            > in almost all circumstances you only need the ;; to terminate
            > statements in the top-level.

            If I don't put them then I cannot "#use" my file from the top level.
            I suppose I would have to compile/#load it instead. Well, I've got
            to get used to it anyway.
          • Cedric Cellier
            -[ Mon, Jan 05, 2009 at 09:44:08PM +0100, Cedric Cellier ]---- ... Forget about this, Im just plain stupid. I assumed that removing the ;; meant replacing
            Message 5 of 16 , Jan 5, 2009
            • 0 Attachment
              -[ Mon, Jan 05, 2009 at 09:44:08PM +0100, Cedric Cellier ]----
              > > b) All those ;; at the end are superfluous and ugly. Remember:
              > > in almost all circumstances you only need the ;; to terminate
              > > statements in the top-level.
              >
              > If I don't put them then I cannot "#use" my file from the top level.
              > I suppose I would have to compile/#load it instead. Well, I've got
              > to get used to it anyway.

              Forget about this, Im just plain stupid.
              I assumed that removing the ";;" meant replacing them by ";". Now I've
              understood that, contrary to C where ';' must end an expression, in Ocaml
              ';' is just used to separate a sequence of expressions (seldom needed).

              I fixed that.
            • Richard Jones
              ... There s a section on this page called Using and omitting ;; and ; which explains the rules a bit:
              Message 6 of 16 , Jan 5, 2009
              • 0 Attachment
                On Mon, Jan 05, 2009 at 09:58:06PM +0100, Cedric Cellier wrote:
                > -[ Mon, Jan 05, 2009 at 09:44:08PM +0100, Cedric Cellier ]----
                > > > b) All those ;; at the end are superfluous and ugly. Remember:
                > > > in almost all circumstances you only need the ;; to terminate
                > > > statements in the top-level.
                > >
                > > If I don't put them then I cannot "#use" my file from the top level.
                > > I suppose I would have to compile/#load it instead. Well, I've got
                > > to get used to it anyway.
                >
                > Forget about this, Im just plain stupid.
                > I assumed that removing the ";;" meant replacing them by ";". Now I've
                > understood that, contrary to C where ';' must end an expression, in Ocaml
                > ';' is just used to separate a sequence of expressions (seldom needed).
                >
                > I fixed that.

                There's a section on this page called "Using and omitting ;; and ;"
                which explains the rules a bit:

                http://www.ocaml-tutorial.org/the_structure_of_ocaml_programs

                Basically you can omit ;; before any let, type, open, module, class
                keyword (and a few others too), but you cannot omit it before any bare
                expression.

                Rich.

                --
                Richard Jones
                Red Hat
              • Richard Jones
                ... Not much to say really, beyond the few things that other people have pointed out. I was going to add that you can use ( ... ) instead of begin ... end ...
                Message 7 of 16 , Jan 5, 2009
                • 0 Attachment
                  On Mon, Jan 05, 2009 at 09:17:53PM +0100, Cedric Cellier wrote:
                  > The purpose is to parse a FEN string (a standard notation to designate
                  > chess game positions - see for instance [1] for a quick exposition).
                  > Use it in the top level for instance with :
                  >
                  > # position_of_FEN "3rr1k1/p3bppp/1p6/2p1BqNQ/3p4/1P6/n4PPP/2R1R1K1 w KqkQ e4 3 26";;
                  >
                  > I would apreciate any remark, whatever superficial, about anything
                  > from data structures, algorithm(??), (lack of) style, naming convention,
                  > indentation, etc, in order to fix my mistackes before they settle into
                  > bad habbits.

                  Not much to say really, beyond the few things that other people have
                  pointed out.

                  I was going to add that you can use ( ... ) instead of begin ... end
                  as in:

                  > if skip > 0 then next_col skip
                  > else (
                  > let down_c = Char.lowercase(c) in
                  > let color = if down_c == c then Black else White
                  > and figure = figure_of_fen down_c in
                  > set_board (Some (color, figure));
                  > next_col 1
                  > ) in

                  and, myself, I would also use less indentation (because OCaml allows
                  more nesting -- eg. functions within functions within functions ...).

                  OCaml isn't really good at regular expressions. To make the program
                  more concise you might look at a regular expression syntax extension,
                  ie. micmatch/mikmatch.

                  http://martin.jambon.free.fr/micmatch.html

                  Rich.

                  --
                  Richard Jones
                  Red Hat
                • Cedric Cellier
                  -[ Mon, Jan 05, 2009 at 11:57:50PM +0000, Richard Jones ]---- ... I didn t knew. That s better. ... I use 3 char for indentation generaly, and use the tab
                  Message 8 of 16 , Jan 5, 2009
                  • 0 Attachment
                    -[ Mon, Jan 05, 2009 at 11:57:50PM +0000, Richard Jones ]----
                    > I was going to add that you can use ( ... ) instead of begin ... end

                    I didn't knew. That's better.

                    > and, myself, I would also use less indentation (because OCaml allows
                    > more nesting -- eg. functions within functions within functions ...).

                    I use 3 char for indentation generaly, and use the tab character only
                    so that everyone can choose what he likes.

                    That's funny because I just discovered yesterday, while posting this code,
                    that there is no way in mutt (the mail client I use) to choose this
                    tab size, so I ended up sending a patch to do just that. I can see from
                    your header that you use mutt also ; if you're interrested the patch is
                    still probably attached with the last opened ticket on mutt bug tracker
                    (Im not sure anyway if you won't be quicker to hack pager.c yourself
                    than to download the trivial patch).

                    > OCaml isn't really good at regular expressions. To make the program
                    > more concise you might look at a regular expression syntax extension,
                    > ie. micmatch/mikmatch.

                    You know what ? I just realize that I do not need regex at all, since
                    I just want to split at spaces. I'm going to redo it with
                    String.index_from.

                    Thank you for the comments !
                  • Florent Monnier
                    ... As sometimes being able to omit ;; depends on what follows one can consider a good idea to put them most of the time, this way when you modify the source
                    Message 9 of 16 , Jan 6, 2009
                    • 0 Attachment
                      > > Forget about this, Im just plain stupid.
                      > > I assumed that removing the ";;" meant replacing them by ";". Now I've
                      > > understood that, contrary to C where ';' must end an expression, in Ocaml
                      > > ';' is just used to separate a sequence of expressions (seldom needed).
                      > >
                      > > I fixed that.
                      >
                      > There's a section on this page called "Using and omitting ;; and ;"
                      > which explains the rules a bit:
                      >
                      > http://www.ocaml-tutorial.org/the_structure_of_ocaml_programs
                      >
                      > Basically you can omit ;; before any let, type, open, module, class
                      > keyword (and a few others too), but you cannot omit it before any bare
                      > expression.

                      As sometimes being able to omit ;; depends on what follows one can consider a
                      good idea to put them most of the time, this way when you modify the source
                      code you won't end in a position where ;; is omited but required!

                      In addition to this, as ocaml does not encloses the parameter with brackets,
                      it often happens that when you add a parameter to a function (or forget it)
                      you will encounter partial application where not expected.
                      And the important point here is if you have no ;; in your source code, ocaml
                      will provide an error message with the position given the very last char of
                      the file. If you put the ;; the error message will be positioned on the right
                      function.
                    • Richard Jones
                      ... Or even String.nsplit (from extlib). Rich. -- Richard Jones Red Hat
                      Message 10 of 16 , Jan 6, 2009
                      • 0 Attachment
                        On Tue, Jan 06, 2009 at 06:51:48AM +0100, Cedric Cellier wrote:
                        > You know what ? I just realize that I do not need regex at all, since
                        > I just want to split at spaces. I'm going to redo it with
                        > String.index_from.

                        Or even String.nsplit (from extlib).

                        Rich.

                        --
                        Richard Jones
                        Red Hat
                      • Martin Jambon
                        ... Most if not all problems related to missing parentheses or separators are trivially detected when using an editor that indents the code for you. I ve been
                        Message 11 of 16 , Jan 6, 2009
                        • 0 Attachment
                          Florent Monnier wrote:
                          >>> Forget about this, Im just plain stupid.
                          >>> I assumed that removing the ";;" meant replacing them by ";". Now I've
                          >>> understood that, contrary to C where ';' must end an expression, in Ocaml
                          >>> ';' is just used to separate a sequence of expressions (seldom needed).
                          >>>
                          >>> I fixed that.
                          >> There's a section on this page called "Using and omitting ;; and ;"
                          >> which explains the rules a bit:
                          >>
                          >> http://www.ocaml-tutorial.org/the_structure_of_ocaml_programs
                          >>
                          >> Basically you can omit ;; before any let, type, open, module, class
                          >> keyword (and a few others too), but you cannot omit it before any bare
                          >> expression.
                          >
                          > As sometimes being able to omit ;; depends on what follows one can consider a
                          > good idea to put them most of the time, this way when you modify the source
                          > code you won't end in a position where ;; is omited but required!
                          >
                          > In addition to this, as ocaml does not encloses the parameter with brackets,
                          > it often happens that when you add a parameter to a function (or forget it)
                          > you will encounter partial application where not expected.
                          > And the important point here is if you have no ;; in your source code, ocaml
                          > will provide an error message with the position given the very last char of
                          > the file. If you put the ;; the error message will be positioned on the right
                          > function.

                          Most if not all problems related to missing parentheses or separators
                          are trivially detected when using an editor that indents the code for
                          you. I've been using emacs with tuareg-mode for years and it does this well.

                          Just avoid putting too many different constructs on one line, and hit
                          the tab key to indent a line. It works great for detecting missing
                          parentheses around conditionals or match-cases.


                          Martin
                          --
                          http://mjambon.com/
                        • Florent Monnier
                          ... I think you have misunderstood what I said, well I know my English is quite bad, sorry for this. I do not talk about missing parentheses or separators or
                          Message 12 of 16 , Jan 6, 2009
                          • 0 Attachment
                            > Most if not all problems related to missing parentheses or separators
                            > are trivially detected when using an editor that indents the code for
                            > you. I've been using emacs with tuareg-mode for years and it does this
                            > well.
                            >
                            > Just avoid putting too many different constructs on one line, and hit
                            > the tab key to indent a line. It works great for detecting missing
                            > parentheses around conditionals or match-cases.

                            I think you have misunderstood what I said, well I know my English is quite
                            bad, sorry for this.

                            I do not talk about missing parentheses or separators or indentation.
                            My editor detects all this too.

                            I'm talking about partial application.
                            When you add a new parameter to a function, and forget to add this parameter
                            in the user code, it will result in an unexpected partial application.

                            In those case when trying to compile the user code, the error message will
                            point the last byte of the source code, which is not usefull to find the
                            location of the error.
                            In this case, you will have to add all the ;; terminators to all of your
                            functions in the source file, and only then ocaml will report the good
                            location for the error.
                          • Martin Jambon
                            ... My apologies, I was just giving some general advice to any beginners who might read this. I was not really replying to your message (and I m not sure which
                            Message 13 of 16 , Jan 6, 2009
                            • 0 Attachment
                              Florent Monnier wrote:
                              >> Most if not all problems related to missing parentheses or separators
                              >> are trivially detected when using an editor that indents the code for
                              >> you. I've been using emacs with tuareg-mode for years and it does this
                              >> well.
                              >>
                              >> Just avoid putting too many different constructs on one line, and hit
                              >> the tab key to indent a line. It works great for detecting missing
                              >> parentheses around conditionals or match-cases.
                              >
                              > I think you have misunderstood what I said, well I know my English is quite
                              > bad, sorry for this.
                              >
                              > I do not talk about missing parentheses or separators or indentation.
                              > My editor detects all this too.

                              My apologies, I was just giving some general advice to any beginners who
                              might read this.

                              I was not really replying to your message (and I'm not sure which
                              problem you are referring to, but I don't have such problem so I'm happy :-)


                              Martin

                              --
                              http://mjambon.com/
                            • Richard Jones
                              ... I think a better way to deal with this is to reduce the use of top lets, writing all/most code inside: let () = (* ... *) Rich. -- Richard Jones Red Hat
                              Message 14 of 16 , Jan 6, 2009
                              • 0 Attachment
                                On Tue, Jan 06, 2009 at 01:07:41PM +0100, Florent Monnier wrote:
                                > I'm talking about partial application.
                                > When you add a new parameter to a function, and forget to add this parameter
                                > in the user code, it will result in an unexpected partial application.

                                I think a better way to deal with this is to reduce the use of "top"
                                lets, writing all/most code inside:

                                let () =
                                (* ... *)

                                Rich.

                                --
                                Richard Jones
                                Red Hat
                              • Florent Monnier
                                ... No, this won t help much either because in fact when there is a partial application, ocaml cannot know if it is done deliberately or accidentally. So in
                                Message 15 of 16 , Jan 6, 2009
                                • 0 Attachment
                                  > > When you add a new parameter to a function, and forget to add this
                                  > > parameter in the user code, it will result in an unexpected partial
                                  > > application.
                                  >
                                  > I think a better way to deal with this is to reduce the use of "top"
                                  > lets, writing all/most code inside:
                                  >
                                  > let () =
                                  > (* ... *)

                                  No, this won't help much either because in fact when there is a partial
                                  application, ocaml cannot know if it is done deliberately or accidentally.
                                  So in such cases ocaml does not point in its error message the partial
                                  application, but the first ;; that follows the unexpected partial
                                  applicaiton.

                                  The first time I got this error when I was an earlier beginner, I really
                                  didn't know what to do with an error message that gives me as the position
                                  the very last byte of the file. I didn't even knew that it could be resolved
                                  just by adding ;; after each function.
                                  I finally discovered this by checking what was my last edit when this error
                                  was encountered.

                                  But indeed if you never encounter this error, you can omit the ;; but I do
                                  think that I was not the first beginner being confused with this error, so I
                                  think we should recommand to the beginners to do put the ;;
                                • Martin Jambon
                                  ... That s strange. ... Could you post some code that exhibits this problem? ... -- http://mjambon.com/
                                  Message 16 of 16 , Jan 6, 2009
                                  • 0 Attachment
                                    Florent Monnier wrote:
                                    >>> When you add a new parameter to a function, and forget to add this
                                    >>> parameter in the user code, it will result in an unexpected partial
                                    >>> application.
                                    >> I think a better way to deal with this is to reduce the use of "top"
                                    >> lets, writing all/most code inside:
                                    >>
                                    >> let () =
                                    >> (* ... *)
                                    >
                                    > No, this won't help much either because in fact when there is a partial
                                    > application, ocaml cannot know if it is done deliberately or accidentally.
                                    > So in such cases ocaml does not point in its error message the partial
                                    > application, but the first ;; that follows the unexpected partial
                                    > applicaiton.

                                    That's strange.

                                    > The first time I got this error when I was an earlier beginner, I really
                                    > didn't know what to do with an error message that gives me as the position
                                    > the very last byte of the file. I didn't even knew that it could be resolved
                                    > just by adding ;; after each function.
                                    > I finally discovered this by checking what was my last edit when this error
                                    > was encountered.

                                    Could you post some code that exhibits this problem?


                                    > But indeed if you never encounter this error, you can omit the ;; but I do
                                    > think that I was not the first beginner being confused with this error, so I
                                    > think we should recommand to the beginners to do put the ;;


                                    --
                                    http://mjambon.com/
                                  Your message has been successfully submitted and would be delivered to recipients shortly.