Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

(v2)

6 juillet 2011 à 10:50:09

inutilisable ? tu voit pas qu'au début j'affiche la grille avec les numérots, puis avec des espaces ?
et won est très compréhensible je t'assure ...
  • Partager sur Facebook
  • Partager sur Twitter
6 juillet 2011 à 13:30:19

Citation : PITETRE

inutilisable ? et won est très compréhensible je t'assure ...


C'est surtout pas générique et donc assez illisible je trouve.
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 11:16:49

@PITETRE Dans ton Tic-Tac-Toe, lorsque 'o' gagne, il affiche que 'x' gagne et inversement.
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 15:53:11

@@@@@

Voici ma correction pour le Triangle de Pascal, désolé pour le retard :

#include <stdio.h>

int foundCase(int L, int C)
{
   int i = 0, p=1;
   for(;i<C;++i)
      p = p*(L-i)/(i+1);
   return p;
}
void getFormat(char* format, int Line)
{
   int i, j;
   j = foundCase(Line-1, Line/2);
   for(i=1;j/=10;++i);
   sprintf(format, "%%%dd ", i);
}
void showPascalsTriangle(int x)
{
   int p = 1, j, i;
   char format[10];
   getFormat(format,x);
   
   for(i=0;i<x;++i)
   {
      printf("1 ");
      for(j=0;j<i;++j)
         printf(format, p = p*(i-j)/(j+1) );
      puts("");
      p = 1;
   }   
}
void showLine(int L)
{
   int p = 1, j;
   char format[10];
   getFormat(format, L);
   
   printf("1 ");
   for(j=0;j<L;++j)
      printf(format, p = p*(L-j)/(j+1) );
   puts("");
   p = 1;
   
}
int main(void)
{
   int choice, line, numcase;
   printf(  "1- afficher le triangle jusqu'a une ligne N.\n"
            "2- afficher une ligne N.\n"
            "3- afficher une case K,N.\n");
   scanf("%d", &choice);

   if(choice == 3)
   {
      puts("Choix de K ?");
      scanf("%d", &numcase);
   }
   if(choice>0 && choice < 4)
   {
      puts("Choix de N ?");
      scanf("%d", &line);
   }
   switch(choice)
   {
      case 1: showPascalsTriangle(line+1);break;
      case 2: showLine(line);break;
      case 3: printf("%d\n",foundCase(line, numcase));break;
      default: puts("Make a choice");
   } 

   return 0;
}


Toujours en C, mais facile à traduire.

  • Partager sur Facebook
  • Partager sur Twitter
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles  - ♡ Copying is an act of love.
7 juillet 2011 à 17:12:26

Je me permettrai de te faire remarquer qu'il y a toujours une sorte de problème sur ton affichage : il affiche toutes les colonnes à la même largeur. Ce qui n'est pas très économe en place.

Mais tu pourrais remarquer que, à part l'aération du code qui n'est pas la même (et le choix du langage), ton code se rapproche déjà beaucoup du mien. ;)
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 17:46:26

@che stp, fais attention à ton anglais, ça fait mal aux yeux... :D
de plus, tu mélanges avec le français 'make a chose' (qui ne veut pas dire grand chose soit dit en passant) :)
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
7 juillet 2011 à 18:25:02

Citation : germino

de plus, tu mélanges avec le français 'make a chose' (qui ne veut pas dire grand chose soit dit en passant) :)

C'est "Make a choice" AMHA...
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 18:32:30

en effet j'avait régler ce pb (je parle de l'inversion de x et o mais j'ai oublier de modifier le post ;) .
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 18:53:39

Dsl, je corrige tout de suite. ^^" Promis je révise l'anglais cet été ^^"

