C++でNimをつくった
C++で某石取りゲームNimを作りました. Nimのコンパイラを作ったわけではありません... CPUと対決するようなものを作りました.
付録のソースコードをコンパイルしてお楽しみください.
開発環境の都合で表示がバグったりするかもしれないですが勘弁.
使い方
- 起動します
- なにも始まりませんが, 石列の数(数値)を入力します(面倒なので数値以外を入力することを想定していません...)(1~30ぐらいが安全です. )
- ゲームが始まります(必ず先手でスタートします
順番ぎめが面倒だったので) - 最後の石をとると勝ちです. がんばりましょう. 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; } }