| Index: experimental/hex/hex_maniac.cc
|
| diff --git a/experimental/hex/hex_maniac.cc b/experimental/hex/hex_maniac.cc
|
| deleted file mode 100644
|
| index f0be725e3daabc1fc72fcc1d067308751a4198c6..0000000000000000000000000000000000000000
|
| --- a/experimental/hex/hex_maniac.cc
|
| +++ /dev/null
|
| @@ -1,793 +0,0 @@
|
| -
|
| -#include "hex_instance.h"
|
| -
|
| -#include <ctype.h>
|
| -#include <stdio.h>
|
| -#include <string.h>
|
| -
|
| -#include <iostream>
|
| -using std::cout;
|
| -using std::cin;
|
| -using std::endl;
|
| -
|
| -
|
| -namespace hexgame {
|
| -
|
| -// Hex Maniac v1.2
|
| -// Copyright Cameron Browne
|
| -// 5/10/2000
|
| -//
|
| -// Point-pairing algorithm with blind row.
|
| -//
|
| -// Feel free to experiment with and develop this code, but please
|
| -// acknowledge its contribution to any derived work.
|
| -//
|
| -// Compiles with the Microsoft C/C++ compiler (12.00.8168) and linker
|
| -// (6.00.8168) but should be portable. Use the following options:
|
| -// cl -GX hex_12.cpp
|
| -//
|
| -// Guaranteed bug free. Any errors must have been introduced by
|
| -// subsequent developers :)
|
| -//
|
| -// From: http://www.cameronius.com/games/hex/hex_12.cpp
|
| -// which is part of http://www.cameronius.com/games/hex/
|
| -//
|
| -
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -
|
| -const int MIN_N = 3; // Smallest board size
|
| -const int MAX_N = 26; // Largest board size (limit of alphanumeric notation)
|
| -
|
| -enum State // board point or move state
|
| -{
|
| - EMPTY = 0, // empty board position
|
| - VERT = 1, // computer player (vertical = j)
|
| - HORZ = 2, // human player (horizontal = i)
|
| - NUM_STATES
|
| -};
|
| -
|
| -static const char* StateNames[NUM_STATES] =
|
| -{
|
| - "Empty",
|
| - "Vertical",
|
| - "Horizontal",
|
| -};
|
| -
|
| -struct Coord
|
| -{
|
| - Coord(int i_=-1, int j_=-1) : i(i_), j(j_) {}
|
| -
|
| - int i;
|
| - int j;
|
| -};
|
| -
|
| -// Hexagonal neighbours of X:
|
| -// >-<
|
| -// >-< 0 >-< | 5 | 0
|
| -// < 5 >-< 1 > ---+---+---
|
| -// >-< X >-< == 4 | X | 1
|
| -// < 4 >-< 2 > ---+---+---
|
| -// >-< 3 >-< 3 | 2 |
|
| -// >-<
|
| -static const Coord nbor[6] =
|
| -{
|
| - Coord(1,-1), Coord(1,0), Coord(0,1),
|
| - Coord(-1,1), Coord(-1,0), Coord(0,-1)
|
| -};
|
| -
|
| -void ConvertColRowToHexManiac(int column, int row, int *hex_i, int *hex_j);
|
| -void ConvertHexManiacToColRow(int hex_i, int hex_j, int* column, int* row);
|
| -
|
| -// Blind row defense templates
|
| -//
|
| -// Key:
|
| -// h = existing HORZ piece
|
| -// v = existing VERT piece
|
| -// . = empty position
|
| -// x = existing piece (VERT or HORZ)
|
| -// - = don't care
|
| -// H = last HORZ move
|
| -// V = VERT's best reply
|
| -// r = reentrant block on furthest connected piece (or adjacent if none)
|
| -//
|
| -// Note: more general situations should go last.
|
| -//
|
| -const int NUM_DEFENSE_TEMPLATES = 25;
|
| -static const char* HEX_DefenseTemplate[NUM_DEFENSE_TEMPLATES][2] =
|
| -{
|
| - { "H V - -", "- - - -" }, // acute blind corner
|
| - { "- - . H", "- - V -" }, // obtuse blind corner
|
| - { "- V H v", "- - - -" },
|
| - { "- v H V", "- - - -" },
|
| - { "- V H .", "h . . h" },
|
| - { "- . H V", "h . . h" },
|
| - { "v h H -", "V . h -" },
|
| - { "- H h v", "h . V -" },
|
| - { "- V H -", "h . h -" },
|
| - { "- - H V", "- h . h" },
|
| - { "- V H -", "- v - -" },
|
| - { "- H V -", "- v - -" },
|
| - { "- V H -", "- - h -" },
|
| - { "- H V -", "h - - -" },
|
| - { ". H h -", "V - - -" },
|
| - { "- h H .", "- - V -" },
|
| - { "- V H -", "h . - -" },
|
| - { "- H V -", "- . h -" },
|
| - { "- h H h", "- v V v" },
|
| - { "- h H h", "v V v -" },
|
| - { "- h H v", "- v V -" },
|
| - { "- v H h", "- V v -" },
|
| - { "- H r -", "h - - -" },
|
| - { "- r H -", "- - h -" },
|
| - { "- . H .", "- V . -" }, // reentrant block below (general case)
|
| -};
|
| -
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -class HEX_Game
|
| -{
|
| -public:
|
| - HEX_Game(int n_=11) : N(n_), SwapOption(false) {} // HACKED SwapOption
|
| - ~HEX_Game() {}
|
| -
|
| - bool Play(void);
|
| - void SetInstance(HexGameInstance *instance) { instance_ = instance; }
|
| -private:
|
| - bool DoMove(State who);
|
| - bool GetUserMove(Coord& move) const;
|
| - bool GameWon(State who);
|
| - bool GameWon(State who, Coord const& from);
|
| - void RandomEmptyPosition(Coord& posn) const;
|
| - void ShowBoard(void) const;
|
| - bool IsValid(Coord const& posn) const;
|
| -
|
| - void BestOpening(Coord& move) const;
|
| - bool GoodSwap(Coord const& move) const;
|
| - bool BestComputerMove(Coord& move) const;
|
| - bool DefendBlindRow(Coord& move) const;
|
| - void SpareMove(Coord& move) const;
|
| -
|
| - void DoUpdate() const;
|
| -private:
|
| - State Board[MAX_N][MAX_N]; // the board
|
| - int N; // current board size NxN
|
| - int NumMoves; // number of moves played
|
| - Coord Last; // opponent's last move
|
| - bool SwapOption; // whether the swap option is enabled
|
| - bool HasSwapped; // whether a player has swapped already
|
| - State WhoStarted; // who played first
|
| - bool Visit[MAX_N][MAX_N]; // for rough working
|
| -
|
| - HexGameInstance* instance_;
|
| -};
|
| -
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -
|
| -void HEX_Game::DoUpdate() const {
|
| - pp::Core* core = pp::Module::Get()->core();
|
| - if(!core)
|
| - return;
|
| - printf("Got computer move, calling CallOnMainThread!\n");
|
| - core->CallOnMainThread(0 /*no delay*/, pp::CompletionCallback(
|
| - UpdateCallback, instance_));
|
| -}
|
| -
|
| -
|
| -// Alternates moves between players until the game is won
|
| -//
|
| -// Returns: whether user choose to continue playing
|
| -//
|
| -bool HEX_Game::Play(void)
|
| -{
|
| - memset(Board, 0, sizeof(Board));
|
| - NumMoves = 0;
|
| - HasSwapped = false;
|
| -
|
| - // Determine who starts
|
| - cout << "\nDo you want to start? [y/n/q]: ";
|
| - char ch('n');
|
| -
|
| - /// cin >> ch;
|
| - ch = 'y'; /// HACK -- allow user to start
|
| -
|
| - if (tolower(ch) == 'q')
|
| - exit(1);
|
| -
|
| - WhoStarted = (tolower(ch) == 'y') ? HORZ : VERT;
|
| -
|
| - if (WhoStarted == HORZ)
|
| - ShowBoard();
|
| -
|
| - // Play a game
|
| - State who(WhoStarted);
|
| - while (!DoMove(who)) {
|
| - who = State((NumMoves + WhoStarted + 1) % 2 + 1);
|
| - }
|
| -
|
| - cout << "\nGame won by " << StateNames[who] << "!" << endl;
|
| - cout << "\nPlay again on " << N << 'x' << N << "? [y/n]: ";
|
| - cin >> ch;
|
| -
|
| - if (who == VERT)
|
| - instance_->SetComputerWins();
|
| - else
|
| - instance_->SetUserWins();
|
| -
|
| - DoUpdate();
|
| -
|
| - return (tolower(ch) == 'y');
|
| -}
|
| -
|
| -// Determines and plays a move for the specfied player
|
| -//
|
| -// Returns: whether this move wins the game
|
| -//
|
| -bool HEX_Game::DoMove(State who)
|
| -{
|
| - Coord move;
|
| - bool did_swap = (who==HORZ) ? GetUserMove(move) : BestComputerMove(move);
|
| - if (did_swap)
|
| - {
|
| - // 'who' chose to swap
|
| - State opp = (who == VERT) ? HORZ : VERT;
|
| - Board[Last.j][Last.i] = EMPTY; // undo opening move
|
| - Board[Last.i][Last.j] = who; // redo its reflection
|
| - ShowBoard();
|
| - cout << endl << "Swap! " << StateNames[who][0] << " takes ";
|
| - cout << char('A' + Last.j) << 1 + Last.i << "." << endl;
|
| -
|
| - WhoStarted = who;
|
| - HasSwapped = true;
|
| - }
|
| - else
|
| - {
|
| - // Make the move
|
| - Board[move.j][move.i] = who;
|
| - NumMoves++;
|
| - Last = move;
|
| -
|
| - // Show the result
|
| - ShowBoard();
|
| - cout << endl << StateNames[who][0] << " plays at ";
|
| - cout << char('A' + move.i) << 1 + move.j << "." << endl;
|
| - }
|
| -
|
| - return GameWon(who);
|
| -}
|
| -
|
| -// Reads user's move from the keyboard (HORZ)
|
| -//
|
| -// Returns: whether user chose to swap
|
| -//
|
| -// We call WaitForUserMove, which gets the user move from a queue (or waits
|
| -// for a new entry in the queue) in order to synchronize with the GUI.
|
| -// The indicated move could either be a replaces the cin code to get 'i/j'.
|
| -// Currently, we don't provide swap as an option.
|
| -// NOTE: We send an update (message) just once to indicate the game loop is
|
| -// ready, so that the UI knows it can now send user moves.
|
| -//
|
| -bool HEX_Game::GetUserMove(Coord& move) const
|
| -{
|
| - static bool gameInitialized = false;
|
| - if (!gameInitialized) {
|
| - // we need to send a message to the UI just once that we have
|
| - // reached this code -- which indicates that not only is the nexe
|
| - // loaded but that the game loop is ready for events to be queued.
|
| - instance_->SetGameLoopReady();
|
| - DoUpdate();
|
| - gameInitialized = true;
|
| - }
|
| - // char str[4];
|
| - if (SwapOption && !HasSwapped && NumMoves==1)
|
| - {
|
| - char ch('y');
|
| - cout << endl << "Swap opening move? ";
|
| - if (GoodSwap(Last))
|
| - cout << "(I would) [y/n/q]: ";
|
| - else
|
| - cout << "(I wouldn't) [y/n/q]: ";
|
| - cin >> ch;
|
| -
|
| - if (tolower(ch) == 'q')
|
| - exit(2);
|
| -
|
| - if (tolower(ch) == 'y')
|
| - return true; // Swap
|
| - }
|
| -
|
| - do {
|
| - cout << endl << "Enter move [eg f6/q]: ";
|
| - cout << "Waiting for UI to send move...";
|
| - // cin >> str;
|
| -
|
| - // if (str[0] == 'q')
|
| - // exit(3);
|
| - uint32_t column, row;
|
| - instance_->WaitForUserMove(&column, &row);
|
| - ConvertColRowToHexManiac(column, row, &move.i, &move.j);
|
| - printf("MOVE IS %d:%d\n", move.i, move.j);
|
| - //move.i = tolower(str[0]) - 'a';
|
| - //move.j = atoi(&str[1]) - 1;
|
| - if (!IsValid(move)) {
|
| - cout << "MOVE " << move.i << ":" << move.j << " is NOT valid" << endl;
|
| - instance_->SetInvalidMove();
|
| - DoUpdate();
|
| - } else {
|
| - cout << "MOVE " << move.i << ":" << move.j << " is valid" << endl;
|
| - instance_->SetValidMove();
|
| - }
|
| - if (Board[move.j][move.i]) {
|
| - printf("Board non-empty contents for %d:%d are %d\n", move.i, move.j, Board[move.j][move.i]);
|
| - } else {
|
| - printf("Board empty contents for %d:%d are %d\n", move.i, move.j, Board[move.j][move.i]);
|
| - }
|
| - } while (!IsValid(move) || Board[move.j][move.i]);
|
| -
|
| - return false;
|
| -}
|
| -
|
| -// Returns: whether the game has been won by the specified player
|
| -//
|
| -bool HEX_Game::GameWon(State who)
|
| -{
|
| - fprintf(stderr, "Entered GameWon\n");
|
| - memset(Visit, 0, sizeof(Visit));
|
| - if (who == VERT)
|
| - {
|
| - for (int i = 0; i < N; i++)
|
| - if (Board[0][i]==VERT && !Visit[0][i] && GameWon(VERT, Coord(i,0)))
|
| - return true;
|
| - }
|
| - else
|
| - {
|
| - for (int j = 0; j < N; j++)
|
| - if (Board[j][0]==HORZ && !Visit[j][0] && GameWon(HORZ, Coord(0,j)))
|
| - return true;
|
| - }
|
| - fprintf(stderr, "Exited GameWon\n");
|
| - return false;
|
| -}
|
| -
|
| -// Recursively examines neighbours of potential winning chains
|
| -//
|
| -// Returns: whether the game has been won by the specified player
|
| -//
|
| -bool HEX_Game::GameWon(State who, Coord const& from)
|
| -{
|
| - if ((who==HORZ && from.i==N-1) || (who==VERT && from.j==N-1))
|
| - return true;
|
| -
|
| - Visit[from.j][from.i] = true; // this coord has been visited
|
| -
|
| - for (int n = 0; n < 6; n++)
|
| - {
|
| - // Check neighbours for continuation of chain
|
| - Coord to(from.i + nbor[n].i, from.j + nbor[n].j);
|
| - if
|
| - (
|
| - IsValid(to) && Board[to.j][to.i]==who
|
| - &&
|
| - !Visit[to.j][to.i] && GameWon(who, to)
|
| - )
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Draws board in ASCII text format
|
| -//
|
| -void HEX_Game::ShowBoard(void) const
|
| -{
|
| - // Show alphabetical (HORZ) labels
|
| - cout << endl << " ";
|
| - for (int i = 0; i < N; i++)
|
| - cout << char('A' + i) << ' ';
|
| - cout << endl;
|
| -
|
| - for (int j = 0; j < N; j++)
|
| - {
|
| - // Show numeric (VERT) labels
|
| - for (int s = 0; s < j; s++)
|
| - cout << ' ';
|
| - if (j < 9)
|
| - cout << ' ';
|
| - cout << j + 1;
|
| -
|
| - // Show state of each board position along this row
|
| - for (int i = 0; i < N; i++)
|
| - if (Board[j][i] == VERT)
|
| - cout << " V";
|
| - else if (Board[j][i] == HORZ)
|
| - cout << " H";
|
| - else
|
| - cout << " .";
|
| - cout << endl;
|
| - }
|
| -}
|
| -
|
| -// Returns: whether posn is within the bounds of the board
|
| -//
|
| -bool
|
| -HEX_Game::IsValid(Coord const& posn) const
|
| -{
|
| - return (posn.i >= 0 && posn.i < N && posn.j >= 0 && posn.j < N);
|
| -}
|
| -
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// Strategic operations
|
| -
|
| -// Determines computer's best opening move (VERT)
|
| -//
|
| -void HEX_Game::BestOpening(Coord& move) const
|
| -{
|
| - move = Coord(N - 1, 0); // obtuse corner in blind row
|
| -}
|
| -
|
| -// Returns: whether this opening move is worth swapping
|
| -//
|
| -bool
|
| -HEX_Game::GoodSwap(Coord const& move) const
|
| -{
|
| - return (move.i == N - move.j - 1); // swap along short diagonal
|
| -}
|
| -
|
| -// Determines best move for computer (VERT)
|
| -//
|
| -// Returns: true on swap, else false
|
| -//
|
| -bool
|
| -HEX_Game::BestComputerMove(Coord& move) const
|
| -{
|
| - if (NumMoves == 0)
|
| - {
|
| - BestOpening(move); // opening move
|
| - }
|
| - else if (NumMoves == 1 && SwapOption && !HasSwapped && GoodSwap(Last))
|
| - {
|
| - return true; // swap opponent's opening move
|
| - }
|
| - else if (Last.j == 0)
|
| - {
|
| - DefendBlindRow(move); // defend the blind row
|
| - }
|
| - else
|
| - {
|
| - if (Last.i < N - Last.j) // determine dual point on left
|
| - move = Coord(N - Last.j, N - Last.i - 1);
|
| - else // determine dual point on right
|
| - move = Coord(N - Last.j - 1, N - Last.i);
|
| - }
|
| -
|
| - if (!IsValid(move) || Board[move.j][move.i])
|
| - SpareMove(move); // spare move - do some damage!
|
| -
|
| -
|
| - int ui_column, ui_row;
|
| - ConvertHexManiacToColRow(move.i, move.j, &ui_column, &ui_row);
|
| - // UPDATE COMPUTER'S MOVE
|
| - instance_->SetComputerMove(ui_column, ui_row);
|
| - DoUpdate();
|
| -
|
| - return false;
|
| -}
|
| -
|
| -// Determines best move along the blind row (row 0)
|
| -//
|
| -// Returns:
|
| -// Whether appropriate defending move was found.
|
| -//
|
| -bool HEX_Game::DefendBlindRow(Coord& move) const
|
| -{
|
| - move = Coord(-1, -1); // should already be initialised but make sure
|
| -
|
| - for (int d = 0; d < NUM_DEFENSE_TEMPLATES; d++)
|
| - {
|
| - // Find root position H on top row
|
| - int root;
|
| - for (root = 0; root < 4; root++)
|
| - if (HEX_DefenseTemplate[d][0][root * 2] == 'H')
|
| - break;
|
| - if
|
| - (
|
| - (root>=4) // no root found
|
| - ||
|
| - (root==0 && !(Last.i==0 && Last.j==0)) // acute corner no good
|
| - ||
|
| - (root==3 && !(Last.i==N-1 && Last.j==0)) // obtuse corner no good
|
| - )
|
| - continue;
|
| -
|
| - // Check whether rest of template matches board position
|
| - bool valid = true;
|
| -
|
| - int reentrant = 0;
|
| -
|
| - for (int j = 0; j < 2 && valid; j++)
|
| - for (int c = 0; c < 4 && valid; c++)
|
| - {
|
| - int i = Last.i - root + c;
|
| - char ch = HEX_DefenseTemplate[d][j][c * 2];
|
| -
|
| - if (ch == 'V' && !Board[j][i])
|
| - move = Coord(i, j);
|
| - else if (ch == 'V' && Board[j][i])
|
| - valid = false;
|
| - else if (ch == 'h' && Board[j][i] != HORZ)
|
| - valid = false;
|
| - else if (ch == 'v' && Board[j][i] != VERT)
|
| - valid = false;
|
| - else if (ch == 'x' && !Board[j][i])
|
| - valid = false;
|
| - else if (ch == '.' && Board[j][i])
|
| - valid = false;
|
| - else if (ch == 'r')
|
| - {
|
| - if (Board[j][i] == VERT)
|
| - valid = false;
|
| - else
|
| - {
|
| - move = Coord(Last);
|
| - reentrant = (i < root) ? -1 : 1; // is reentrant move
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!valid)
|
| - continue; // invalid template
|
| -
|
| - if (move.i == -1 || move.j == -1)
|
| - continue; // no valid reply found
|
| -
|
| - if (reentrant)
|
| - {
|
| - if (reentrant > 0)
|
| - {
|
| - // Find reentrant block above
|
| - while (move.i < N - 1)
|
| - {
|
| - if (!Board[0][move.i])
|
| - return true; // adjacent block above
|
| -
|
| - if (!Board[1][move.i])
|
| - {
|
| - move = Coord(move.i, 1);
|
| - return true; // reentrant block above
|
| - }
|
| - move.i++;
|
| - }
|
| - }
|
| - else
|
| - {
|
| - // Find reentrant block below
|
| - while (move.i >= 0)
|
| - {
|
| - if (!Board[0][move.i])
|
| - return true; // adjacent block above
|
| -
|
| - if (!Board[1][move.i - 1])
|
| - {
|
| - move = Coord(move.i - 1, 1);
|
| - return true; // reentrant block above
|
| - }
|
| - move.i--;
|
| - }
|
| - }
|
| - return false; // no reentrant block found
|
| - }
|
| - return true; // good move found!
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -// Determines best spare move. There will ALWAYS be a spare move somewhere.
|
| -//
|
| -void HEX_Game::SpareMove(Coord& move) const
|
| -{
|
| - // Look for urgent moves on the blind row
|
| - move.j = 0;
|
| - for (move.i = 0; move.i < N; move.i++)
|
| - if
|
| - (
|
| - !Board[0][move.i]
|
| - &&
|
| - (
|
| - (move.i < N - 1 && Board[0][move.i + 1] == HORZ )
|
| - &&
|
| - (
|
| - (Board[1][move.i] == VERT )
|
| - ||
|
| - (move.i > 0 && !Board[1][move.i] && Board[1][move.i-1]==HORZ)
|
| - )
|
| - ||
|
| - (move.i > 0 && Board[0][move.i - 1] == HORZ
|
| - &&
|
| - (
|
| - (Board[1][move.i - 1] == VERT )
|
| - ||
|
| - (!Board[1][move.i] && Board[1][move.i + 1] == HORZ )
|
| - ))
|
| - )
|
| - )
|
| - return;
|
| -
|
| - // If top obtuse corner is empty, take it
|
| - if (!Board[0][N - 1])
|
| - {
|
| - move = Coord(N - 1, 0);
|
| - return;
|
| - }
|
| -
|
| - // Block any reentrant point on row 1
|
| - move.j = 1;
|
| - for (move.i = 0; move.i < N - 1; move.i++) // skip move.i == N - 1
|
| - if
|
| - (
|
| - !Board[1][move.i]
|
| - &&
|
| - (
|
| - (Board[0][move.i] == HORZ && Board[0][move.i + 1] != HORZ )
|
| - ||
|
| - (Board[0][move.i + 1] == HORZ && Board[0][move.i] != HORZ)
|
| - )
|
| - )
|
| - return;
|
| -
|
| - // Block any point adjacent to White on row 0
|
| - move.j = 0;
|
| - for (move.i = 0; move.i < N; move.i++)
|
| - if
|
| - (
|
| - !Board[0][move.i]
|
| - &&
|
| - (
|
| - (move.i > 0 && Board[0][move.i - 1] == HORZ )
|
| - ||
|
| - (move.i < N - 1 && Board[0][move.i + 1] == HORZ)
|
| - )
|
| - )
|
| - return;
|
| -
|
| - // Take any point an empty point away from Black on row 0
|
| - move.j = 0;
|
| - for (move.i = 0; move.i < N; move.i++)
|
| - if
|
| - (
|
| - !Board[0][move.i]
|
| - &&
|
| - (
|
| - (move.i > 1 && !Board[0][move.i-1] && Board[0][move.i-2]==VERT )
|
| - ||
|
| - (move.i < N-2 && !Board[0][move.i+1] && Board[0][move.i+2]==VERT )
|
| - )
|
| - )
|
| - return;
|
| -
|
| - // Take any empty point from top obtuse corner down (must be at least one)
|
| - for (move.j = 0; move.j < N; move.j++)
|
| - for (move.i = N-1; move.i >= 0; move.i--)
|
| - if (!Board[move.j][move.i])
|
| - return;
|
| -
|
| - move = Coord(-1, -1); // bad result
|
| -}
|
| -
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void* AppMain(void* param)
|
| -{
|
| - HexGameInstance* pepper_instance = static_cast<HexGameInstance*>(param);
|
| - cout << "Hex Maniac v1.2" << endl;
|
| - cout << "Cameron Browne 5/10/2000" << endl << endl;
|
| - cout << "You are horizontal (H), computer is vertical (V)" << endl;
|
| -
|
| - int n = 11;
|
| -/*
|
| - if (argc == 2)
|
| - {
|
| - n = atoi(argv[1]);
|
| - if (n < MIN_N)
|
| - n = MIN_N;
|
| - else if (n > MAX_N)
|
| - n = MAX_N;
|
| - }
|
| -*/
|
| - HEX_Game game(n);
|
| - game.SetInstance(pepper_instance);
|
| - while (game.Play());
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -
|
| -
|
| -// Move from JS is based on 'straight' columns that are 1-based
|
| -// 4:1
|
| -// 2:1 3:1 4:2
|
| -// 1:1 2:2 3:2 4:3
|
| -// 3:3 4:4
|
| -//
|
| -// while the i/j are based on 0-based grid that looks like:
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -// . . . . . . . . . . .
|
| -//
|
| -// where i is how many columns from the left we are (0-based) in this
|
| -// 'shifted' view
|
| -//
|
| -// Here's another view with the numbers from UI col:row shown
|
| -//
|
| -// 1:1 2:1 3:1 4:1 5:1 6:1
|
| -// 2:2 3:2 4:2 5:2
|
| -// 3:3 4:3 5:3
|
| -//
|
| -// Top 1:1->0:0 2:1->1:0 3:1->2:0 4:1->3:0
|
| -// Next 2:2->0:1 3:2->1:1 4:2->2:1
|
| -// 3:3->0:2 4:3->1:3
|
| -//
|
| -// Need to handle the case where the rhombus is shrinking -- column > 11
|
| -// TODO (make sure this can be expanded to handle different sizes)
|
| -// Note that when column > 11, column is always > row
|
| -// 12:1 -> 10:1
|
| -// 13:1 -> 10:2
|
| -// 14:1 -> 10:3
|
| -//
|
| -// 13:1 -> 10:2
|
| -// 13:2 -> 9:3
|
| -// 13:3 -> 8:4
|
| -//
|
| -// col:row x:y col-11 - row
|
| -// 14:1 -> 10:3 3
|
| -// 14:2 -> 9:4 3
|
| -// 14:3 -> 8:5 3
|
| -//
|
| -// 15:1 -> 10:4
|
| -// 16:1 -> 10:5
|
| -// 21:1 -> 10:10
|
| -// 19:3 -> 8:10
|
| -//
|
| -void ConvertColRowToHexManiac(int column, int row, int *hex_i, int *hex_j) {
|
| - if (column < 12) { // FIXME -- magic number (12)
|
| - *hex_i = column - row;
|
| - *hex_j = row -1;
|
| - } else {
|
| - *hex_j = (column-11) + (row - 1);
|
| - *hex_i = column - *hex_j - 1;
|
| - }
|
| - std::cout << " ConvertColRowToHexManiac column=" << column << " row=" << row
|
| - << " ... hex_i = " << *hex_i << " hex_j = " << *hex_j << std::endl;
|
| - if (*hex_i < 0 || *hex_i > 11 || *hex_j < 0 || *hex_j > 11) {
|
| - fprintf(stderr, "ERROR! BAD hex value!\n");
|
| - }
|
| -}
|
| -
|
| -// Does the inverse of ConvertColRowToHexManiac
|
| -// Input of 10:1 should be 12:1
|
| -void ConvertHexManiacToColRow(int hex_i, int hex_j, int* column, int* row) {
|
| - fprintf(stderr, "ENTERED ConvertHexManiacToColRow %d %d\n", hex_i, hex_j);
|
| - if (hex_i + hex_j >= 11) { // FIXME -- magic number (11)
|
| - *column = hex_i + hex_j + 1;
|
| - *row = hex_j - *column + 11 + 1;
|
| - } else {
|
| - // input of hex 1:8 => 10:9
|
| - *row = hex_j + 1;
|
| - *column = hex_i + *row;
|
| - }
|
| - fprintf(stderr, " ... done conversion");
|
| - fprintf(stderr, " ... result is %d:%d\n", *column, *row);
|
| - std::cout << " ConvertHexManiacToColRow " << hex_i << ":" << hex_j
|
| - << " ... " << *column << ":" << *row << std::endl;
|
| -}
|
| -
|
| -
|
| -} // empty namepsace
|
|
|