@ Equinoxe: Je me suis rapproché de la structure de ton code. Mais sinon, tout est différent (notamment le style du code/de l'indentation ).
Je me suis facilité la vie, plutôt que de recalculé le format pour chaque ligne, j'ai préféré le faire pour la ligne la plus grande. Si on veut réglé "le problème" il suffit de déplacer getformat() donc la boucle, mais ce sont des calculs inutiles je pense.
  • Partager sur Facebook
  • Partager sur Twitter
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles  - ♡ Copying is an act of love.
7 juillet 2011 à 19:30:40

Hop, voilà une solution au tic-tac-toe.
Elle est en C++0x (gcc 4.6), elle supporte un plateau de taille quelconque, et elle vient avec deux variantes du negamax pour l'IA -- au détail que l'algo sur wikipédia est faux, je ne vous dit pas le plaisir à débugguer.

Il reste à fignoler:
- les options pour configurer la taille du plateau (TCLAP, c'est bien pratique pour les options)
- les options pour la profondeur de recherche des IA
- les options pour dire combien il faut aligner de pions pour gagner
- trouver un moyen d’abréger les souffrances : les IA semblent prendre leur temps pour achever leurs victimes.
- implémenter d'autres IA comme negascout, etc

Ensuite, j'ai fait un chouilla trop compliqué pour certains trucs, et je n'ai plus trop de temps ni envie de refactoriser pour améliorer. Donc
- bof la gestion des joueurs et des cases
- séparation des responsabilités entre Game et Board à re-penser
- ça manque de commentaires
- c'est mono-fichier, mais ça c'est le moins grave, il suffit de suivre les pointillés
// licence GPL 3.0 (cf gnu.org, tout ça)
// (c) Luc H., 2011
#include <string>
#include <vector>
#include <stdexcept>
#include <limits>
#include <tuple>
#include <memory>
#include <fstream>
#include <ostream>
#include <iostream>

#include <cassert>

#define DEBUG_IA_LEVEL 0

enum class PlayerId {
    first=1, second=2
};
PlayerId operator++(PlayerId &id, int) { // todo: rename to next()
    PlayerId tmp = id;
    id=PlayerId(3-size_t(id));
    return tmp;
}
std::ostream & operator<<(std::ostream & os, const PlayerId & v) {
    const char c = (v==PlayerId::first ? 'X' : 'O');
    return os << c;
}

enum class CaseValue {
    none  =0,
    first =PlayerId::first,
    second=PlayerId::second
};

struct Case {
    Case(CaseValue v = CaseValue::none) : m_value(v) {}
    CaseValue value() const { return m_value; }
    char as_char() const {
        switch (m_value) {
            case CaseValue::first: return 'X';
            case CaseValue::second: return 'O';
            case CaseValue::none: return ' ';
        }
        assert(!"Invalid value");
    }
private:
    CaseValue m_value;
};
std::ostream& operator<<(std::ostream& os, Case c) {
    return os << c.as_char();
}

/*===========================================================================*/
/*==============================[ Coordinates ]==============================*/
/*===========================================================================*/
typedef std::tuple<size_t, size_t>       Coords;
typedef std::tuple<ptrdiff_t, ptrdiff_t> Delta;

Coords     & operator+=(Coords& c, Delta const& d) {
    std::get<0>(c) += std::get<0>(d);
    std::get<1>(c) += std::get<1>(d);
    return c;
}
Coords const operator+ (Coords  c, Delta const& d) {
    return c+=d;
}

Coords     & operator-=(Coords& c, Delta const& d) {
    std::get<0>(c) -= std::get<0>(d);
    std::get<1>(c) -= std::get<1>(d);
    return c;
}
Coords const operator- (Coords  c, Delta const& d) {
    return c-=d;
}

bool in_range(Coords const& c, Coords const& M) {
    return std::get<0>(c) >= 0
        && std::get<1>(c) >= 0
        && std::get<0>(c) <  std::get<0>(M)
        && std::get<1>(c) <  std::get<1>(M);
}

namespace std {
    ostream& operator<<(ostream&os, Coords const& c) {
        return os << '{' << std::get<0>(c) << ',' << std::get<1>(c) << '}';
    }
} // std namespace 


/*===========================================================================*/
/*=================================[ Board ]=================================*/
/*===========================================================================*/
struct Board
{
    Board(size_t L_, size_t C_)
        : m_board(L_*C_), m_L(L_), m_C(C_) {}
    Board(size_t L_=3)
        : m_board(L_*L_), m_L(L_), m_C(L_) {}
    // Board(Board && tmp)

    Case const& operator()(size_t l, size_t c) const {
        return board(l,c);
    }
    Case const& operator()(Coords c) const {
        return board(std::get<0>(c), std::get<1>(c));
    }

    bool is_empty(size_t l, size_t c) const {
        return board(l,c).value() == CaseValue::none;
    }
    bool set(size_t l, size_t c, CaseValue v) {
        if (board(l,c).value() != CaseValue::none) {
            return false;
        }
        board(l,c) = v;
        return true;
    }
    bool set(Coords const& c, CaseValue v) {
        return set(std::get<0>(c), std::get<1>(c), v);
    }
    void reset(size_t l, size_t c) {
        board(l,c) = CaseValue::none;
    }
    void reset(Coords const& c) {
        reset(std::get<0>(c), std::get<1>(c));
    }

    size_t L() const { return m_L; }
    size_t C() const { return m_C; }
    Coords M() const { return Coords{L(), C()}; }
private:
    Case      & board(size_t l, size_t c) {
        assert(l < L());
        assert(c < C());
        return m_board[l*C()+c];
    }
    Case const& board(size_t l, size_t c) const {
        return const_cast <Board*>(this)->board(l,c);
    }
    std::vector<Case> m_board;
    size_t            m_L;
    size_t            m_C;
};

std::ostream & draw_line(std::ostream& os , size_t C)
{
    os << '+';
    for (size_t c=0; c!=C ; ++c) 
        os << "-+";
    return os;
}

std::ostream& operator<<(std::ostream&os, Board const& b) {
    draw_line(os, b.C());
    for (size_t l=0; l!=b.L() ; ++l) {
        os << "\n|";
        for (size_t c=0; c!=b.C() ; ++c) {
            os << b(l,c) << '|';
        }
        draw_line(os<<'\n', b.C());
    }
    return os << '\n';
}

/*===========================================================================*/
/*========================[ Player Decision Centers ]========================*/
/*===========================================================================*/
struct Game;

struct PlayerDC
{
    virtual ~PlayerDC() {};
    virtual Coords choose(Game &) const = 0;

protected:
    PlayerDC() {}
    PlayerDC           (PlayerDC const&) = delete;
    PlayerDC& operator=(PlayerDC const&) = delete;
};

struct Player
{
    Player(std::unique_ptr<PlayerDC>&& dc, std::string && name_)
        : m_dc(std::move(dc))
        , m_name(name_)
        {
            assert(m_dc);
        }
    Coords choose(Game & b) const { return m_dc->choose(b); }
    std::string const& name() const { return m_name; }
private:
    std::unique_ptr<PlayerDC> m_dc;
    std::string               m_name;
};

std::ostream & operator<<(std::ostream & os, const Player & v) {
    return os << v.name();
}



/*===========================================================================*/
/*=================================[ Game ]==================================*/
/*===========================================================================*/
struct Game
{
    Game(size_t L_=3, size_t C_=0, size_t nb_required_to_win = 0)
        : m_nb_moves(0)
        , m_board(L_, C_?C_:L_)
        , m_nb_required_to_win(nb_required_to_win ? nb_required_to_win : L_)
        {}

    bool can_play_at(size_t l, size_t c) const {
        return m_board.is_empty(l,c);
    }
    bool set(Coords c, PlayerId p) {
        return m_board.set(c,CaseValue(size_t(p)));
    }
    void reset(Coords const& c) {
        m_board.reset(c);
    }

    template <class F> void for_each_possible_move(F f) {
        bool cont = true;
        for (size_t l=0; cont && l!=m_board.L() ; ++l)
            for (size_t c=0; cont && c!=m_board.C() ; ++c)
                if(can_play_at(l,c))
                    cont = f(Coords{l,c});
    }

    bool is_a_winning_move_for(Coords c, PlayerId p) const {
        const CaseValue v = CaseValue(size_t(p)) ;
        // vert
        if (check_orth<0>(c,v)) { return true; }
        // horiz
        if (check_orth<1>(c,v)) { return true; }
        // diag 1
        if (check_diag(c,v, Delta{1, 1})) { return true; }
        // diag 2
        if (check_diag(c,v, Delta{1, -1})) { return true; }
        return false;
    }

    void push(std::unique_ptr<PlayerDC> && player, std::string && name) {
        assert(player);
        m_players.push_back(Player(std::move(player), std::move(name)));
    }

    void run()
    {
        PlayerId player = m_nb_moves%2 == 0 ? PlayerId::first : PlayerId::second;
        while (m_nb_moves != L() * C()) {
            Player & p =  m_players[size_t(player)-1];
            std::cout
                <<"Moves: " << m_nb_moves
                << " ; Player " << size_t(player) << ", " << p.name() << ", ";
            Coords c = p.choose(*this);
            assert(in_range(c, board().M())); // choose() post constract
            if (set(c, player)) {
                std::cout << board();
                if (is_a_winning_move_for(c, player)) {
                    std::cout << "Player " << size_t(player) << ", " << p.name() << ", has won!\n";
                    return;
                }
                player++;
                m_nb_moves ++;
            } else {
                std::cout << "Cannot play there, try again.\n";
            }
        }
        std::cout << "Draw. Nobody wins.\n";
    }

    Board const& board() const { return m_board; }
    size_t       L()     const { return m_board.L(); }
    size_t       C()     const { return m_board.C(); }
    Coords       M()     const { return m_board.M(); }
private:

    template <size_t Dir> bool check_orth(Coords c, const CaseValue v) const
    {
        size_t nb = 1; // crt
        for (Coords t = c ; std::get<Dir>(t) > 0 ; ++nb) {
            std::get<Dir>(t)-- ;
            if ((m_board)(t).value() != v) break;
        }
        for (Coords t = c ; std::get<Dir>(t) < std::get<Dir>(m_board.M())-1 ; ++nb) {
            std::get<Dir>(t)++ ;
            if ((m_board)(t).value() != v) break;
        }
        return (nb >= m_nb_required_to_win) ;
    }

    bool check_diag(Coords c, CaseValue v, Delta d) const {
        size_t nb = 1; // crt
        for (Coords t = c ; ; ++nb) {
            t -= d;
            if (!in_range(t, m_board.M()))  break; 
            if ((m_board)(t).value() != v) break;
        }
        for (Coords t = c ; ; ++nb) {
            t += d;
            if (!in_range(t, m_board.M()))  break; 
            if ((m_board)(t).value() != v) break;
        }
        return (nb >= m_nb_required_to_win) ;
    }

    // game dynamic data
    size_t              m_nb_moves;
    // game static data
    Board               m_board;
    size_t              m_nb_required_to_win;
    std::vector<Player> m_players;

    friend std::istream & operator>>(std::istream & is,  Game & v);
};

std::istream & operator>>(std::istream & is,  Game & v)
{
    std::vector<std::string> lines;
    std::string line;
    size_t C;
    while (std::getline(is, line)) { // till eof
        if (line[0] == '|') {
            lines.push_back(line);
            C =  (line.size()-1)/2;
        } else if (line == "<<EOF") {
            break;
        }
    }
    // if (is) {
        Board b(lines.size(), C);
        v.m_nb_moves = 0;
        for (size_t l=0, L=b.L(); l!=L ; ++l) {
            for (size_t c=0,C=b.C(); c!=C ; ++c) {
                switch (lines[l][c*2+1]) {
                    case 'X':
                        b.set(l,c,CaseValue::first);
                        v.m_nb_moves++;
                        break;
                    case 'O':
                        b.set(l,c,CaseValue::second);
                        v.m_nb_moves++;
                        break;
                }
            }
        }
        // std::cout << b;
        v.m_board = std::move(b);
    // }
    return is ;
}

/*===========================================================================*/
/*========================[ Player Decision Centers ]========================*/
/*===========================================================================*/

/*===============================[ LocalPlayerDC : cin/cout ]================*/
struct LocalPlayerDC : PlayerDC {
    virtual Coords choose(Game & g) const {
        size_t l, c;
        while (! (std::cout << "Where? (x y)" && (std::cin >> l >> c) && l<g.L() && c<g.C())) {
            if (std::cin.eof()) {
                throw std::runtime_error("\nAh ah, you gave up!");
            } else if (std::cin.fail()) {
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                std::cout << "Invalid numbers, try again: ";
            } else if (l>=g.L()) {
                std::cout << "line out of range [0,"<<g.L()<<"[, try again: ";
            } else if (c>=g.C()) {
                std::cout << "column out of range [0,"<<g.C()<<"[, try again: ";
            } else {
                assert(!"unexpected case");
            }
        }
        return Coords{l, c};
    }
};

/*===============================[ IAPlayerDC : negamax ]====================*/
struct NegaMaxPlayerDC : PlayerDC
{
    NegaMaxPlayerDC(size_t depth, PlayerId id) : m_depth(depth), m_id(id) {}

    virtual Coords choose(Game & g) const {
        Coords best=g.M();
        int max = std::numeric_limits<int>::min();
        g.for_each_possible_move([&](Coords const& where) -> bool {
                g.set(where,this->m_id); // push the current move
                int eval = - this->negamax(g, this->m_depth, this->m_id, where);
                g.reset(where);   // pop the move
                if (eval > max) {
                    max = eval;
                    best = where;
                }
                return true; // continue
            });
        std::cout << "negamax plays at " << best << " (" << max << ")\n";
        if (max > +950)
            std::cout << "You'll loose!\n";
        else if (max < -950)
            std::cout << "You should win...\n";
        return best;
    }
private:
    int negamax(Game & g, size_t depth, PlayerId who, Coords const& current) const noexcept
    {
#if DEBUG_IA_LEVEL > 0
        const std::string indent (4*(6-depth), ' ');
        std::cout << indent << "negamax(" << current << ", " <<depth<<", "<<who
            // << ", alpha="<<alpha << ", beta= "<<beta
            << ")\n";
#if DEBUG_IA_LEVEL > 1
        std::cout << g.board();
#endif
#endif

        // terminal conditions => heuristic
        if (g.is_a_winning_move_for(current, who)) {
            // const int found = (1000) * (who==this->m_id ? 1 : -1);
            const int found = -(1000) + depth;
#if DEBUG_IA_LEVEL > 0
            std::cout << indent << "  "<<current<<"-> ... winning move => "<<found<<"("<<who<< ")\n" ;
#endif
            return found;
        } else if (depth == 0) {
#if DEBUG_IA_LEVEL > 0
            std::cout << indent << "  "<<current<<"-> ... exploration leaf => "<<0<<"("<<who<< ")\n" ;
#endif
            return 0; // should return how many openings there are
        }

        // else loop on all children nodes
        int max = std::numeric_limits<int>::min();
#if DEBUG_IA_LEVEL > 0
        Coords best=g.M();
#endif
        PlayerId adv = who; adv ++;
        g.for_each_possible_move(
            [&](Coords const& child_node) -> bool {
                g.set(child_node,adv); // push the current move
                int eval = - this->negamax(g, depth-1, adv, child_node);
                g.reset(child_node);   // pop the move
                if (eval > max) {
                    max = eval;
#if DEBUG_IA_LEVEL > 0
                    best= child_node;
#endif
                }
                return true; // continue
            });
        if (max == std::numeric_limits<int>::min()) { // no child node
            max = 0;
        }
#if DEBUG_IA_LEVEL > 0
        std::cout << indent << "  "<<current<<"-> best move="<<best<<" => "<<max<<"("<<who<< ")\n" ;
#endif
        return max;
    }

    const size_t   m_depth;
    const PlayerId m_id;
};


/*===============================[ IAPlayerDC : negamax alpha-beta ]=========*/
struct NegaMaxPlayerAlphaBetaDC : PlayerDC
{
    NegaMaxPlayerAlphaBetaDC(size_t depth, PlayerId id) : m_depth(depth), m_id(id) {}

    virtual Coords choose(Game & g) const {
#if DEBUG_IA_LEVEL > 0
        std::cout << "\n";
#endif
        Coords best=g.M();
        int max = std::numeric_limits<int>::min();
        int alpha = -1000;
        int beta  = +1000;
        g.for_each_possible_move([&](Coords const& where) -> bool {
                g.set(where,this->m_id); // push the current move
                int eval = - this->negamax(g, this->m_depth, this->m_id, where, -beta, -alpha);
                g.reset(where);   // pop the move
                if (eval > max) {
                    max = eval;
                    best = where;
                }
                if (eval > alpha) {
                    alpha = eval;
                    if (alpha >= beta) {
                        return false; // abort loop
                    }
                }
                return true; // continue
            });
        std::cout << "negamax plays at " << best << " (" << max << ")\n";
        if (max > +950)
            std::cout << "You'll loose!\n";
        else if (max < -950)
            std::cout << "You should win...\n";
        return best;
    }
private:
    int negamax(Game & g, size_t depth, PlayerId who, Coords const& current, int alpha, int beta) const noexcept
    {
#if DEBUG_IA_LEVEL > 0
        const std::string indent (4*(6-depth), ' ');
        std::cout << indent << "negamax(" << current << ", " <<depth<<", "<<who
            // << ", alpha="<<alpha << ", beta= "<<beta
            << ")\n";
#if DEBUG_IA_LEVEL > 1
        std::cout << g.board();
#endif
#endif

        // terminal conditions => heuristic
        if (g.is_a_winning_move_for(current, who)) {
            // const int found = (1000) * (who==this->m_id ? 1 : -1);
            const int found = -(1000) + depth;
            // todo: find a way to shorten the suffering! (+depth is not
            // enough)
#if DEBUG_IA_LEVEL > 0
            std::cout << indent << "  "<<current<<"-> ... winning move => "<<found<<"("<<who<< ")\n" ;
#endif
            return found;
        } else if (depth == 0) {
#if DEBUG_IA_LEVEL > 0
            std::cout << indent << "  "<<current<<"-> ... exploration leaf => "<<0<<"("<<who<< ")\n" ;
#endif
            return 0; // should return how many openings there are
        }

        // else loop on all children nodes
        int max = std::numeric_limits<int>::min();
#if DEBUG_IA_LEVEL > 0
        Coords best=g.M();
#endif
        PlayerId adv = who; adv ++;
        g.for_each_possible_move(
            [&](Coords const& child_node) -> bool {
                g.set(child_node,adv); // push the current move
                int eval = - this->negamax(g, depth-1, adv, child_node, -beta, -alpha);
                g.reset(child_node);   // pop the move
                if (eval > max) {
                    max = eval;
#if DEBUG_IA_LEVEL > 0
                    best= child_node;
#endif
                }
                if (eval > alpha) {
                    alpha = eval;
                    if (alpha >= beta) {
                        return false; // abort loop
                    }
                }
                return true; // continue
            });
        if (max == std::numeric_limits<int>::min()) { // no child node
            max = 0;
        }
#if DEBUG_IA_LEVEL > 0
        std::cout << indent << "  "<<current<<"-> best move="<<best<<" => "<<max<<"("<<who<< ")\n" ;
#endif
        return max;
    }

    const size_t   m_depth;
    const PlayerId m_id;
};



/*===========================================================================*/
/*=================================[ main ]==================================*/
/*===========================================================================*/
int main (int argc, char **argv)
{
    if (argc < 3) {
        std::cout << "Usage: " << argv[0] << " [options] <player> <player>"
            << "\n\t[options]"
            << "\n\t\t--board <filename>"
            << "\n\t<player>"
            << "\n\t\tn==ai player, (n)egamax"
            << "\n\t\ta==ai player, negamax-(a)lphabeta"
            << "\n\t\th==(h)uman player";
        return EXIT_FAILURE;
    }
    try
    {
        Game g(8,8,4);
        PlayerId id = PlayerId::first;
        for (int i=1; i!=argc ; ++i) {
            const std::string opt=argv[i];
            if (opt == "--board" || opt=="-b") {
                std::ifstream f(argv[++i]);
                if (!f) {
                    throw std::runtime_error("Cannot open " + std::string(argv[i]));
                }
                f >> g;
            } else if (opt == "n" || opt=="negamax") {
                g.push(std::unique_ptr<PlayerDC>(new NegaMaxPlayerDC(3, id)), "(AI-negamax)");
                id++;
            } else if (opt == "a" || opt=="negamax-ab") {
                g.push(std::unique_ptr<PlayerDC>(new NegaMaxPlayerAlphaBetaDC(8, id)), "(AI-negamax-AB)");
                id++;
            } else if (opt == "h" || opt=="human") {
                g.push(std::unique_ptr<PlayerDC>(new LocalPlayerDC()), "(Human)");
                id++;
            } else {
                g.push(std::unique_ptr<PlayerDC>(new LocalPlayerDC()), "opt");
                id++;
                // std::cerr << argv[0] << ": invalid option != i/h\n";
                // return EXIT_FAILURE;
            }
        }
        // scenario
#if 0
        g.set(0, 0, PlayerId::first);
        g.set(1, 1, PlayerId::second);
        g.set(0, 1, PlayerId::first);
        g.set(0, 2, PlayerId::second);
#endif

        std::cout << g.board();
        g.run();
    } catch (std::exception const& e) {
        std::cerr << e.what() << '\n';
    }
}
// Vim: let $CXXFLAGS='-std=c++0x -g -pedantic -Wall'
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
7 juillet 2011 à 19:39:10

Citation : lmghs

- ça manque de commentaires


^^
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 20:11:31

Je n'ai pas tout lu (en fait, j'ai sauté la partie IA), mais j'aurais juste à dire que check_orth et check_diag pourraient être fusionnées, au pris d'un poil de performance : il suffirait d'appeller check_diag({0, 1}); et check_diag({1, 0}) pour ne plus avoir besoin de check_orth. De là, on pourrait supprimmer check_orth, et ne plus avoir qu'une fonction de check.

En tout cas, merci pour ce code !

Edit : Maintenant j'ai tout lu, et je pense qu'il y a eu une unexpected erreur sur ce même mot. :p
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 21:12:37

lmghs, ton code ne correspond à l'attente de débutant, en revanche il est extrêmement complet, et propre et donc on en apprend beacoup, c'est pourquoi je propose de faire plusieures difficultées pour le Tic-Tac-Toe, du style niveau 1 la grille onjoue normale, 2 (ou plus tard, je sais pas) ajout d'une IA
  • Partager sur Facebook
  • Partager sur Twitter
7 juillet 2011 à 22:55:48

@lmghs, GPL (V3 en plus) vraiment? Tu me déçois :€.

Plus sérieusement, si j'ai le temps je regarde demain matin pendant mon café.
Btw, j'aimerais bien voir à l'occasion ta correction de l'interpréteur befunge, juste pour voir jusqu'où tu la poussé.
  • Partager sur Facebook
  • Partager sur Twitter
8 juillet 2011 à 1:32:32

@equinoxe, j'y avais pensé. Et puis finalement pour des raisons d'optim, j'ai préféré gratter un chouilla là où je le pouvais par anticipation (oui, c’est une optim prématurée ^^'). Pourquoi ? À cause des recherches de nœuds qui prennent pas mal de temps -- je ne pense pas gagner 1%, mais c'est toujours ça de pris.

