forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Проекты C++ (http://forum.boolean.name/forumdisplay.php?f=56)
-   -   Реверси (http://forum.boolean.name/showthread.php?t=597)

alcoSHoLiK 21.01.2006 12:19

Вложений: 2
Вот, что готово. Осталось ИИ написать. С этим возникли трудности, так как я еще ниразу не писал ИИ. Буду рад, если кто-нибудь поможет советом :)

Код:

#include <conio.h>
#include <iostream>
#include <windows.h>
using namespace std;

const int FIELD_SIZE=8;
const int BLACK=1;
const int WHITE=2;

bool white=false;
bool game_over=false;
bool winner=false;
bool ai=false;

int bscore=2;        //score for black
int wscore=2;        //same for white

struct Coord {
        int x, y;
        Coord (int xx=1, int yy=1) : x (xx), y (yy) {}
};

struct AI_tmp {
        int x, y;
        int col;
        AI_tmp () : x (1), y (1), col (0) {}
};

class Field {
        Coord pos;
        AI_tmp ai_pos[64];        //array to keep AI's available moves in
        char temp_pos; //just a helping var

public:
        class Quit { public: Quit() {} };        //exception for the instant break

        char field[FIELD_SIZE+2][FIELD_SIZE+2];        //field must be public

        Field();

        void refresh();          //set the cursor
        void draw (bool move_skipped=false);

        void set_pos (int x=0, int y=0);
        bool ai_check();
        bool move_check();        //check whether move is available
        bool put();
};

Field::Field() : pos (Coord (1,1))
{
        for (int i=0; i<=FIELD_SIZE+1; i++)
    for (int j=0; j<=FIELD_SIZE+1; j++)
        field[i][j]='0';

/*        Starting position        */
        field[4][4]=field[5][5]=WHITE;
        field[4][5]=field[5][4]=BLACK;

        refresh();
        draw();
}

inline void Field::refresh()
{
        for (int i=1; i<=FIELD_SIZE; i++)
 for (int j=1; j<=FIELD_SIZE; j++)
        if (field[i][j]=='x') field[i][j]=temp_pos;
       
        temp_pos=field[pos.y][pos.x];
        field[pos.y][pos.x]='x';
}

inline void Field::draw(bool move_skipped)
{
        system("cls");

        for (int i=1; i<=FIELD_SIZE; i++) {
 for (int j=1; j<=FIELD_SIZE; j++) {
        cout<<field[i][j]<<" ";
 }
 cout<<endl;
        }

/*        Display statistics        */
        cout<<"\nPLAYER vs ";
        if (ai) cout<<"COMPUTER\n";
        else cout<<"PLAYER\n";
        cout<<"\nSCORE:\n\tblack: "<<bscore<<"\n\twhite: "<<wscore<<endl;
        if (game_over) return;
        if (move_skipped) {
 cout<<"\nWARNING: Move skipped.";
 if (ai && white) {
        cout<<" Press any key...";
        getch();
 }
        }
        if (white) cout<<"\nWhite's turn.";
        else cout<<"\nBlack's turn.";
}

void Field::set_pos (int x, int y)
{
        switch (x)
        {
        case -1:
 if (pos.x>1) pos.x--;
 break;
        case 1:
 if (pos.x<FIELD_SIZE) pos.x++;
        }
        switch (y)
        {
        case -1:
 if (pos.y>1) pos.y--;
 break;
        case 1:
 if (pos.y<FIELD_SIZE) pos.y++;
        }
       
        refresh();
        draw();
}

bool Field::ai_check()
{
        char piece=WHITE;
        int size=0;

/*        Finding all availabe moves        */
        for (int i=1; i<=FIELD_SIZE; i++) {
 for (int j=1; j<=FIELD_SIZE; j++) {
        if (field[i][j]=='0') {
  for (int y=-1; y<=1; y++) {
          for (int x=-1; x<=1; x++) {
  if (y==0 && x==0) continue;
           
  int subi=i+y;
  int subj=j+x;
  if (field[subi][subj]=='0' || field[subi][subj]==piece) continue;
            int counter=0;
 
  while (field[subi][subj]!=piece && field[subi][subj]!='0') {
          subi+=y;
          subj+=x;
          counter++;
  }

  if (counter && field[subi][subj]==piece) {
          ai_pos[size].y=i;
          ai_pos[size].x=j;
          ai_pos[size].col=counter;
          size++;
  }
          }
  }
        }
 }
        }
        if (!size) return false;        //no moves available

/*        Setting priority        */
        while (true) {
        /*        Sorting        */
    for (int i=0; i<size-1; i++) {
        for (int j=1; j<size; j++)
  if (ai_pos[i].col<ai_pos[j].col) swap (ai_pos[i], ai_pos[j]);
        if (ai_pos[i].col==0) size--;
 }

        /*        Tactical checks        */
 bool change=false;
 try {
        //Don't give away an angle!
        for (int i=1; i<=FIELD_SIZE; i+=7) {
  for (int j=1; j<=FIELD_SIZE; j+=7) {
          for (int y=-1; y<=1; y++) {
  for (int x=-1; x<=1; x++) {
          int tmp_x=j+x;
          int tmp_y=i+y;
          if (ai_pos[0].x==tmp_x && ai_pos[0].y==tmp_y && size>1) {
    ai_pos[0].col=0;
    change=true;
    throw Quit();        //instant break
          }
  }
          }
  }
        }
 }
 catch (...) {}
 if (!change) break;        //nothing to change
        }

/*        Finally setting the position for move */
        pos.x=ai_pos[0].x;
        pos.y=ai_pos[0].y;

        return true;
}

bool Field::move_check()
{
        for (int i=1; i<=FIELD_SIZE; i++) {
 for (int j=1; j<=FIELD_SIZE; j++) {
        if (field[i][j]=='0') {
  for (int y=-1; y<=1; y++) {
          for (int x=-1; x<=1; x++) {
  if (y==0 && x==0) continue;

  int subi=i+y;
  int subj=j+x;
  int counter=0;
  char piece=white ? WHITE : BLACK;

          /*        Counting possible moves        */
  while (field[subi][subj]==piece) {
          subi+=y;
          subj+=x;
          counter++;
  }

          /*        Got at least one move        */
  piece=3-piece;
  if (counter && field[subi][subj]==piece) return true;
          }
  }
        }
 }
        }

        return false;
}

bool Field::put()
{
        if (temp_pos!='0') return false;        //cell is not empty


        char piece=white ? WHITE : BLACK;
        bool check=false;

        for (int y=pos.y-1; y<=pos.y+1; y++) {
 for (int x=pos.x-1; x<=pos.x+1; x++) {
        if (y==pos.y && x==pos.x) continue;
        if (field[y][x]!='0' && field[y][x]!=piece) check=true;
 }
        }
        if (!check) return false;        //there is nothing useful around


        bool changed=false;
        int* ptr_bscore=&bscore;        //these 2 pointers are
        int* ptr_wscore=&wscore;        //for the comfortable score setting
        if (white) swap(ptr_bscore, ptr_wscore);


/*        Validating the move        */
        int i=pos.y;
        int j=pos.x;
        for (int y=-1; y<=1; y++) {
 for (int x=-1; x<=1; x++) {
        if (y==0 && x==0) continue;

        int subi=i+y;
        int subj=j+x;
        if (field[subi][subj]=='0' || field[subi][subj]==piece) continue;
        int counter=0;

        while (field[subi][subj]!=piece && field[subi][subj]!='0') {
  subi+=y;
  subj+=x;
  counter++;
        }

        if (counter && field[subi][subj]==piece) {
  while (counter) {
          counter--;
          subi-=y;
          subj-=x;
          (*ptr_bscore)++;
          (*ptr_wscore)--;
          field[subi][subj]=piece;
  }
  changed=true;
        }
 }
        }
        if (!changed) return false;        //validation failed


        bool move_skip=false;

        if (!game_over) {
    field[pos.y][pos.x]=piece;
 (*ptr_bscore)++;

 if (wscore==0 || bscore==0 || (wscore+bscore)==64) {
        game_over=true;
        winner=bscore>wscore;
 }

 if (move_check()) white=!white;
 else move_skip=true;

 draw(move_skip);

 if (ai && white) {
        Coord tmp_pos=pos;
        ai_check();
        Sleep (500);
        put();
        pos=tmp_pos;
 }
        }

        return true;
}


int main()
{
        char comp;
        bool inerror=true;

        while (inerror) {
    cout<<"Play with computer? (y/n)\n";
 comp=getch();
 switch (comp)
 {
 case 27:
        return 0;
 case 'y':
        ai=true;
 case 'n':
        inerror=false;
        break;
 default:
        system ("cls");
        cout<<"INPUT ERROR.\n";
 }
        }

        Field field;
        int key;

        while (true) {
    key=getch();
 switch (key)
 {
 case 72:
        field.set_pos (0, -1);
        break;
 case 75:
        field.set_pos (-1);
        break;
 case 77:
        field.set_pos (1);
        break;
 case 80:
        field.set_pos (0, 1);
        break;
 case 32:
        field.put();
        break;

 case 27:
        return 0;
 }
 if (game_over) {
        cout<<"\nTHE GAME HAS ENDED.\n";
        if (winner) cout<<"BLACK";
        else cout<<"WHITE";
        cout<<" WON!\n";
        getch();
        return 0;
 }
        }
}

В аттаче exe.


P.S. Движок форума частично игнорирует табуляцию, поэтому советую использовать функцию цитирования для копирования кода в IDE.

jimon 21.01.2006 13:44

я так и непонял чем управлять
ps. если capslock включон - понажимай k и m :)

