C++でNimをつくった

C++で某石取りゲームNimを作りました. Nimのコンパイラを作ったわけではありません... CPUと対決するようなものを作りました.

付録のソースコードコンパイルしてお楽しみください.
開発環境の都合で表示がバグったりするかもしれないですが勘弁.

使い方

  1. 起動します
  2. なにも始まりませんが, 石列の数(数値)を入力します(面倒なので数値以外を入力することを想定していません...)(1~30ぐらいが安全です. )
  3. ゲームが始まります(必ず先手でスタートします順番ぎめが面倒だったので)
  4. 最後の石をとると勝ちです. がんばりましょう. CPUは一瞬で石を取るのですぐに自分の番が来ます.

各石列が16個までなのは開発環境の都合です.
クラスとかメソッドとかいろいろ学べてよかったです. あまり活かせてませんが.
にしてもグラフィカルなUIはめんどいっすね〜めんどいめんどい.

コンパイルオプション

	g++ -std=c++11 -o nim nim.cpp -lglut -lGLU -lGL

スパゲッティなソースコードは続きから

#include<bits/stdc++.h>
#include<GL/gl.h>
#include<GL/glut.h>
#include<random>
#include"unistd.h"
#include<GL/freeglut.h>
#define INF_INT 2147483647
#define INF_LL 9223372036854775807
#define REP(i,n) for(int i=0;i<(int)(n);i++)
using namespace std;
void display();
void init();
void resize(int,int);
void mouse(int,int,int,int);

typedef pair<int,int> P;
class Nim
{
private:
  vector<int> board;
  bool turn;
public:
  void switchTurn(){
    turn = 1-turn;
  }
  bool nowTurn(){return turn;}
  Nim(){
    turn = true;
    board = vector<int>(0);
    REP(i,5)board.push_back((rand() % 16) +1);
  }
  Nim(int N){
    turn = true;
    board = vector<int>(0);
    REP(i,N)board.push_back((rand() % 16) +1);
  }
  Nim(vector<int> F){
    board = vector<int>(0);
    REP(i,F.size()){
      if(F[i] <= 0){
        cout << "error" << endl;
        exit(1);
      }
      board.push_back(F[i]);
    }
  }
  //N番目(0-indexed)の山からM個取り除く
  bool Remove(int N, int M){
    if((board.size() <= N) || (board[N] - M < 0) || (M <= 0))
      return false;
    else{
      board[N] -= M;
      return true;
    }
  }
  bool isEnd(){
    REP(i,board.size()){
      if(board[i])
        return false;
    }
    return true;
  }
  vector<int> getBoard(){
    return board;
  }
  void Show(){
    REP(i,board.size())
      cout << board[i] << " ";
    cout << endl;
  }
  int calcXOR(){
    int res = 0;
    REP(i,board.size()){
      res ^= board[i];
    }
    return res;
  }
  
};
Nim E;

bool Enemy(){
  if(!E.isEnd()){
    vector<int> board = E.getBoard();
    if(E.calcXOR() == 0){
      vector<int> p(0);
      REP(i,board.size())if(board[i])p.push_back(i);
      int d=(rand()%p.size());
      int kk=d;
      int sd=rand()%board[p[d]]+1;    
      glFlush();
      glFinish();
      E.Remove(p[d],sd);
      E.switchTurn();
    }else{
      int M=-1,XOR=E.calcXOR(),I;
      REP(i,board.size()){
        if(((XOR ^ board[i]) <= board[i]) && (board[i] - (XOR^board[i]))){
          E.Remove(i,board[i]-(XOR^board[i]));
          glutPostRedisplay();
          glFlush();
          glFinish();
          E.switchTurn();
          break;
        }
      }
    }
  }else{
    glutLeaveMainLoop();
    cout << "YOU WIN!!" << endl;
    return 0;
  }
  if(E.isEnd()){
    glutLeaveMainLoop();
    cout << "YOU LOSE!!" << endl;
    return 0;
  }
  cout << "Now" << endl;
  E.Show();
  return 1;
}

int main(int argc,char* argv[])
{
  int N,turn=1;
  srand((unsigned int)time(NULL));
  cin >> N;
  E = Nim(N);
  glutInitWindowSize(64*N, 240);
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA);
  glutCreateWindow(argv[0]);
  glutReshapeFunc(resize);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);
  init();
  glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_GLUTMAINLOOP_RETURNS);
  glutMainLoop();
  return 0;
}

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  vector<int> board = E.getBoard();
  double D = 180.0;
  REP(s,board.size()){
    REP(j,board[s]){
      glBegin(GL_POLYGON);
      REP(i,D){
        glColor3d(0.3+(0.7*i/D),((0.7*i/D)),0.0);
        glVertex2d((double)1.0/(2.0*board.size())+(double)s/board.size()+cos(i*2*M_PI/D)/(2.0*board.size()),0.05+0.06*j+sin(i*2*M_PI/D)/20);
      }
      glEnd();
    }
  }
  glFlush(); 
  
}

void init(){
  glClearColor(1.0,1.0,1.0,1.0);
}

void resize(int w, int h)
{
  glViewport(0, 0, w, h);
  glLoadIdentity();
  glOrtho(0, 1, 0, 1, -1.0, 1.0);
}

void mouse(int button, int state, int x, int y)
{
  if(!E.nowTurn())
    return;
  static bool touched = false;
  static int ni=-1,nj=-1;
  double w = glutGet( GLUT_WINDOW_WIDTH );
  double h = glutGet( GLUT_WINDOW_HEIGHT );
  double sw = x/w;
  double sh = (h-y)/h;
  switch (button) {
  case GLUT_LEFT_BUTTON:
    break;
  case GLUT_MIDDLE_BUTTON:
    break;
  case GLUT_RIGHT_BUTTON:
    break;
  default:
    break;
  }
  vector<int> board = E.getBoard();
  switch (state) {
  case GLUT_UP:
    for(int j=board.size()-1;j>=0;j--){
      for(int i=board[j]-1;i>=0;i--){
        if((4.0*board.size()*board.size()*pow((x/w-1.0/(2.0*board.size())-(double)j/board.size()),2.0)+400.0*(pow((h-y)/h-0.05-0.06*i,2))) <= 1.0){
          if(ni == i && nj == j){
            //board[
            cout << "YOU SELECTED" << endl;
            E.Remove(j,board[j]-i);
            E.switchTurn();
            E.Show();
            Enemy();
          }
        }
      }
    }
    glutPostRedisplay();
    glFlush();
    glFinish();
    break;
  case GLUT_DOWN:
    {
    double D = 180.00;
    for(int j=board.size()-1;j>=0;j--){
      for(int i=board[j]-1;i>=0;i--){
        if(4.0*board.size()*board.size()*pow((x/w-1.0/(2.0*board.size())-(double)j/board.size()),2.0)+400.0*(pow((h-y)/h-0.05-0.06*i,2)) <= 1.0){
          for(int d=i;d<board[j];d++){
            glBegin(GL_POLYGON);
              REP(f,D){
                glColor3d(0.7+(0.3*f/D),((0.3*f/D)),0.0);
                glVertex2d((double)1.0/(2.0*board.size())+(double)j/board.size()+cos(f*2*M_PI/D)/(2.0*board.size()),0.05+0.06*d+sin(f*2*M_PI/D)/20);
              }
              glEnd();
            }
          glFlush();
          ni = i;
          nj = j;
          i = -1;
          j = -1;
          
        }
      }
    }
    
    }
    break;
  default:
    break;
  }
}