Je n'ai pas compris l'histoire du unexpected-error.

@PITETRE, il y a effectivement plusieurs constructions qui ne sont pas pour débutants. Plus mes expérimentations dont les enum class qui n'aident pas les choses. Cependant, pour la partie Board, et les parties PlayerDC, je pense que c'est important, même pour les débutants.
Et on rejoint au passage une digression sur la pertinence du OO dans les exos.

@Goten. Ben .. si je n'avais rien mis, c'eut été le droit d'auteur pur et dur, et donc totalement inutilisable sans accord écrit de ma part, tout ça. Le tout n'étant pas une lib, choses pour lesquelles je préfère le non intrusif et donc du BSL p.ex., GPL m'a paru bien.

Pour befunge, c'est du befunge 98. Le code aujourd'hui est encore bien plus dégueulasse que celui du morpion (constructeur à rallonge: il contient des définitions de lambdas en pagaille). Je vous le passerai à l'occasion. Il n'a rien d'exceptionnel. Je l'ai poussé pour qu'il passe pas mal de tests de micose (ou un nom qui ressemble)

Ce qui me fait penser à mon expérimentation sur le thème des polynômes: http://www.siteduzero.com/forum-83-257 [...] html#r3690723 (dans la catégorie "autres solutions"). Elle est intéressante pour les définitions des opérations mathématiques, en particulier * qui se fait à l'envers des bonnes pratiques usuelles ; et pour les TU.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
8 juillet 2011 à 12:15:31

