/**
* @file
* Code to deal with 4x4 planes within the board.
*
* Last Modified: Sat Dec 27 09:16:23 PST 2014
* @author Kevin O'Gorman
*/
/*
* Copyright 2012-2014 Kevin O'Gorman <kogorman@gmail.com>.
* Distributed under the GNU General Public License.
*
* This file is part of libqubist, the library of functions for playing
* 4x4x4 tic-tac-toe, also known by some other names outside the USA.
*
* Libqubist is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2.
*
* Libqubist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @file
* Code to do various things with individual planes of the qube. Not currently used by
* the game engine, but may be of interest to other progams that use this library.
*
* The Qubic board (Qube) has 18 4x4 planes. Each can be thought of as an intersection
* of an infinite plane with the Qube. The count of 18 may seem a bit large if you're
* thinking just of planes that are perpedicular to an axis. It would be, but there are
* other planes that can form 4x4 intersections.
*
* There are 4 planes that are perpendicular to each axis, and 3 axes to form them for a
* total of 12 such planes. There are 6 additional, diagonal planes, each one
* intersecting two opposite edges of the Qube; there are 12 edges total, and thus 6
* diagonal planes. Thus, 18 planes.
*
* Each row is found in two or three different planes. Edge rows, interior rows and
* non-major diagoanl rows are found in two of the perpedicular planes and one diagonal
* plane. Other parallel rows (that do not contain any highly-connected squares) are
* found in two perpendicular planes. Major-diagonal rows are found in three diagonal
* planes.
*
* More information is contained in the iso.c comments.
*/
#include <stdlib.h>
#include <stdio.h>
#include "state.h"
#include "isoplane.h"
#undef NDEBUG
#define NDEBUG
#include <assert.h>
/**
* Array of isomorphisms. The initializer seeds it with the generators,
* and the code forms a kind of transitive closure.
*/
static int planeisos[64][16] = {
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, /* identity */
{12,8,4,0,13,9,5,1,14,10,6,2,15,11,7,3}, /* rotate clockwise */
{3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12}, /* mirror horizontally across vertical axis */
{5,4,7,6,1,0,3,2,13,12,15,14,9,8,11,10}, /* inside-out */
{0,2,1,3,8,10,9,11,4,6,5,7,12,14,13,15}}; /* inside scramble */
/** Count of the isos, intially 5 but should reach 64 */
static int isocount = 5;
#if 0 /* not yet implemented */
/**
* The 10 winning rows on the plane:
* 4 horizontal
* 4 vertical
* 2 diagonals
*/
static int planerows[10][4] = {
{ 0, 1, 2, 3},
{ 4, 5, 6, 7},
{ 8, 9,10,11},
{12,13,14,15},
{ 0, 4, 8,12},
{ 1, 5, 9,13},
{ 2, 6,10,14},
{ 3, 7,11,15},
{ 1, 5,10,15},
{ 3, 6, 9,12}};
static int rowvalues[10];
#endif
/**
* Predicate to tell if an iso is identical to any other that comes before.
*/
static int
qb_plane_isnew(int iso) {
int i, j;
for (i = 0; i < iso; i++) {
for (j = 0; j < 16; j++) {
if (planeisos[i][j] != planeisos[iso][j]) {
break;
}
}
if (j == 16) {
/* equal */
return 0; /* not new */
}
}
return 1;
}
/**
* Initialize the list of isomorphisms of the Qubic plane.
*/
void
qb_plane_create_isos(void) {
int i, j, k;
int nextiso = isocount;
for (i = 1; i < nextiso; i++) {
for (j = 0; j < i; j++) {
for (k = 0; k < 16; k++) {
planeisos[nextiso][k] = planeisos[i][planeisos[j][k]];
}
if (qb_plane_isnew(nextiso)) {
nextiso++;
isocount = nextiso;
break;
}
}
}
#ifndef NDEBUG
printf("There are %d isomorphisms of the Qubic plane.\n", isocount);
for (i = 0; i < isocount; i++) {
printf("%d ", i);
for (j = 0; j < 16; j++) {
printf("%3d", planeisos[i][j]);
}
putchar('\n');
}
#endif
}
int
qb_plane_find_canonic_iso(char *pos) {
int m, iso, bestiso;
bestiso = 0;
for (iso = 1; iso < isocount; iso++) {
for (m = 0; m < 16; m++) {
if (pos[planeisos[iso][m]] > pos[planeisos[bestiso][m]]) {
bestiso = iso;
break;
}
if (pos[planeisos[iso][m]] < pos[planeisos[bestiso][m]]) {
break;
}
}
}
return bestiso;
}
/**
* Interrogate a position in one of the isomorphisms.
*/
int
qb_plane_get_iso_spot(int iso, int spot) {
return planeisos[iso][spot];
}
/**
* Write a resentation of a position, as seen through an isomorphism.
*/
void
qb_write_plane_through_iso(char *pos, int iso, FILE *stream) {
int m;
for (m = 0; m < 16; m++) {
fputc(pos[planeisos[iso][m]], stream);
}
fputc('\n', stream);
}
/* vim: set expandtab autoindent shiftround nosmartindent tabstop=8 softtabstop=2 shiftwidth=2: */