LYNEのトリックプログラム

ルームメイトは最近STEAMのLYNEというゲームに夢中している

LYNE 01

 

ルールは簡単である:スタートからエンドまで同じ色な菱形をひとつのラインで繋ぐ

その難点は白い菱形のホールを最後の時に全て占用しなければいけないこと

だから、状況によって時々とっても難しいパゾルになることもある

LYNE 02

 

それでこのパゾル等を解けるためにひとつのプログラムを書きた

とても簡単で最適化されることもなかったプログラムなので、難しいパゾルなら時々多くの時間を掛かるかも知れない欠点があるけど(/ω\*)

#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

コメントを残す