Pour unexpected, c'était à ce passage que je faisais allusion : assert(!"unexcepted case"). Une petite typo de rien du tout. :)
Edit : typo moi-même.
  • Partager sur Facebook
  • Partager sur Twitter
8 juillet 2011 à 12:50:35

Bien vu, merci.
Je mettrais ça sur github à l'occas si vous voulez l'enrichir/corriger, etc.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
8 juillet 2011 à 19:42:34

@lmghs : avec ma version de gcc, il a fallu rajouter std:: devant size_t pour que ça compile.

Sinon, est-ce normal que les IA soient si lentes ? Elles prennent plusieurs minutes par coup chez moi.

Edit : tu as inversé x et y.
  • Partager sur Facebook
  • Partager sur Twitter
Administrateur du forum Paul Diel
9 juillet 2011 à 2:39:27

Oui c'est normal, je les ai réglées à 6 coups de profondeur si mes souvenirs sont exacts -- et je n'arrive toujours pas à les faire jouer au milieu du plateau.
Rajoute une une grille 8x8 et c'est la cata. J'ai laissé tombé les 10x10 du coup.
  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
9 juillet 2011 à 15:54:18

@Equinoxe : peux-tu m'envoyer par mp les flammes de niveau 1/2/3/4/5 ?
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2011 à 13:12:24