AsmLover 21.01.2006 14:04

А выбор в switch (key) тебе ничего не говорит? :)

Имхо, фоновые нолики сбивают контраст, надо бы вместо них точки ...
Выигрышный алгоритм х.з. Лучше делай шахматы.

alcoSHoLiK 21.01.2006 17:50

jimon
Двигать стрелками, ход - пробел.

jimon 21.01.2006 22:01

похоже я незнаю правил игры :(

Kain 22.01.2006 04:03

Не разбираюсь в C++,но походу комп не следит за возможностью моего хода:
закончил 57 против 6 и 1 пустая,сори он тоже ходить не может ,
значит в завершение баг,а какой алгоритм у тебя ? (если не секрет)

У меня есть 2(или 3) реверси :одна флешка(безбашенная),вторая на 1С как
док. 1С предприятие( исходник, там же )оказалось что по русски
ещё труднее разобраться ,за что и не люблю енглиш ,гад !
:P
3 (и 4 ) ха -ха вспомнил мой телефон и тел моей подруги (у неё совсем тупой,
иногда ему ето помагает) :P
твой на первый взгляд похож на.. м .. (млин код что ли посмотреть...) ладно попробую...потом дам рецензию

Если я воспользуюсь твоим кодом (в теория или практике) ето наказуемо ?,

я же тоже в своем топике её родную и обсуждаю ,хочу сделать ,но не хватает
знаний, ето сильно отталкивает при первых трудностях,

вот почему я с тобой спорил по поводу отвлечься ,сейчас отвлекся на муз.прогу
на Блице(как только подключил библиотеку)

а ваще алгоритм надо у себя подсмотреть,то как ты ходишь: делай анализ,затем сортируй (думаю версии 3-4(игры)) и можно сделать самый-самый II
ну ладно а то разошолся .... :ok:
PS вот сайт електронной библиотеки http://lib.mexmat.ru/

все через день затру.......
стер....

Kain 22.01.2006 04:27

Не утерпел, при
CapsLock и RU-складке
З =вниз
Р =вверх
Ь =вправо
Л =влево

AsmLover
Цитата:

Выигрышный алгоритм х.з. Лучше делай шахматы.
Он есть, только я неграмотный, наверняка через двоичную систему находиться
я про одну игру читал, все сводиться к безопасному и опасному ходу (не буду умничать, могу черкануть заметку с учбника по ТПаскалю = игра Ним)
jimon
Цитата:

похоже я незнаю правил игры
в кратце правилатаковы:
если Крестики-Нолики константы,
то Реверси переменные

alcoSHoLiK 22.01.2006 11:42

Цитата:

Не разбираюсь в C++,но походу комп не следит за возможностью моего хода:
закончил 57 против 6 и 1 пустая,сори он тоже ходить не может ,
значит* в завершение баг,а какой алгоритм у тебя ? (если не секрет)

Т.е. осталась одна пустая клетка, и никто из вас не может походить?

Цитата:

Если я воспользуюсь твоим кодом (в теория или практике) ето наказуемо ?,

Нет.


Алгоритм виден в коде. Сейчас ИИ почти не думает. Он выполняет только сортировку, а затем делает ход, при котором он заберет наибольшее количество очков. Естественно, это ведет к проигрышу.

Отдельное спасибо Jet'у за помощь с функцией move_check().


P.S. Kain, твоя ссылка тут не в тему. На форуме есть отдельный раздел для этого.

Kain 22.01.2006 22:37

Цитата:

Originally posted by alcoSHoLiK@Jan 22 2006, 10:42 AM
Т.е. осталась одна пустая клетка, и никто из вас не может походить?

Нет.
Алгоритм виден в коде. Сейчас ИИ почти не думает. Он выполняет только сортировку, а затем делает ход, при котором он заберет наибольшее количество очков. Естественно, это ведет к проигрышу.

первая часть да,и игра не заканчивается,ожидает мой ход (вроде)
второе осмелюсь спорить
не обязательно,ведь он не подставу тебе делает
у меня будет такой ИИ:

углы ...
стены...
больше захват...
возможность хода(и где...)
и по кругу(в 8х8 два раза(маленький 4х4,большой 8х8))
общая картина, вроде ещё чё-то было не помню, возобновлю работу вспомню


Часовой пояс GMT +4, время: 16:33.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot