ルームメイトは最近STEAMのLYNEというゲームに夢中している
ルールは簡単である:スタートからエンドまで同じ色な菱形をひとつのラインで繋ぐ
その難点は白い菱形のホールを最後の時に全て占用しなければいけないこと
だから、状況によって時々とっても難しいパゾルになることもある
それでこのパゾル等を解けるためにひとつのプログラムを書きた
とても簡単で最適化されることもなかったプログラムなので、難しいパゾルなら時々多くの時間を掛かるかも知れない欠点があるけど(/ω\*)
#include<iostream>
#include<string>
#include<memory.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define MAXLINK 650
using namespace std;
char square[20][20];
int sizex, sizey;
typedef int8_t link[4];
link links[MAXLINK];
bool letters[30];
clock_t t_start, t_end;
// Common Functions
char toSmall(char toConvert)
{
return (char)(toConvert + 32);
}
int toNum(char num)
{
return num - '0';
}
int8_t abs(int8_t origin)
{
if(origin >= 0)
return origin;
else
return -origin;
}
int8_t toSeq(char lt)
{
return lt - 'A';
}
char toLetter(int8_t k)
{
return k + 'A';
}
// Way-Searching Functions
void startNew(char lt);
bool availability(char lt, int8_t xNow, int8_t yNow, int8_t xStep, int8_t yStep);
bool finishLetter(char lt);
bool finishHole();
void getOutput();
void nextStep(char lt, int8_t xNow, int8_t yNow, bool startPoint)
{
//cout<<(int)xNow<<" "<<(int)yNow<<endl;
if(!startPoint)
{
// Whether there's a step could be taken
bool nextStepAvail = false;
for(int8_t yStep = -1; yStep <= 1; yStep++)
{
for(int8_t xStep = -1; xStep <=1; xStep++)
{
if(xStep == 0 && yStep == 0)
continue;
if(availability(lt, xNow, yNow, xStep, yStep))
{
nextStepAvail = true;
break;
}
}
if(nextStepAvail)
break;
}
if(!nextStepAvail || (square[xNow][yNow] >= 'A' && square[xNow][yNow] <= 'Z'))
{
// Stops at a hole
if(square[xNow][yNow] >= '0' && square[xNow][yNow] <= '8')
return;
// Stops at a color block which is not an endpoint
if(square[xNow][yNow] >= 'a' && square[xNow][yNow] <= 'z')
return;
// Stops at an endpoint
if(square[xNow][yNow] >= 'A' && square[xNow][yNow] <= 'Z')
{
// Now at an endpoint but the color unfinished
if(!finishLetter(square[xNow][yNow]))
return;
// A whole path of the color finished
// Check if there're other colors
int8_t k = toSeq(lt) + 1;
while(!letters[k])
{
if(k >= 26)
{
if(finishHole())
getOutput();
else
return;
break;
}
else
k++;
}
startNew(toLetter(k));
}
}
}
// Taking steps
for(int8_t yStep = -1; yStep <= 1; yStep++)
for(int8_t xStep = -1; xStep <=1; xStep++)
{
if(xStep == 0 && yStep == 0)
continue;
if(availability(lt, xNow, yNow, xStep, yStep))
{
// Add link
int i = 0;
while(links[i][0] != -1)
i++;
links[i][0] = xNow; links[i][1] = yNow;
links[i][2] = xNow + xStep; links[i][3] = yNow + yStep;
// Go
nextStep(lt, xNow + xStep, yNow + yStep, false);
// Clear link
memset(links[i], -1, sizeof(links[i]));
}
}
}
void startNew(char lt)
{
//cout<<"New: "<<lt<<endl;
int x, y;
bool found = false;
for(y = 0; y < sizey; y++)
{
for(x = 0; x < sizex; x++)
if(square[x][y] == lt)
{
found = true;
break;
}
if(found)
break;
}
nextStep(lt, x, y, true);
}
int8_t pointPathSum(int8_t x, int8_t y)
{
int8_t r = 0;
for(int i = 0; i < MAXLINK; i++)
if((links[i][0] == x && links[i][1] == y) || (links[i][2] == x && links[i][3] == y))
r++;
return r;
}
bool finishLetter(char lt)
{
for(int y = 0; y < sizey; y++)
for(int x = 0; x < sizex; x++)
{
//cout<<"Finish Letter: "<<(int)pointPathSum(x, y)<<endl;
if(square[x][y] == lt && pointPathSum(x, y) < 1)
return false;
if(square[x][y] == toSmall(lt) && pointPathSum(x, y) < 2)
return false;
}
return true;
}
bool finishHole()
{
for(int y = 0; y < sizey; y++)
for(int x = 0; x < sizex; x++)
{
if(square[x][y] >= '0' && square[x][y] <= '8')
if(pointPathSum(x, y) < toNum(square[x][y]))
return false;
}
return true;
}
bool availability(char lt, int8_t xNow, int8_t yNow, int8_t xStep, int8_t yStep)
{
int8_t xDes = xNow + xStep;
int8_t yDes = yNow + yStep;
// Out of the image
if(xDes < 0 || yDes < 0 || xDes >= sizex || yDes >= sizey)
return false;
// Color not match
if(square[xDes][yDes] >= 'A' && square[xDes][yDes] <= 'Z' && square[xDes][yDes] != lt)
return false;
if(square[xDes][yDes] >= 'a' && square[xDes][yDes] <= 'z' && square[xDes][yDes] != toSmall(lt))
return false;
// Color match but taken
if(square[xDes][yDes] == toSmall(lt) || square[xDes][yDes] == lt)
{
for(int i = 0; i < MAXLINK; i++)
if((links[i][0] == xDes && links[i][1] == yDes) || (links[i][2] == xDes && links[i][3] == yDes))
return false;
}
// Holes full
int taken = 0;
int avail = toNum(square[xDes][yDes]);
for(int i = 0; i < MAXLINK; i++)
if((links[i][0] == xDes && links[i][1] == yDes) || (links[i][2] == xDes && links[i][3] == yDes))
taken++;
if(taken == avail)
return false;
// X-Cross problem
if(abs(xStep) == 1 && abs(yStep) == 1)
{
for(int i = 0; i < MAXLINK; i++)
{
if(links[i][0] == xDes && links[i][1] == yNow && links[i][2] == xNow && links[i][3] == yDes)
return false;
if(links[i][0] == xNow && links[i][1] == yDes && links[i][2] == xDes && links[i][3] == yNow)
return false;
}
}
// Path taken
for(int i = 0; i < MAXLINK; i++)
{
if(links[i][0] == xNow && links[i][1] == yNow && links[i][2] == xDes && links[i][3] == yDes)
return false;
if(links[i][0] == xDes && links[i][1] == yDes && links[i][2] == xNow && links[i][3] == yNow)
return false;
}
// Available
return true;
}
void getOutput()
{
cout<<"Result: "<<endl;
for(int i = 0; i < MAXLINK; i++)
if(links[i][0] != -1)
cout<<"("<<(int)links[i][0]<<","<<(int)links[i][1]<<") TO ("<<(int)links[i][2]<<","<<(int)links[i][3]<<")"<<endl;
char result[40][40];
memset(result, ' ', sizeof(result));
for(int y = 0; y < sizey; y++)
for(int x = 0; x < sizex; x++)
{
result[x * 2][y * 2] = square[x][y];
}
for(int i = 0; i < MAXLINK; i++)
{
if(links[i][0] != -1)
{
if(abs(links[i][0] - links[i][2]) == 1 && links[i][1] == links[i][3])
result[links[i][0] + links[i][2]][links[i][1] + links[i][3]] = '-';
if(abs(links[i][1] - links[i][3]) == 1 && links[i][0] == links[i][2])
result[links[i][0] + links[i][2]][links[i][1] + links[i][3]] = '|';
if((links[i][0] - links[i][2]) == (links[i][1] - links[i][3]))
result[links[i][0] + links[i][2]][links[i][1] + links[i][3]] = '\\';
if((links[i][0] - links[i][2]) + (links[i][1] - links[i][3]) == 0)
result[links[i][0] + links[i][2]][links[i][1] + links[i][3]] = '/';
}
}
for(int y = 0; y < sizey * 2 - 1; y++)
{
for(int x = 0; x < sizex * 2 - 1; x++)
{
cout<<result[x][y];
}
cout<<endl;
}
t_end = clock();
double totalTime = (double)(t_end - t_start);
cout<<totalTime<<endl;
exit(0);
}
int main()
{
memset(square, '!', sizeof(square));
memset(links, -1, sizeof(links));
memset(letters, false, sizeof(letters));
cout<<"Input the size of the puzzle (x y): ";
cin>>sizex>>sizey;
cout<<"Input the puzzle."<<endl;
cout<<"Use Capital Letters for endpoints and the same Small Letters for the paths;"<<endl;
cout<<"Use Numbers for the holes."<<endl<<endl;
for(int y = 0; y < sizey; y++)
for(int x = 0; x < sizex; x++)
{
cin>>square[x][y];
if(square[x][y] >= 'A' && square[x][y] <= 'Z')
letters[toSeq(square[x][y])] = true;
if(square[x][y] >= '1' && square[x][y] <= '4')
square[x][y] = toNum(square[x][y]) * 2 + '0';
}
t_start = clock();
int8_t k = 0;
while(!letters[k])
k++;
startNew(toLetter(k));
return 0;
}
Steamコミュニティよりのテストデータ
C-09 3x3 y 2 B Y 3 2 Y b B F-01 4x4 B b b Y r r R 2 B 3 3 y b b R Y X-01 3x8 a a a a a a A 2 A a a a 2 3 a 2 3 0 a 3 a a a a Z-01 4x8 r r r R r 3 2 r r R r r y Y b B 2 3 2 B 2 3 Y b y 2 4 b 0 y y b Z-02 4x8 Y 2 y y r r 4 y R r y r Y 2 y r B b r 2 b 3 3 b b 3 2 2 R B b 0