Biblio++



Catégorie : gestion de BDD



Le but de cet exercice, est de réaliser un logiciel de gestion d'une bibliothèque. Comme la mairie n'est pas richissime, elle vous a demandé de réaliser un programme en console :D .

Niveau 1



Vous devez pouvoir lire et écrire dans un/plusieurs fichier(s) la base de donnée qui est composée pour chaque entrée de :
  • Auteur
  • Titre
  • Genre
  • Un n° unique à chaque livre


Niveau 2



Il faut que votre logiciel communique ! Votre but est que les actions suivantes soient disponibles :
  • Ajouter un livre
  • Supprimer un livre
  • Affichage d'un livre
  • Afficher la liste des livres (attention, débrouillez-vous pour que la liste s'affiche morceau par morceau, la console a tendance à avoir une limite en hauteur)
  • Modifier les données d'un livre


Niveau 3



Pour que ce soit vraiment un logiciel de bibliothèque il manque ceci :
  • Données à ajouter à la BDD :
    • Date du dernier emprunt
    • Date du dernier retour

  • Actions possibles :
    • Emprunter
    • Rendre
    • Afficher la liste des livres empruntés



Niveau 4



Ben maintenant faut ajouter les membres de la bibliothèque dans une nouvelle base de donnée !
  • Données à ajouter à la seconde BDD pour chaque membre :
    • Nom
    • Prénom
    • n° (ou ID)

  • Données à ajouter à la première BDD pour chaque livre :
    • n° (ou ID) de l'emprunteur

  • Actions possibles :
    • Ajouter un membre
    • Afficher la liste des livres empruntés par un membre


Vous devez bien sûr adapter vos actions précédentes :)

Niveau 5



Maintenant, fini de laisser tout le sale boulot à la bibliothécaire !
Les n° des livres et des membres, c'est au logiciel de les calculer lui-même !
Pour les membres, c'est faciles, vous comptez 0;1;2;3;4;5;6;7;8;9;10;11;... ^^
Pour les livres, voyez ici :
http://fr.wikipedia.org/wiki/Classific [...] male_de_Dewey
http://www.mrugala.net/Divers/Dewey.html (amusez-vous bien !)

Cet exercice se situerait en 005 :)

Aller plus loin



Vous avez tout fait ? Ben figurez-vous que la bibliothèque, grâce à votre logiciel, a décidé de se transformer en médiathèque ! Ajouter donc les DVDs, les CDs audio, les jeux de société, et les logiciels (+ jeux)... (il n'existe pas de classification, peut-être en inventerez-vous une ?

Amusez-vous bien !
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2011 à 13:28:19

Sympa ce nouveau exercice. Cependant, j'ai une question:
Dans le niveau 1, quand tu dit un numéro unique pour chaque livre, cela signifie-t-il que l'utilisateur doit le renseigner puis le programme vérifie s'il n'est pas déjà utilisé, ou bien le programme le génère lui même d'une certaine façon pour qu'il ne soit pas réutilisé ?
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2011 à 15:08:16

Citation : Metallica-z80

Sympa ce nouveau exercice. Cependant, j'ai une question:
Dans le niveau 1, quand tu dit un numéro unique pour chaque livre, cela signifie-t-il que l'utilisateur doit le renseigner puis le programme vérifie s'il n'est pas déjà utilisé, ou bien le programme le génère lui même d'une certaine façon pour qu'il ne soit pas réutilisé ?


Et bien dans le niveau 1 tu fais comme tu veux, mais au niveau 5, on te demande que ce soit le programme qui s'en charge !
  • Partager sur Facebook
  • Partager sur Twitter
13 juillet 2011 à 15:19:50

OK, je m'y met (au niveau 1 pour l'instant).
  • Partager sur Facebook
  • Partager sur Twitter
14 juillet 2011 à 10:10:25

Cet exercice est bien pensé pour l’entraînement, la difficulté est progressive, il est vraiment comme il faut ^^
  • Partager sur Facebook
  • Partager sur Twitter
14 juillet 2011 à 12:18:15

J'ai fini le Biblio++ au niveau 2, voici mon code :

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <conio.h>
#include "Livre.h"

using namespace std;

int main()
{
    vector<Livre*> listeLivre;
    int numeroUnique(0), nombreLivre(-1);
    cout << "Biblio++, le logiciel de gestion d'une bibliotheque" << endl << endl;
    int choixMenu;
    do
    {
        cout << endl << "Que voulez vous faire ?" << endl;
        cout << "1 : Ajouter un livre" << endl;
        cout << "2 : Supprimer un livre" << endl;
        cout << "3 : Afficher tout les livres" << endl;
        cout << "4 : Afficher un livre" << endl;
        cout << "5 : Modifier un livre" << endl;
        cout << "6 : Quitter" << endl;
        cin >> choixMenu;
        switch(choixMenu)
        {
            case 1:     ++nombreLivre;
                        listeLivre.push_back(new Livre(nombreLivre));
                        listeLivre[nombreLivre]->modifie(*listeLivre[nombreLivre]);
                break;
            case 2:     if(nombreLivre >= 0)
                        {
                            --nombreLivre;
                            listeLivre.pop_back();
                        }
                break;
            case 3:     for(int i = 0; i <= nombreLivre; i++)
                        {
                            listeLivre[i]->affiche(*listeLivre[i]);
                            getch();
                        }
                break;
            case 4:     cout << "Entrez le Numero unique du livre a consulter :" << endl;
                        cin >> numeroUnique;
                        if (numeroUnique <= nombreLivre && numeroUnique >= 0)
                            listeLivre[numeroUnique]->affiche(*listeLivre[numeroUnique]);
                        else
                            cout << "Ce livre n'existe pas !" << endl;
                break;
            case 5:     cout << "Entrez le Numero unique du livre a modifier :" << endl;
                        cin >> numeroUnique;
                        if (numeroUnique <= nombreLivre && numeroUnique >= 0)
                            listeLivre[numeroUnique]->modifie(*listeLivre[numeroUnique]);
                        else
                            cout << "Ce livre n'existe pas !" << endl;
                break;
        }

    }while (choixMenu != 6);
    return 0;
}


Livre.h

#ifndef LIVRE_H_INCLUDED
#define LIVRE_H_INCLUDED

#include <string>
#include <vector>

class Livre
{
    public:
        Livre(int numeroUnique);
        void affiche(Livre &livre) const;
        void modifie(Livre &livre);
        std::string getAuteur(Livre &livre) const;
        std::string getTitre(Livre &livre) const;
        std::string getGenre(Livre &livre) const;

    private:

        std::string m_auteur;
        std::string m_titre;
        std::string m_genre;
        int m_numeroUnique;
};


#endif // LIVRE_H_INCLUDED


Livre.cpp

#include "Livre.h"
#include <iostream>
#include <string>

using namespace std;

Livre::Livre(int numeroUnique) : m_auteur(""), m_titre(""), m_genre(""), m_numeroUnique(numeroUnique)
{};


void Livre::affiche(Livre &livre) const
{
    cout << endl << "Auteur : " << livre.m_auteur << endl;
    cout << "Titre : " << livre.m_titre << endl;
    cout << "Genre : " << livre.m_genre << endl;
    cout << "Numero unique : " << livre.m_numeroUnique << endl;
};

void Livre::modifie(Livre &livre)
{
    cin.ignore();
    cout << "Auteur : ";
    getline(cin, livre.m_auteur);
    cout << "Titre : ";
    getline(cin, livre.m_titre);
    cout << "Genre : ";
    getline(cin, livre.m_genre);
};



Bon OK, mon programme n'écrit pas dans un BDD. J'ai essayer mais il y avait toujours des problèmes de compilation donc j'ai abandonné :-° (Si le bibliothécaire ne ferme jamais le programme, il n'y a pas de problèmes et puis voilà ! :lol: ). Vivement que d'autre membres poste leurs codes pour que je vois ce qui n'allait pas dans le mien.
  • Partager sur Facebook
  • Partager sur Twitter
14 juillet 2011 à 18:04:14

Citation : nours59

Cet exercice est bien pensé pour l’entraînement, la difficulté est progressive, il est vraiment comme il faut ^^


Merci :)

@Metallica-z80 : c'est dommage pour la BDD... tu peux nous montrer le code qui marche pas ?
  • Partager sur Facebook
  • Partager sur Twitter
14 juillet 2011 à 18:08:55

Dans l'ancien tuto sur les notions avancées, j'avais proposé un exercice de conception. Comme il est maintenant passé hors-ligne, je vous le remets ici.

Je posterai une solution dans quelques temps.

---------------------------------------------------------------------

TP - Le site du zéro



Notions : conception, classes, héritage, polymorphisme.
Niveau : 3/5

Contexte



Bravo ! Le site du zéro vient de vous engager pour un stage. Vos compétences en programmation ont séduit le jury de sélection et c'est avec une fierté non dissimulée que vous arrivez dans les bureaux pour votre première journée de travail.

Après plusieurs années à se développer sur le web, le site du zéro a décidé de s'orienter vers les logiciels pour pouvoir fournir ses services aux gens qui n'ont pas accès à Internet en permanence. C'est pour développer ce côté-ci de l'entreprise que vous avez été engagé.

La première partie du travail consiste à développer une interface de gestion des différents tutoriels du site pour permettre aux administrateurs de modifier et organiser les cours. Ceci devra être fait en C++ afin de pouvoir être utilisé sur tous les systèmes d'exploitation imaginables. Dans un premier temps, tout se fera en console.

Toute ressemblance avec des faits réels n'est que fortuite. :)

Voici le cahier des charges que l'on vous a fourni.

Cahier des charges



Sur le site du zéro, on trouve 3 types de tutoriels :
  • les Articles ;
  • les Mini-tutos ;
  • les Big-tutos.


Les Articles contiennent un lien vers le site qu'ils décrivent.

Les Mini-tutos contiennent un certain nombre (entier) de parties.

Les Big-tutos sont composés de plusieurs Mini-tutos.

Tous les tutoriels contiennent un titre.

Le programme doit fournir un moyen d'afficher les informations de chaque tutoriel (de quelque sorte qu'il soit). Les big-tutos doivent également fournir un moyen d'ajouter des chapitres.

Voilà pour les tutoriels. Pour ranger et classifier ceux-ci, le site du zéro possède une interface appelée « Vos Tutos » qui se comporte globalement comme une liste de tutoriels (de toutes les sortes) et qui a les fonctionnalités suivantes :

  • Afficher le nombre total de tutos.
  • Afficher tous les tutoriels.
  • Ajouter un tutoriel à la liste.
  • Supprimer un tutoriel.


Chaque tutoriel se voit attribuer un numéro (sa position dans la liste) et la suppression d'un tutoriel passe par ce numéro.

L'exercice



Ok, mais on doit faire quoi ?


Eh bien, c'est simple. Vous devez écrire un ensemble de classes et de fonctions qui reproduisent la description donnée ci-dessus.
Il n'y a pas plus d'indications puisque le but de l'exercice est justement la modélisation d'un problème donné.

Pour vérifier que votre programme fonctionne, le main suivant devra compiler :

#include "Tutos.hpp"
#include "VosTutos.hpp"

int main()
{
// Création du module VosTutos.

    VosTutos SdZ;

// Création d'un big tuto.

    MiniTuto chap1("Les bases du C++",4);
    MiniTuto chap2("La métaprogrammation récursivement polymorphique appliquée au RAII",12);
    MiniTuto chap3("Un TP bien trop dur",5);

    BigTuto tuto1("[C++] C++ roxx");
    tuto1.ajouteChapitre(&chap1);
    tuto1.ajouteChapitre(&chap2);
    tuto1.ajouteChapitre(&chap3);

// Création d'un mini-tuto.

    MiniTuto tuto2("[C++] Les namespaces",3);

// Création d'un article.

    Article tuto3("La librairie Boost", "www.boost.org");

// Ajout des tutos au "site".

    SdZ.ajouteTuto(&tuto1);
    SdZ.ajouteTuto(&tuto2);
    SdZ.ajouteTuto(&tuto3);

// Affichage de l'ensemble des tutoriels du "site".

    SdZ.affiche();

// Suppression du mini-tuto.

    SdZ.supprimeTuto(1);

// Fin du programme.

    return 0;
}


Ce programme devra afficher le résultat suivant:
Le tutoriel 'Les bases du C++' a bien été créé.
Le tutoriel 'La métaprogrammation récursivement polymorphique appliquée au RAII' a bien été créé.
Le tutoriel 'Un TP bien trop dur' a bien été créé.
Le tutoriel '[C++] C++ roxx' a bien été créé.
Le tutoriel '[C++] Les namespaces' a bien été créé.
Le tutoriel 'La librairie Boost' a bien été créé.
Votre tutoriel a bien été ajouté.
Votre tutoriel a bien été ajouté.
Votre tutoriel a bien été ajouté.

Le Site du zéro contient les tutoriels suivants :

0) BIG-TUTO
Titre : [C++] C++ roxx
Nombre de chapitres : 3
Sommaire : 
MINI-TUTO
Titre : Les bases du C++
Nombre de sous-parties : 4
MINI-TUTO
Titre : La métaprogrammation récursivement polymorphique appliquée au RAII
Nombre de sous-parties : 12
MINI-TUTO
Titre : Un TP bien trop dur
Nombre de sous-parties : 5

1) MINI-TUTO
Titre : [C++] Les namespaces
Nombre de sous-parties : 3

2) ARTICLE
Titre: La librairie Boost
Lien : www.boost.org

Votre tutoriel a été supprimé correctement du site.
Le tutoriel 'La librairie Boost' a été correctement détruit.
Le tutoriel '[C++] Les namespaces' a été correctement détruit.
Le tutoriel '[C++] C++ roxx' a été correctement détruit.
Le tutoriel 'Un TP bien trop dur' a été correctement détruit.
Le tutoriel 'La métaprogrammation récursivement polymorphique appliquée au RAII' a été correctement détruit.
Le tutoriel 'Les bases du C++' a été correctement détruit.


Bon, assez parlé. À vous de travailler un peu !

Astuces



Si vous ne savez pas comment commencer ou comment continuer, cette section est faite pour vous aider. Tout ce dont vous avez besoin est présenté dans les parties I et II du cours officiel, c'est seulement une liste des questions que vous devriez vous poser.

Le mieux serait que vous n'utilisiez pas du tout cette partie et que vous passiez directement à la résolution. ;)

Par quoi dois-je commencer ?

Lisez plusieurs fois la description du problème et essayez de la reformuler de sorte qu'elle soit claire pour vous.
Essayez de faire un « dessin » de ce que vous allez devoir programmer.
Ensuite, aidez-vous du main() pour mettre des noms et des concepts C++ sur votre dessin.


Quelles classes dois-je créer ?

Combien « d'entités » différentes pouvez-vous voir dans la description donnée ?
Essayez de mettre un nom sur chacune de ces entités.


Entre quelles classes dois-je créer un héritage ?

Pouvez-vous dire qu'une classe EST UNE autre ou EST IMPLÉMENTÉE SOUS FORME DE une autre ?
Si oui, alors l'héritage se justifie. Sinon, alors il n'y a pas de lien (de ce type) entre les deux classes.


Dois-je utiliser l'héritage public ou privé ?

Tout dépend si la classe fille EST UNE classe mère ou si elle EST IMPLÉMENTÉE SOUS FORME DE classe mère.


Quelles fonctions doivent être virtuelles ?

Si votre fonction doit avoir un comportement différent dans différentes classes filles, alors elle doit être virtuelle.
Si la fonction ne doit pas être appelée depuis la classe mère, alors elle doit être virtuelle pure.


Mes fonctions doivent-elles être const ?

Si votre fonction membre ne modifie pas l'objet, alors elle doit être const.


Si vous vous posez d'autres questions, faites-nous en part sur le forum. Ainsi cette liste pourra s'agrandir pour mieux aider les suivants.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
14 juillet 2011 à 18:13:47

Très intéressant ces exercices, je vais peut-être me lancer dans un pourquoi pas.


@Nanoc: Pourquoi ce tuto est-il passé en Hors-ligne ? Sur le forum C on a été obligé de regarder une archive. Qu'es qui n'allait pas avec ce tuto ?

  • Partager sur Facebook
  • Partager sur Twitter
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles  - ♡ Copying is an act of love.
14 juillet 2011 à 18:17:21

Citation : @che

@Nanoc: Pourquoi ce tuto est-il passé en Hors-ligne ? Sur le forum C on a été obligé de regarder une archive. Qu'es qui n'allait pas avec ce tuto ?



Il a été fusionné avec le tutoriel officiel. Sauf pour le chapitre sur les pointeurs de fonctions (c.f. ma signature) et pour ce TP. Avec cette re-publication, tout ce qui était dans le cours est à nouveau disponible en ligne.
  • Partager sur Facebook
  • Partager sur Twitter
Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.

[Exercices] Venez vous entraîner !

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown