ফ্লাড পেইন্ট এআই তৈরি করুন


34

ফ্লাড পেইন্টের খেলায়, গেমটির লক্ষ্যটি হ'ল যতটা সম্ভব কয়েকটি টার্নে পুরো বোর্ডটি একই রঙে পাওয়া যায়।

খেলাটি এমন বোর্ডের সাহায্যে শুরু হয় যা এরকম কিছু দেখায়:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 5 5 5 4 1 4
6 2 5 3[3]1 1 6 6
5 5 1 2 5 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

বোর্ডের কেন্দ্রে বর্তমানে সংখ্যা (একটি রঙের প্রতিনিধিত্ব করে) is Each অর্থাত্ কেন্দ্র বর্গক্ষেত্রের বন্যার অঞ্চলে) এর সাথে রঙ পরিবর্তন করবে। সুতরাং যদি কেন্দ্র বর্গাকার রঙটি 5 তে পরিবর্তন করে:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 5 5 5 4 1 4
6 2 5 5[5]1 1 6 6
5 5 1 2 5 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

তারপরে 3 যেটি 3 কেন্দ্রের বাম দিকে ছিল তাও রঙ পরিবর্তন করবে। এখন কেন্দ্রের এক থেকে মোট সাতটি 5 টি পৌঁছনীয় এবং তাই আমরা যদি তখন রঙ 4 এ পরিবর্তন করি:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 4 4 4 4 1 4
6 2 4 4[4]1 1 6 6
5 5 1 2 4 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

আঁকা অঞ্চলটি আবার আকারে নাটকীয়ভাবে বৃদ্ধি পায়।

আপনার কাজ হ'ল এমন একটি প্রোগ্রাম তৈরি করা যা আপনি 19-বাই-19 রঙের গ্রিড 1 থেকে 6 থেকে ইনপুট হিসাবে গ্রহণ করবেন, আপনি যে কোনও ফর্মই চয়ন করুন:

4 5 1 1 2 2 1 6 2 6 3 4 2 3 2 3 1 6 3
4 2 6 3 4 4 5 6 4 4 5 3 3 3 3 5 4 3 4
2 3 5 2 2 5 5 1 2 6 2 6 6 2 1 6 6 1 2
4 6 5 5 5 5 4 1 6 6 3 2 6 4 2 6 3 6 6
1 6 4 4 4 4 6 4 2 5 5 3 2 2 4 1 5 2 5
1 6 2 1 5 1 6 4 4 1 5 1 3 4 5 2 3 4 1
3 3 5 3 2 2 2 4 2 1 6 6 6 6 1 4 5 2 5
1 6 1 3 2 4 1 3 3 4 6 5 1 5 5 3 4 3 3
4 4 1 5 5 1 4 6 3 3 4 5 5 6 1 6 2 6 4
1 4 2 5 6 5 5 3 2 5 5 5 3 6 1 4 4 6 6
4 6 6 2 6 6 2 4 2 6 1 5 6 2 3 3 4 3 6
6 1 3 6 3 5 5 3 6 1 3 4 4 5 1 2 6 4 3
2 6 1 3 2 4 2 6 1 1 5 2 6 6 6 6 3 3 3
3 4 5 4 6 6 3 3 4 1 1 6 4 5 1 3 4 1 2
4 2 6 4 1 5 3 6 4 3 4 5 4 2 1 1 4 1 1
4 2 4 1 5 2 2 3 6 6 6 5 2 5 4 5 4 5 1
5 6 2 3 4 6 5 4 1 3 2 3 2 1 3 6 2 2 4
6 5 4 1 3 2 2 1 1 1 6 1 2 6 2 5 6 4 5
5 1 1 4 2 6 2 5 6 1 3 3 4 1 6 1 2 1 2

এবং রঙগুলির একটি ক্রম ফিরে আসুন যা কেন্দ্রের বর্গক্ষেত্রটি প্রতিটি পরিবর্তনে পরিবর্তিত হবে, আবার আপনার নির্বাচনের বিন্যাসে:

263142421236425431645152623645465646213545631465

প্রতিটি চলার ক্রম শেষে, 19-বাই-19 গ্রিডের স্কোয়ারগুলি অবশ্যই একই রঙের হবে।

আপনার প্রোগ্রামটি সম্পূর্ণরূপে নির্বিচারক হওয়া উচিত; সিউডোর্যান্ডম সমাধানগুলি অনুমোদিত, তবে প্রোগ্রামটি অবশ্যই প্রতিবার একই পরীক্ষার ক্ষেত্রে একই আউটপুট উত্পন্ন করতে হবে।

বিজয়ী প্রোগ্রামটি এই ফাইলটিতে পাওয়া সমস্ত 100,000 পরীক্ষার কেস সমাধানের জন্য সর্বনিম্ন মোট পদক্ষেপ গ্রহণ করবে (জিপযুক্ত পাঠ্য ফাইল, 14.23 মেগাবাইট)। যদি দুটি সমাধান একই সংখ্যক পদক্ষেপ নেয় (উদাহরণস্বরূপ যদি তারা উভয়ই অনুকূল কৌশলটি খুঁজে পেয়ে থাকে), তবে সংক্ষিপ্ত প্রোগ্রামটি জয়ী হবে।


বার্টপিজা পরীক্ষার ফলাফল যাচাই করার জন্য জাভাতে একটি প্রোগ্রাম লিখেছিল। এই প্রোগ্রামটি ব্যবহার করতে, আপনার জমা দিন এবং কোনও ফাইলকে আউটপুটটি পাইপ করুন steps.txt। তারপরে, একই ডিরেক্টরিতে এই প্রোগ্রামটি steps.txtএবং floodtestফাইলটি চালান । যদি আপনার এন্ট্রি বৈধ হয় এবং সমস্ত ফাইলের জন্য সঠিক সমাধান উত্পাদন করে তবে এটি সমস্ত পরীক্ষা পাস করে ফিরে আসতে হবেAll boards solved successfully.

import java.io.*;
import java.util.*;

public class PainterVerifier {

    public static void main(String[] args) throws FileNotFoundException {

        char[] board = new char[361];

        Scanner s = new Scanner(new File("steps.txt"));
        Scanner b = new Scanner(new File("floodtest"));

        int lineNum = 0;

        caseloop: while (b.hasNextLine()) {

            for (int l = 0; l < 19; l++) {
                String lineb = b.nextLine();
                if (lineb.isEmpty())
                    continue caseloop;
                System.arraycopy(lineb.toCharArray(), 0, board, l * 19, 19);
            }

            String line = s.nextLine();
            if (line.isEmpty())
                continue;
            char[] steps = line.toCharArray();

            Stack<Integer> nodes = new Stack<Integer>();

            for (char c : steps) {
                char targetColor = board[180];
                char replacementColor = c;

                nodes.push(180);

                while (!nodes.empty()) {
                    int n = nodes.pop();
                    if (n < 0 || n > 360)
                        continue;
                    if (board[n] == targetColor) {
                        board[n] = replacementColor;
                        if (n % 19 > 0)
                            nodes.push(n - 1);
                        if (n % 19 < 18)
                            nodes.push(n + 1);
                        if (n / 19 > 0)
                            nodes.push(n - 19);
                        if (n / 19 < 18)
                            nodes.push(n + 19);
                    }
                }
            }
            char center = board[180];
            for (char c : board)
                if (c != center) {
                    s.close();
                    b.close();

                    System.out.println("\nIncomplete board found!\n\tOn line " + lineNum + " of steps.txt");
                    System.exit(0);
                }

            if (lineNum % 5000 == 0)
                System.out.printf("Verification %d%c complete...\n", lineNum * 100 / 100000, '%');

            lineNum++;
        }
        s.close();
        b.close();
        System.out.println("All boards solved successfully.");
    }
}

এছাড়াও, একটি স্কোরবোর্ড, যেহেতু ফলাফলগুলি আসলে স্কোর অনুসারে বাছাই হয় না এবং এখানে এটি আসলে অনেকটাই গুরুত্বপূর্ণ:

  1. 1,985,078 - স্ম্যাক 42, জাভা
  2. 2,075,452 - ব্যবহারকারী1502040, সি
  3. 2,098,382 - টাইগ্রো, সি #
  4. 2,155,834 - কোডার টাও, সি #
  5. 2,201,995 - মিস্টারব্যাকেন্ড, জাভা
  6. 2,383,569 - কোডার টাও, সি #
  7. 2,384,020 - হার্জান, সি
  8. 2,403,189 - অরিজিনিল, জাভা
  9. 2,445,761 - হার্জান, সি
  10. 2,475,056 - জেরেমি তালিকা, হাস্কেল
  11. 2,480,714 - স্টিলটার্মাইট, সি (2,395 বাইট)
  12. 2,480,714 - হার্জান, জাভা (4,702 বাইট)
  13. 2,588,847 - বার্ন্ট পিজ্জা, জাভা (2,748 বাইট)
  14. 2,588,847 - Gero3, node.js (4,641 বাইট)
  15. 2,979,145 - টিউন প্রোঙ্ক , ডেল্ফি এক্সই 3
  16. 4,780,841 - বার্ন্ট পিজ্জা, জাভা
  17. 10,800,000 - জো জেড, পাইথন

2
আপনার নিজের জমা দিয়ে বিচার করে আউটপুটটিতে আসলে ফাঁকা স্থান থাকা উচিত নয়?
মার্টিন এন্ডার

5
এটি লক্ষণীয় যে পরীক্ষার ইনপুট ডেটার সংখ্যাগুলির মধ্যে ফাঁকা স্থান নেই।
nderscore

3
আপনি এখনও এটি লিখতে পারেন। যদি এটি বর্তমান বিজয়ীকে কমিয়ে দেয় তবে আমি স্বীকৃত উত্তরটি পরিবর্তন করব।
জো জে।

4
সময়ের সীমাবদ্ধতা হ'ল "এটি চালানোর জন্য এবং আপনার আসল ফলাফলগুলি এখানে পোস্ট করার জন্য আপনার পক্ষে যথেষ্ট দ্রুত হওয়া দরকার"।
জো জে।

2
@ আলেকজান্ডার রেভো আমি ভেবেছিলাম আমি ফাইলটি সরিয়ে নিই না, তবে দৃশ্যত লিঙ্কটি শেষ হয়েছে এবং আমাকে না করেই পরিবর্তন হয়েছে। এখানে আবার লিঙ্ক।
জো জেড।

উত্তর:


4

জাভা - 1,985,078 পদক্ষেপ

https://github.com/smack42/ColorFill

আর একটি দেরীতে প্রবেশ। 1,985,078 পদক্ষেপযুক্ত ফলাফল ফাইলটি এখানে পাওয়া যাবে

কিছু পটভূমি তথ্য:

আমি এই চ্যালেঞ্জটি কয়েক বছর আগে আবিষ্কার করেছি, যখন আমি নিজের বন্যার-এটির নিজের ক্লোনটির প্রোগ্রামিং শুরু করি।

"সেরা-অসম্পূর্ণ" ডিএফএস এবং এ * অ্যালগোরিদম
শুরু থেকেই, আমি এই গেমটির জন্য একটি ভাল সলভার অ্যালগরিদম তৈরি করতে চেয়েছিলাম। সময়ের সাথে সাথে, বিভিন্ন অসম্পূর্ণ অনুসন্ধানগুলি (এখানে অন্যান্য প্রোগ্রামগুলিতে ব্যবহৃত একই ধরণের) এবং প্রতিটি সমাধানের জন্য সেই কৌশলগুলির সেরা ফলাফলটি ব্যবহার করে আমি বিভিন্ন কৌশল অন্তর্ভুক্ত করে আমার সমাধানকারীটিকে উন্নত করতে পারি। এমনকি আমি জাভাতে টাইগ্রোজের এ * অ্যালগোরিদম পুনরায় প্রয়োগ করেছি এবং টাইগ্রো'র ফলাফলের চেয়ে সামগ্রিক উন্নত সমাধান অর্জনের জন্য এটি আমার সলভারে যুক্ত করেছি।

সম্পূর্ণ ডিএফএস অ্যালগরিদম
তারপরে আমি একটি অ্যালগরিদমে ফোকাস করেছি যা সর্বদা অনুকূল সমাধানগুলি খুঁজে পায়। আমি আমার সম্পূর্ণ গভীরতার প্রথম অনুসন্ধান কৌশলটি অনুকূল করতে অনেক প্রচেষ্টা ব্যয় করেছি। অনুসন্ধানের গতি বাড়ানোর জন্য, আমি একটি হ্যাশম্যাপ অন্তর্ভুক্ত করেছি যা সমস্ত অন্বেষণকৃত রাজ্যগুলিকে সঞ্চয় করে, যাতে অনুসন্ধানটি আবারও অন্বেষণ এড়াতে পারে। যদিও এই অ্যালগরিদম সূক্ষ্মভাবে কাজ করে এবং সমস্ত 14x14 ধাঁধাটি দ্রুত যথেষ্ট পরিমাণে সমাধান করে, এটি খুব বেশি স্মৃতি ব্যবহার করে এবং এই কোড চ্যালেঞ্জের 19x19 ধাঁধা সহ খুব ধীরে ধীরে চলে runs

পুচার্ট এ * অ্যালগরিদম
কয়েক মাস আগে অ্যারোন এবং সাইমন পিউচার্ট দ্বারা বন্যা-ইট সমাধানকারীটি দেখার জন্য আমার সাথে যোগাযোগ করা হয়েছিল । সেই প্রোগ্রামটিতে একটি * * টাইপ অ্যালগরিদম একটি স্বীকৃত হিউরিস্টিক (টাইগ্রো'র বিপরীতে) এবং জম্প-পয়েন্ট অনুসন্ধানের মতো ছাঁটাইকে সরানো ব্যবহার করে। আমি দ্রুত লক্ষ করেছি যে এই প্রোগ্রামটি খুব দ্রুত এবং অনুকূল সমাধানগুলি খুঁজে পেয়েছে !

অবশ্যই, আমাকে এই দুর্দান্ত অ্যালগরিদমটি পুনরায় প্রয়োগ করতে হয়েছিল এবং এটি আমার প্রোগ্রামে যুক্ত করতে হয়েছিল। আমি আমার জাভা প্রোগ্রামটি পুচার্ট ভাইদের দ্বারা মূল সি ++ প্রোগ্রামের মতো দ্রুত চালানোর জন্য চেষ্টা করেছি। তারপরে আমি এই চ্যালেঞ্জের 100,000 পরীক্ষার ক্ষেত্রে চেষ্টা করার সিদ্ধান্ত নিয়েছি। আমার মেশিনে পুচার্ট এ * অ্যালগরিদমটি প্রয়োগ করে, 1,985,078 টি পদক্ষেপগুলি খুঁজে পেতে প্রোগ্রামটি 120 ঘন্টােরও বেশি সময় ধরে চালিত হয়েছিল

এই হতে হয় সম্ভাব্য সর্বোত্তম সমাধান যদি না সেখানে প্রোগ্রাম যা উপ-সন্তোষজনক সমাধান স্থাপিত হবে কিছু বাগ, এই চ্যালেঞ্জ করতে। যে কোনও প্রতিক্রিয়া স্বাগত!

সম্পাদনা করুন: কোডের প্রাসঙ্গিক অংশ এখানে যুক্ত করেছেন:

ক্লাস AStarPuchertStrategy

/**
 * a specific strategy for the AStar (A*) solver.
 * <p>
 * the idea is taken from the program "floodit" by Aaron and Simon Puchert,
 * which can be found at <a>https://github.com/aaronpuchert/floodit</a>
 */
public class AStarPuchertStrategy implements AStarStrategy {

    private final Board board;
    private final ColorAreaSet visited;
    private ColorAreaSet current, next;
    private final short[] numCaNotFilledInitial;
    private final short[] numCaNotFilled;

    public AStarPuchertStrategy(final Board board) {
        this.board = board;
        this.visited = new ColorAreaSet(board);
        this.current = new ColorAreaSet(board);
        this.next = new ColorAreaSet(board);
        this.numCaNotFilledInitial = new short[board.getNumColors()];
        for (final ColorArea ca : board.getColorAreasArray()) {
            ++this.numCaNotFilledInitial[ca.getColor()];
        }
        this.numCaNotFilled = new short[board.getNumColors()];
    }

    /* (non-Javadoc)
     * @see colorfill.solver.AStarStrategy#setEstimatedCost(colorfill.solver.AStarNode)
     */
    @Override
    public void setEstimatedCost(final AStarNode node) {

        // quote from floodit.cpp: int State::computeValuation()
        // (in branch "performance")
        //
        // We compute an admissible heuristic recursively: If there are no nodes
        // left, return 0. Furthermore, if a color can be eliminated in one move
        // from the current position, that move is an optimal move and we can
        // simply use it. Otherwise, all moves fill a subset of the neighbors of
        // the filled nodes. Thus, filling that layer gets us at least one step
        // closer to the end.

        node.copyFloodedTo(this.visited);
        System.arraycopy(this.numCaNotFilledInitial, 0, this.numCaNotFilled, 0, this.numCaNotFilledInitial.length);
        {
            final ColorAreaSet.FastIteratorColorAreaId iter = this.visited.fastIteratorColorAreaId();
            int nextId;
            while ((nextId = iter.nextOrNegative()) >= 0) {
                --this.numCaNotFilled[this.board.getColor4Id(nextId)];
            }
        }

        // visit the first layer of neighbors, which is never empty, i.e. the puzzle is not solved yet
        node.copyNeighborsTo(this.current);
        this.visited.addAll(this.current);
        int completedColors = 0;
        {
            final ColorAreaSet.FastIteratorColorAreaId iter = this.current.fastIteratorColorAreaId();
            int nextId;
            while ((nextId = iter.nextOrNegative()) >= 0) {
                final byte nextColor = this.board.getColor4Id(nextId);
                if (--this.numCaNotFilled[nextColor] == 0) {
                    completedColors |= 1 << nextColor;
                }
            }
        }
        int distance = 1;

        while(!this.current.isEmpty()) {
            this.next.clear();
            final ColorAreaSet.FastIteratorColorAreaId iter = this.current.fastIteratorColorAreaId();
            int thisCaId;
            if (0 != completedColors) {
                // We can eliminate colors. Do just that.
                // We also combine all these elimination moves.
                distance += Integer.bitCount(completedColors);
                final int prevCompletedColors = completedColors;
                completedColors = 0;
                while ((thisCaId = iter.nextOrNegative()) >= 0) {
                    final ColorArea thisCa = this.board.getColorArea4Id(thisCaId);
                    if ((prevCompletedColors & (1 << thisCa.getColor())) != 0) {
                        // completed color
                        // expandNode()
                        for (final int nextCaId : thisCa.getNeighborsIdArray()) {
                            if (!this.visited.contains(nextCaId)) {
                                this.visited.add(nextCaId);
                                this.next.add(nextCaId);
                                final byte nextColor = this.board.getColor4Id(nextCaId);
                                if (--this.numCaNotFilled[nextColor] == 0) {
                                    completedColors |= 1 << nextColor;
                                }
                            }
                        }
                    } else {
                        // non-completed color
                        // move node to next layer
                        this.next.add(thisCaId);
                    }
                }
            } else {
                // Nothing found, do the color-blind pseudo-move
                // Expand current layer of nodes.
                ++distance;
                while ((thisCaId = iter.nextOrNegative()) >= 0) {
                    final ColorArea thisCa = this.board.getColorArea4Id(thisCaId);
                    // expandNode()
                    for (final int nextCaId : thisCa.getNeighborsIdArray()) {
                        if (!this.visited.contains(nextCaId)) {
                            this.visited.add(nextCaId);
                            this.next.add(nextCaId);
                            final byte nextColor = this.board.getColor4Id(nextCaId);
                            if (--this.numCaNotFilled[nextColor] == 0) {
                                completedColors |= 1 << nextColor;
                            }
                        }
                    }
                }
            }

            // Move the next layer into the current.
            final ColorAreaSet tmp = this.current;
            this.current = this.next;
            this.next = tmp;
        }
        node.setEstimatedCost(node.getSolutionSize() + distance);
    }

}

ক্লাস AstarSolver অংশ

private void executeInternalPuchert(final ColorArea startCa) throws InterruptedException {
    final Queue<AStarNode> open = new PriorityQueue<AStarNode>(AStarNode.strongerComparator());
    open.offer(new AStarNode(this.board, startCa));
    AStarNode recycleNode = null;
    while (open.size() > 0) {
        if (Thread.interrupted()) { throw new InterruptedException(); }
        final AStarNode currentNode = open.poll();
        if (currentNode.isSolved()) {
            this.addSolution(currentNode.getSolution());
            return;
        } else {
            // play all possible colors
            int nextColors = currentNode.getNeighborColors(this.board);
            while (0 != nextColors) {
                final int l1b = nextColors & -nextColors; // Integer.lowestOneBit()
                final int clz = Integer.numberOfLeadingZeros(l1b); // hopefully an intrinsic function using instruction BSR / LZCNT / CLZ
                nextColors ^= l1b; // clear lowest one bit
                final byte color = (byte)(31 - clz);
                final AStarNode nextNode = currentNode.copyAndPlay(color, recycleNode, this.board);
                if (null != nextNode) {
                    recycleNode = null;
                    this.strategy.setEstimatedCost(nextNode);
                    open.offer(nextNode);
                }
            }
        }
        recycleNode = currentNode;
    }
}

ক্লাসের অংশ AStarNode

/**
 * check if this color can be played. (avoid duplicate moves)
 * the idea is taken from the program "floodit" by Aaron and Simon Puchert,
 * which can be found at <a>https://github.com/aaronpuchert/floodit</a>
 * @param nextColor
 * @return
 */
private boolean canPlay(final byte nextColor, final List<ColorArea> nextColorNeighbors) {
    final byte currColor = this.solution[this.solutionSize];
    // did the previous move add any new "nextColor" neighbors?
    boolean newNext = false;
next:   for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
        for (final ColorArea prevNeighbor : nextColorNeighbor.getNeighborsArray()) {
            if ((prevNeighbor.getColor() != currColor) && this.flooded.contains(prevNeighbor)) {
                continue next;
            }
        }
        newNext = true;
        break next;
    }
    if (!newNext) {
        if (nextColor < currColor) {
            return false;
        } else {
            // should nextColor have been played before currColor?
            for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
                for (final ColorArea prevNeighbor : nextColorNeighbor.getNeighborsArray()) {
                    if ((prevNeighbor.getColor() == currColor) && !this.flooded.contains(prevNeighbor)) {
                        return false;
                    }
                }
            }
            return true;
        }
    } else {
        return true;
    }
}

/**
 * try to re-use the given node or create a new one
 * and then play the given color in the result node.
 * @param nextColor
 * @param recycleNode
 * @return
 */
public AStarNode copyAndPlay(final byte nextColor, final AStarNode recycleNode, final Board board) {
    final List<ColorArea> nextColorNeighbors = new ArrayList<ColorArea>(128);  // constant, arbitrary initial capacity
    final ColorAreaSet.FastIteratorColorAreaId iter = this.neighbors.fastIteratorColorAreaId();
    int nextId;
    while ((nextId = iter.nextOrNegative()) >= 0) {
        final ColorArea nextColorNeighbor = board.getColorArea4Id(nextId);
        if (nextColorNeighbor.getColor() == nextColor) {
            nextColorNeighbors.add(nextColorNeighbor);
        }
    }
    if (!this.canPlay(nextColor, nextColorNeighbors)) {
        return null;
    } else {
        final AStarNode result;
        if (null == recycleNode) {
            result = new AStarNode(this);
        } else {
            // copy - compare copy constructor
            result = recycleNode;
            result.flooded.copyFrom(this.flooded);
            result.neighbors.copyFrom(this.neighbors);
            System.arraycopy(this.solution, 0, result.solution, 0, this.solutionSize + 1);
            result.solutionSize = this.solutionSize;
            //result.estimatedCost = this.estimatedCost;  // not necessary to copy
        }
        // play - compare method play()
        for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
            result.flooded.add(nextColorNeighbor);
            result.neighbors.addAll(nextColorNeighbor.getNeighborsIdArray());
        }
        result.neighbors.removeAll(result.flooded);
        result.solution[++result.solutionSize] = nextColor;
        return result;
    }
}

2
পিপিসিজিতে আপনাকে স্বাগতম! আপনি নিজেই উত্তরটিতে সমাধানকারীটির জন্য প্রাসঙ্গিক কোডটি অন্তর্ভুক্ত করতে পারেন, যাতে এটি স্বয়ংসম্পূর্ণ থাকে, আপনার গিথুব রেপো কি কখনও চলতে বা নিচে যেতে হবে?
মার্টিন ইন্ডার

কোডটির সর্বাধিক প্রাসঙ্গিক অংশ এখানে যুক্ত করা হয়েছে: "পুশার্ট এ * অ্যালগরিদম" এর আমার বাস্তবায়ন। (এই কোড উদ্ধৃতিটি স্বয়ংসম্পূর্ণ নয় এবং যেমনটি সংকলন করা যায় না)
স্মাক 42

আমি খুশি যে কেউ এর জন্য একটি নিখুঁত / অনুকূল সমাধান খুঁজে পেয়েছে। তবে অন্যদিকে, এর অর্থ আর কোনও প্রতিযোগিতা / নতুন উত্তর থাকবে না।
tigrou

15

সি # - 2,098,382 পদক্ষেপ

আমি অনেক কিছুই চেষ্টা করে দেখি, বেশিরভাগ ব্যর্থ হয়েছে এবং কিছুক্ষণ আগে পর্যন্ত কাজ করে নি। আমি উত্তর পোস্ট করার জন্য যথেষ্ট আকর্ষণীয় কিছু পেয়েছি।

এটিকে আরও আরও উন্নত করার অবশ্যই উপায় রয়েছে। আমি মনে করি 2M পদক্ষেপের অধীনে যাওয়া সম্ভব হতে পারে।

এটি 7 hoursফলাফল উত্পন্ন করতে প্রায় লেগেছিল । সমস্ত সমাধান সহ এখানে একটি টেক্সট ফাইল রয়েছে, যদি কেউ তাদের পরীক্ষা করতে চান: ফলাফল.জিপ

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FloodPaintAI
{
    class Node
    {   
        public byte Value;             //1-6
        public int Index;              //unique identifier, used for easily deepcopying the graph
        public List<Node> Neighbours;  
        public List<Tuple<int, int>> NeighboursPositions; //used by BuildGraph() 

        public int Depth;    //used by GetSumDistances() 
        public bool Checked; // 

        public Node(byte value, int index)
        {
            Value = value;      
            Index = index;          
        }

        public Node(Node node)
        {           
            Value = node.Value; 
            Index = node.Index;                     
        }
    }

    class Board
    {
        private const int SIZE = 19;
        private const int STARTPOSITION = 9;

        public Node Root;         //root of graph. each node is a set of contiguous, same color square
        public List<Node> Nodes;  //all nodes in the graph, used for deep copying


        public int EstimatedCost; //estimated cost, used by A* Pathfinding
        public List<byte> Solution;

        public Board(StreamReader input)
        {                   
            byte[,] board = new byte[SIZE, SIZE];
            for(int j = 0 ; j < SIZE ; j++)
            {
                string line = input.ReadLine();
                for(int i = 0 ; i < SIZE ; i++)         
                {                                       
                    board[j, i] = byte.Parse(line[i].ToString());
                }               
            }
            Solution = new List<byte>();
            BuildGraph(board);  
        }

        public Board(Board boardToCopy)
        {               
            //copy the graph            
            Nodes = new List<Node>(boardToCopy.Nodes.Count);
            foreach(Node nodeToCopy in boardToCopy.Nodes)
            {
                Node node = new Node(nodeToCopy);
                Nodes.Add(node);
            }

            //copy "Neighbours" property
            for(int i = 0 ; i < boardToCopy.Nodes.Count ; i++)
            {
                Node node = Nodes[i];
                Node nodeToCopy = boardToCopy.Nodes[i];

                node.Neighbours = new List<Node>(nodeToCopy.Neighbours.Count);
                foreach(Node neighbour in nodeToCopy.Neighbours)
                {
                    node.Neighbours.Add(Nodes[neighbour.Index]);
                }
            }

            Root = Nodes[boardToCopy.Root.Index];
            EstimatedCost = boardToCopy.EstimatedCost;          
            Solution = new List<byte>(boardToCopy.Solution);            
        }

        private void BuildGraph(byte[,] board)
        {                       
            int[,] nodeIndexes = new int[SIZE, SIZE];
            Nodes = new List<Node>();

            //check how much sets we have (1st pass)
            for(int j = 0 ; j < SIZE ; j++)
            {
                for(int i = 0 ; i < SIZE ; i++)         
                {               
                    if(nodeIndexes[j, i] == 0) //not already visited                    
                    {
                        Node newNode = new Node(board[j, i], Nodes.Count);                      
                        newNode.NeighboursPositions = new List<Tuple<int, int>>();
                        Nodes.Add(newNode);

                        BuildGraphFloodFill(board, nodeIndexes, newNode, i, j, board[j, i]);
                    }
                }       
            }

            //set neighbours and root (2nd pass)
            foreach(Node node in Nodes)
            {
                node.Neighbours = new List<Node>();
                node.Neighbours.AddRange(node.NeighboursPositions.Select(x => nodeIndexes[x.Item2, x.Item1]).Distinct().Select(x => Nodes[x - 1]));
                node.NeighboursPositions = null;                
            }
            Root = Nodes[nodeIndexes[STARTPOSITION, STARTPOSITION] - 1];            
        }

        private void BuildGraphFloodFill(byte[,] board, int[,] nodeIndexes, Node node, int startx, int starty, byte floodvalue)
        {
            Queue<Tuple<int, int>> queue = new Queue<Tuple<int, int>>();
            queue.Enqueue(new Tuple<int, int>(startx, starty));

            while(queue.Count > 0)
            {
                Tuple<int, int> position = queue.Dequeue();
                int x = position.Item1;
                int y = position.Item2;

                if(x >= 0 && x < SIZE && y >= 0 && y < SIZE)
                {
                    if(nodeIndexes[y, x] == 0 && board[y, x] == floodvalue)
                    {
                        nodeIndexes[y, x] = node.Index + 1;

                        queue.Enqueue(new Tuple<int, int>(x + 1, y));
                        queue.Enqueue(new Tuple<int, int>(x - 1, y));
                        queue.Enqueue(new Tuple<int, int>(x, y + 1));
                        queue.Enqueue(new Tuple<int, int>(x, y - 1));                                           
                    }               
                    if(board[y, x] != floodvalue)
                        node.NeighboursPositions.Add(position);                         
                }       
            }
        }

        public int GetEstimatedCost()
        {       
            Board current = this;

            //copy current board and play the best color until the end.
            //number of moves required to go the end is the heuristic
            //estimated cost = current cost + heuristic
            while(!current.IsSolved())
            {
                int minSumDistance = int.MaxValue;
                Board minBoard = null;

                //find color which give the minimum sum of distance from root to each other node
                foreach(byte i in current.Root.Neighbours.Select(x => x.Value).Distinct())
                {
                    Board copy = new Board(current);
                    copy.Play(i);                   

                    int distance = copy.GetSumDistances();                  

                    if(distance < minSumDistance)
                    {
                        minSumDistance = distance;
                        minBoard = copy;
                    }
                }
                current = minBoard;
            }           
            return current.Solution.Count;
        }

        public int GetSumDistances()
        {
            //get sum of distances from root to each other node, using BFS
            int sumDistances = 0;           

            //reset marker
            foreach(Node n in Nodes)
            {
                n.Checked = false;                                  
            }

            Queue<Node> queue = new Queue<Node>();
            Root.Checked = true;
            Root.Depth = 0; 
            queue.Enqueue(Root);

            while(queue.Count > 0)
            {
                Node current = queue.Dequeue();                             
                foreach(Node n in current.Neighbours)
                {
                    if(!n.Checked)          
                    {                                   
                        n.Checked = true;                                               
                        n.Depth = current.Depth + 1;
                        sumDistances += n.Depth;            
                        queue.Enqueue(n);   
                    }               
                }
            }
            return sumDistances;
        }       

        public void Play(byte value)            
        {
            //merge root node with other neighbours nodes, if color is matching
            Root.Value = value;
            List<Node> neighboursToRemove = Root.Neighbours.Where(x => x.Value == value).ToList();
            List<Node> neighboursToAdd = neighboursToRemove.SelectMany(x => x.Neighbours).Except((new Node[] { Root }).Concat(Root.Neighbours)).ToList();

            foreach(Node n in neighboursToRemove)
            {
                foreach(Node m in n.Neighbours)
                {
                    m.Neighbours.Remove(n);
                }
                Nodes.Remove(n);
            }   

            foreach(Node n in neighboursToAdd)
            {
                Root.Neighbours.Add(n);         
                n.Neighbours.Add(Root); 
            }           

            //re-synchronize node index
            for(int i = 0 ; i < Nodes.Count ; i++)
            {
                Nodes[i].Index = i;
            }           
            Solution.Add(value);
        }

        public bool IsSolved()
        {           
            //return Nodes.Count == 1;
            return Root.Neighbours.Count == 0;  
        }           
    }


    class Program
    {       
        public static List<byte> Solve(Board input)
        {
            //A* Pathfinding            
            LinkedList<Board> open = new LinkedList<Board>();       
            input.EstimatedCost = input.GetEstimatedCost();
            open.AddLast(input);            

            while(open.Count > 0)
            {                       
                Board current = open.First.Value;
                open.RemoveFirst();

                if(current.IsSolved())
                {
                    return current.Solution;                
                }
                else
                {
                    //play all neighbours nodes colors
                    foreach(byte i in current.Root.Neighbours.Select(x => x.Value).Distinct())
                    {                       
                        Board newBoard = new Board(current);
                        newBoard.Play(i);           
                        newBoard.EstimatedCost = newBoard.GetEstimatedCost();   

                        //insert board to open list
                        bool inserted = false;
                        for(LinkedListNode<Board> node = open.First ; node != null ; node = node.Next)
                        {                               
                            if(node.Value.EstimatedCost > newBoard.EstimatedCost)
                            {
                                open.AddBefore(node, newBoard);
                                inserted = true;
                                break;
                            }
                        }       
                        if(!inserted)
                            open.AddLast(newBoard);                                                 
                    }   
                }   
            }
            throw new Exception(); //no solution found, impossible
        }   

        public static void Main(string[] args)
        {                   
            using (StreamReader sr = new StreamReader("floodtest"))
            {   
                while(!sr.EndOfStream)
                {                               
                    List<Board> boards = new List<Board>();
                    while(!sr.EndOfStream && boards.Count < 100)
                    {
                        Board board = new Board(sr);                        
                        sr.ReadLine(); //skip empty line
                        boards.Add(board);
                    }                                           
                    List<byte>[] solutions = new List<byte>[boards.Count];                                          
                    Parallel.For(0, boards.Count, i => 
                    {                               
                        solutions[i] = Solve(boards[i]); 
                    });                                         
                    foreach(List<byte> solution in solutions)
                    {
                        Console.WriteLine(string.Join(string.Empty, solution));                                             
                    }       
                }               
            }
        }
    }
}

এটি কীভাবে কাজ করে সে সম্পর্কে আরও বিশদ:

এটি এ * প্যাথফাইন্ডিং অ্যালগরিদম ব্যবহার করে ।

যেটি কঠিন তা হ'ল একটি ভাল খুঁজে পাওয়া heuristic। যদি heuristicএটির ব্যয়কে অবমূল্যায়ন করা হয় তবে এটি প্রায় ডিজিকস্ট্রার অ্যালগরিদমের মতো সঞ্চালিত হবে এবং 6 টি রঙযুক্ত 19x19 বোর্ডের জটিলতার কারণে এটি চিরতরে চলে। যদি এটির ব্যয়কে অতিমাত্রায় বিবেচনা করা হয় তবে তা দ্রুত কোনও সমাধানে রূপান্তরিত হবে তবে ভাল কিছু দেবে না (26 টি পদক্ষেপের 19 টি যেমন সম্ভব ছিল)। heuristicসমাধানে পৌঁছানোর সঠিক পদক্ষেপের সঠিক পরিমাণটি দেয় এমন নিখুঁত সন্ধান করা সর্বোত্তম (এটি দ্রুত হবে এবং সর্বোত্তম সম্ভাব্য সমাধান দেবে)। এটি (আমি ভুল না হলে) অসম্ভব। এটি প্রথমে বোর্ডকে নিজেই সমাধান করার দরকার হয়, যখন আপনি আসলে এটি করার চেষ্টা করছেন (মুরগী ​​এবং ডিমের সমস্যা)

আমি অনেক কিছুই চেষ্টা করেছিলাম, এখানে যা কাজ করেছে তা হল heuristic:

  • আমি মূল্যায়নের জন্য বর্তমান বোর্ডের একটি গ্রাফ তৈরি করি । প্রত্যেকে nodeএকত্রে একই রঙের স্কোয়ারের প্রতিনিধিত্ব করে। এটি ব্যবহার করে graph, আমি সহজেই কেন্দ্র থেকে অন্য কোনও নোডের সঠিক ন্যূনতম দূরত্ব গণনা করতে পারি। উদাহরণস্বরূপ কেন্দ্র থেকে উপরের বাম দিকে দূরত্ব 10 হবে কারণ কমপক্ষে 10 টি রঙ তাদের আলাদা করে।
  • গণনার জন্য heuristic: আমি বর্তমান বোর্ডটি শেষ অবধি খেলি। প্রতিটি পদক্ষেপের জন্য, আমি রঙটি চয়ন করি যা মূল থেকে সমস্ত অন্যান্য নোডের দূরত্বের যোগফলকে হ্রাস করবে।
  • এই প্রান্তে পৌঁছানোর জন্য প্রয়োজনীয় চালগুলির সংখ্যা হ'ল heuristic

  • Estimated cost(এ * দ্বারা ব্যবহৃত) = moves so far+heuristic

এটি নিখুঁত নয় কারণ এটি ব্যয়টিকে সামান্য পরিমাণে দেখায় (এইভাবে নন অনুকূল সমাধানটি পাওয়া যায়)। যাইহোক এটি গণনা করা এবং ভাল ফলাফল দেওয়ার পক্ষে দ্রুত।

আমি সমস্ত ক্রিয়াকলাপ সম্পাদন করতে গ্রাফ ব্যবহার করে বিশাল গতির উন্নতি করতে সক্ষম হয়েছি। ভিক্ষা করতে গিয়ে আমার একটা 2-dimensionঅ্যারে ছিল । আমি এটি প্লাবন করি এবং যখন প্রয়োজন হয় তখন গ্রাফটি পুনরায় গণনা করি (যেমন: হিউরিস্টিক গণনা করা)। এখন সমস্ত কিছু গ্রাফটি ব্যবহার করেই করা হয়, যা কেবল শুরুতে গণনা করা হয়। পদক্ষেপগুলি অনুকরণ করতে, বন্যার ভরাট আর প্রয়োজন হয় না, আমি পরিবর্তে নোডগুলি মার্জ করি। এটি অনেক দ্রুত।


2
code blocksপাঠ্যের উপর জোর দেওয়ার জন্য দয়া করে ব্যবহার করবেন না । আমরা এর জন্য তির্যক এবং সাহসী আছে ।
তহবিল মনিকার লসুইট

10

পাইথন - 10,800,000 পদক্ষেপ

শেষ স্থানের রেফারেন্স সমাধান হিসাবে, এই ক্রমটি বিবেচনা করুন:

print "123456" * 18

সমস্ত রঙের nসময় সাইকেল চালানোর অর্থ হ'ল প্রতিটি বর্গ nধাপ দূরে কেন্দ্র বর্গক্ষেত্রের মতো একই রঙের গ্যারান্টি দেওয়া হবে। প্রতিটি স্কোয়ারটি কেন্দ্র থেকে সর্বাধিক 18 ধাপ দূরে থাকে, সুতরাং 18 চক্র সমস্ত স্কোয়ার একই বর্ণের গ্যারান্টি দেবে। সম্ভবত এটি এর চেয়ে কম সময়ে শেষ হবে, তবে সমস্ত স্কোয়ার একই রঙ হওয়ার সাথে সাথে প্রোগ্রামটি থামার প্রয়োজন নেই; এটি করা আরও অনেক বেশি উপকারী। এই ধ্রুবক পদ্ধতিটি মোট পরীক্ষার ক্ষেত্রে 108 টি পদক্ষেপ, মোট 10,800,000 এর জন্য।


গুরুতর জোর পদ্ধতি, গুরুতর ...? জো, আমি ভেবেছিলাম আপনার আরও ভাল অভিজ্ঞতা সম্পর্কে আরও কিছু অভিজ্ঞতা আছে, সাথী?
ওয়ালিওয়েস্ট

2
এটি কোনও গুরুতর প্রবেশ হিসাবে বোঝানো হয়নি। নোট করুন যে আমি এটি সমাধান হিসাবে বিশেষভাবে শেষ স্থানে ক্যাচ-অল হিসাবে কাজ করার জন্য রেখেছি । যে কোনও গুরুতর প্রবেশের স্কোর এটির চেয়ে অনেক কম হবে।
জো জে।

জায়গা থাকতে হবে না? মতই 1 2 3 4 5 6 ...পরিবর্তে আপনার বর্তমান সমাধান যা দেয় 123456...
ব্যবহারকারী 80551

1
কোড গল্ফের জন্য অনুকূল অ্যালগরিদম হবে (অন্য কোনও ভাষায় যদিও "মুদ্রণ" অনেক বেশি অক্ষর)।
ক্রંચার

1
আমি আরও মনে করি না যে 18 টি পদক্ষেপের সবচেয়ে খারাপ পরিস্থিতি এমনকি সম্ভব । তবে অবশ্যই আমরা জানি যে এর চেয়ে খারাপ আর কোনও মামলা নেই, তাই এটি অবশ্যই কাজ করে :)
ক্রাঙ্কার

8

জাভা - 2,480,714 পদক্ষেপ

আমি এর আগে কিছুটা ভুল করেছি (আমি লুপের পরিবর্তে একটি লুপের আগে একটি গুরুত্বপূর্ণ বাক্যটি রেখেছিলাম:

import java.io.*;

public class HerjanPaintAI {

    BufferedReader r;
    String[] map = new String[19];
    char[][] colors = new char[19][19];
    boolean[][] reached = new boolean[19][19], checked = new boolean[19][19];
    int[] colorCounter = new int[6];
    String answer = "";
    int mapCount = 0, moveCount = 0;

    public HerjanPaintAI(){
        nextMap();

        while(true){

            int bestMove = nextRound();
            answer += bestMove;
            char t = Character.forDigit(bestMove, 10);
            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    if(reached[x][y]){
                        colors[x][y] = t;
                    }else if(checked[x][y]){
                        if(colors[x][y] == t){
                            reached[x][y] = true;
                        }
                    }
                }
            }

            boolean gameOver = true;
            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    if(!reached[x][y]){
                        gameOver = false;
                        break;
                    }
                }
            }

            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    checked[x][y] = false;
                }
            }
            for(int i = 0; i < 6; i++)
                colorCounter[i] = 0;

            if(gameOver)
                nextMap();
        }
    }

    int nextRound(){
        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                if(reached[x][y]){//check what numbers are next to the reached numbers...
                    check(x, y);
                }
            }
        }

        int[] totalColorCount = new int[6];
        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                totalColorCount[Character.getNumericValue(colors[x][y])-1]++;
            }
        }

        for(int i = 0; i < 6; i++){
            if(totalColorCount[i] != 0 && totalColorCount[i] == colorCounter[i]){//all of this color can be reached
                return i+1;
            }
        }

        int index = -1, number = 0;
        for(int i = 0; i < 6; i++){
            if(colorCounter[i] > number){
                index = i;
                number = colorCounter[i];
            }
        }

        return index+1;
    }

    void check(int x, int y){
        if(x<18)
            handle(x+1, y, x, y);
        if(x>0)
            handle(x-1, y, x, y);
        if(y<18)
            handle(x, y+1, x, y);
        if(y>0)
            handle(x, y-1, x, y);
    }

    void handle(int x2, int y2, int x, int y){
        if(!reached[x2][y2] && !checked[x2][y2]){
            checked[x2][y2] = true;
            if(colors[x2][y2] == colors[x][y]){
                reached[x2][y2] = true;
                check(x2, y2);
            }else{
                colorCounter[Character.getNumericValue(colors[x2][y2])-1]++;
                checkAround(x2, y2);
            }
        }
    }

    void checkAround(int x2, int y2){
        if(x2<18)
            handleAround(x2+1, y2, x2, y2);
        if(x2>0)
            handleAround(x2-1, y2, x2, y2);
        if(y2<18)
            handleAround(x2, y2+1, x2, y2);
        if(y2>0)
            handleAround(x2, y2-1, x2, y2);
    }

    void handleAround(int x2, int y2, int x, int y){
        if(!reached[x2][y2] && !checked[x2][y2]){
            if(colors[x2][y2] == colors[x][y]){
                checked[x2][y2] = true;
                colorCounter[Character.getNumericValue(colors[x2][y2])-1]++;
                checkAround(x2, y2);
            }
        }
    }

    void nextMap(){
        moveCount += answer.length();
        System.out.println(answer);
        answer = "";

        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                reached[x][y] = false;
            }
        }

        reached[9][9] = true;

        try {
            if(r == null)
                r = new BufferedReader(new FileReader("floodtest"));

            for(int i = 0; i < 19; i++){
                map[i] = r.readLine();
            }
            r.readLine();//empty line

            if(map[0] == null){
                System.out.println("Maps solved: " + mapCount + " Steps: " + moveCount);
                r.close();
                System.exit(0);
            }
        } catch (Exception e) {e.printStackTrace();}

        mapCount++;

        for(int x = 0; x < 19; x++){
            colors[x] = map[x].toCharArray();
        }
    }

    public static void main(String[] a){
        new HerjanPaintAI();
    }
}

এটি চালাতে কত সময় নিয়েছে?
আলেকজান্দার-ব্রেট

@ ali0sha আমার পিসি আধ মিনিটও সময় নেয় নি
হার্জান

ভাল বকাবকি। আমার আধ ঘন্টা ধরে চলছে ...
আলেকজান্ডার-ব্রেট

গল্ফিং প্রয়োজন হয় না, উপায় দ্বারা।
জো জে।

1
@ m.buettner শয়তানের কথা বলুন, কারও কারও কাছে করেনি এই সমাধান গিঁট (এবং খাটো কোড ছিল) তিন ঘণ্টা পর আপনি যে বলেন।
জো জে।

5

সি - 2,075,452

আমি জানি আমি পার্টিতে চূড়ান্ত দেরি করেছি, কিন্তু আমি এই চ্যালেঞ্জটি দেখেছি এবং যেতে চাইছি।

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

uint64_t rand_state;

uint64_t rand_u64(void) {
    return (rand_state = rand_state * 6364136223846793005ULL + 1442695040888963407ULL);
}

uint64_t better_rand_u64(void) {
    uint64_t r = rand_u64();
    r ^= ((r >> 32) >> (r >> 60));
    return r + 1442695040888963407ULL;
}

uint32_t rand_u32(void) {return rand_u64() >> 32;}

float normal(float mu, float sigma) {
    uint64_t t = 0;
    for (int i = 0; i < 6; i++) {
        uint64_t r = rand_u64();
        uint32_t a = r;
        uint32_t b = r >> 32;
        t += a;
        t += b;
    }
    return ((float)t / (float)UINT32_MAX - 6) * sigma + mu;
}

typedef struct {
    uint8_t x;
    uint8_t y;
} Position;

#define ncolors 6
#define len 19
#define cells (len * len)
#define max_steps (len * (ncolors - 1))
#define center_x 9
#define center_y 9
#define center ((Position){center_x, center_y})

uint64_t zobrist_table[len][len];

void init_zobrist() {
    for (int y = 0; y < len; y++) {
        for (int x = 0; x < len; x++) {
            zobrist_table[y][x] = better_rand_u64();
        }
    }
}

typedef struct {
    uint64_t hash;
    uint8_t grid[len][len];
    bool interior[len][len];
    int boundary_size;
    Position boundary[cells];
} Grid;


void transition(Grid* grid, uint8_t color, int* surrounding_counts) {
    int i = 0;
    while (i < grid->boundary_size) {
        Position p = grid->boundary[i];
        uint8_t x = p.x;
        uint8_t y = p.y;
        bool still_boundary = false;
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (!(dx == 0 || dy == 0)) {
                    continue;
                }
                int8_t x1 = x + dx;
                if (!(0 <= x1 && x1 < len)) {
                    continue;
                }
                int8_t y1 = y + dy;
                if (!(0 <= y1 && y1 < len)) {
                    continue;
                }
                if (grid->interior[y1][x1]) {
                    continue;
                }
                uint8_t color1 = grid->grid[y1][x1];
                if (color1 == color) {
                    grid->boundary[grid->boundary_size++] = (Position){x1, y1};
                    grid->interior[y1][x1] = true;
                    grid->hash ^= zobrist_table[y1][x1];
                } else {
                    surrounding_counts[color1]++;
                    still_boundary = true;
                }
            }
        }
        if (still_boundary) {
            i += 1;
        } else {
            grid->boundary[i] = grid->boundary[--grid->boundary_size]; 
        }
    }
}

void reset_grid(Grid* grid, int* surrounding_counts) {
    grid->hash = 0;
    memset(surrounding_counts, 0, ncolors * sizeof(int)); 
    memset(&grid->interior, 0, sizeof(grid->interior));
    grid->interior[center_y][center_x] = true;
    grid->boundary_size = 0;
    grid->boundary[grid->boundary_size++] = center; 
    transition(grid, grid->grid[center_y][center_x], surrounding_counts);
}

bool load_grid(FILE* fp, Grid* grid) {
    memset(grid, 0, sizeof(*grid));
    char buf[19 + 2];
    size_t row = 0;
    while ((fgets(buf, sizeof(buf), fp)) && row < 19) {
        if (strlen(buf) != 20) {
            break;
        }
        for (int i = 0; i < 19; i++) {
            if (!('1' <= buf[i] && buf[i] <= '6')) {
                return false;
            }
            grid->grid[row][i] = buf[i] - '1';
        }
        row++;
    }
    return row == 19;
}

typedef struct Node Node;

struct Node {
    uint64_t hash;
    float visit_counts[ncolors];
    float mean_cost[ncolors];
    float sse[ncolors];
};

#define iters 15000
#define pool_size 32768
#define pool_nodes (pool_size + 100)
#define pool_mask (pool_size - 1)

Node pool[pool_nodes];

void init_node(Node* node, uint64_t hash, int* surrounding_counts) {
    node->hash = hash;
    for (int i = 0; i < ncolors; i++) {
        if (surrounding_counts[i]) {
            node->visit_counts[i] = 1;
            node->mean_cost[i] = 20;
            node->sse[i] = 400;
        }
    }
}

Node* lookup_node(uint64_t hash) {
    size_t index = hash & pool_mask;
    for (int i = index;; i++) {
        uint64_t h = pool[i].hash;
        if (h == hash || !h) {
            return pool + i;
        }
    }
}

int rollout(Grid* grid, int* surrounding_counts, char* solution) {
    for (int i = 0;; i++) {
        int nonzero = 0;
        uint8_t colors[6];
        for (int i = 0; i < ncolors; i++) {
            if (surrounding_counts[i]) {
                colors[nonzero++] = i;
            }
        }
        if (!nonzero) {
            return i;
        }
        uint8_t color = colors[rand_u32() % nonzero]; 
        *(solution++) = color;
        assert(grid->boundary_size);
        memset(surrounding_counts, 0, 6 * sizeof(int));
        transition(grid, color, surrounding_counts);
    }
}

int simulate(Node* node, Grid* grid, int depth, char* solution) {
    float best_cost = INFINITY;
    uint8_t best_color = 255;
    for (int color = 0; color < ncolors; color++) {
        float n = node->visit_counts[color];
        if (node->visit_counts[color] == 0) {
            continue;
        }
        float sigma = sqrt(node->sse[color] / (n * n));
        float cost = node->mean_cost[color];
        cost = normal(cost, sigma);
        if (cost < best_cost) {
            best_color = color;
            best_cost = cost;
        }
    }
    if (best_color == 255) {
        return 0;
    }
    *solution++ = best_color;
    int score;
    int surrounding_counts[ncolors] = {0};
    transition(grid, best_color, surrounding_counts);
    Node* child = lookup_node(grid->hash);
    if (!child->hash) {
        init_node(child, grid->hash, surrounding_counts);
        score = rollout(grid, surrounding_counts, solution);
    } else {
        score = simulate(child, grid, depth + 1, solution);
    }
    score++;
    float n1 = ++node->visit_counts[best_color];
    float u0 = node->mean_cost[best_color];
    float u1 = node->mean_cost[best_color] = u0 + (score - u0) / n1;
    node->sse[best_color] += (score - u0) * (score - u1);
    return score;
}

int main(void) {
    FILE* fp;
    if (!(fp = fopen("floodtest", "r"))) {
        return 1;
    }
    Grid grid;
    init_zobrist();
    while (load_grid(fp, &grid)) {

        memset(pool, 0, sizeof(pool));
        int surrounding_counts[ncolors] = {0};

        reset_grid(&grid, surrounding_counts);
        Node root = {0};

        init_node(&root, grid.hash, surrounding_counts);

        char solution[max_steps] = {0};
        char best_solution[max_steps] = {0};

        int min_score = INT_MAX;

        uint64_t prev_hash = 0;
        uint64_t hash = 0;
        int same_count = 0;

        for (int iter = 0; iter < iters; iter++) {
            reset_grid(&grid, surrounding_counts);
            int score = simulate(&root, &grid, 1, solution);
            if (score < min_score) {
                min_score = score;
                memcpy(best_solution, solution, score);
            }
            hash = 0;
            for (int i = 0; i < score; i++) {
                hash ^= zobrist_table[i%len][(int)solution[i]];
            }
            if (hash == prev_hash) {
                same_count++;
                if (same_count >= 10) {
                    break;
                }
            } else {
                same_count = 0;
                prev_hash = hash;
            }
        }
        int i;
        for (i = 0; i < min_score; i++) {
            best_solution[i] += '1';
        }
        best_solution[i++] = '\n';
        best_solution[i++] = '\0';
        printf(best_solution);
        fflush(stdout);
    }
    return 0;
}

অ্যালগরিদম থম্পসন নমুনা সহ মন্টে-কার্লো ট্রি অনুসন্ধান এবং অনুসন্ধানের স্থান হ্রাস করার জন্য একটি ট্রান্সপোজিশন টেবিলের ভিত্তিতে তৈরি। আমার মেশিনে এটি প্রায় 12 ঘন্টা সময় নেয়। আপনি যদি ফলাফলগুলি পরীক্ষা করতে চান তবে আপনি সেগুলি https://DPfile.to/pvjYDMV এ খুঁজে পেতে পারেন ।


ব্যবহারকারী smack42 প্রোগ্রাম ক্র্যাশ ঠিক করতে পরিবর্তন hash ^= zobrist_table[i][(int)solution[i]];করার পরামর্শ দেয় hash ^= zobrist_table[i%len][(int)solution[i]];
স্টিফেন

@ স্টেপহেন আমি দেখতে পাচ্ছি না কীভাবে স্কোর লেনের চেয়ে বড় হতে পারে। আপনার কি এমন কোনও ইনপুট রয়েছে যা এই ক্রাশ করে? আপনার smak42 এর সাথে আপনার কথোপকথনের কোনও লিঙ্ক রয়েছে? এমনকি যদি ক্রাশ নাও হতে পারে তবে আমি মনে করি যে কোডটি পারফরম্যান্স-সমালোচনা না করে সেফ সাইডে থাকার কোনও ক্ষতি নেই।
ব্যবহারকারী1502040

না, দুঃখিত, এটি প্রস্তাবিত সম্পাদনাগুলিতে ছিল। এখানে পর্যালোচনাটি দেওয়া হয়েছে: কোডগল্ফ.স্ট্যাকেক্সেঞ্জারওয়েজ
স্টিফেন

আমাকে এখানে মারার জন্য +1 করুন তবে সাবধান থাকুন, কিছুটা উন্নতি হতে পারে;)
টাইপ করুন

4

জাভা - 2,434,108 2,588,847 পদক্ষেপ

বর্তমানে 4/26 হিসাবে জিতেছে (হার্জানের চেয়ে 46 ডলার এগিয়ে)

ওয়েলপ, তবে মিস্টারব্যাকেন্ড কেবল আমাকেই পরাজিত করেনি, তবে আমি একটি বাগ পেয়েছি যা একটি ছদ্মবেশী ভাল স্কোর তৈরি করেছে। এটি এখনই স্থির হয়ে গেছে (যাচাইকারীটিতেও ছিল! আক) তবে দুর্ভাগ্যক্রমে মুকুটটি চেষ্টা ও ফিরে নেওয়ার জন্য এই মুহুর্তে আমার আর কোনও সময় নেই। পরে চেষ্টা করবে।

এটি আমার অন্যান্য সমাধানের ভিত্তিতে তৈরি তবে ভরাট প্রান্তগুলিতে রঙের সাথে পেইন্টিংয়ের পরিবর্তে এটি রঙে পেইন্ট করে যা একই রঙের অনেক সংলগ্ন স্কোয়ারযুক্ত প্রান্তগুলিকে ফুটিয়ে তুলবে। এটিকে লুকএহেডপেইন্টার বলুন। আমি প্রয়োজন পরে এটি গল্ফ করব।

import java.io.*;
import java.util.*;

public class LookAheadPainter {

    static final boolean PRINT_FULL_OUTPUT = true;

    public static void main(String[] a) throws IOException {

        int totalSteps = 0, numSolved = 0;

        char[] board = new char[361];
        Scanner s = new Scanner(new File("floodtest"));
        long startTime = System.nanoTime();

        caseloop: while (s.hasNextLine()) {
            for (int l = 0; l < 19; l++) {
                String line = s.nextLine();
                if (line.isEmpty())
                    continue caseloop;
                System.arraycopy(line.toCharArray(), 0, board, l * 19, 19);
            }

            List<Character> colorsUsed = new ArrayList<>();

            for (;;) {

                FillResult fill = new FillResult(board, board[180], (char) 48, null);

                if (fill.nodesFilled.size() == 361)
                    break;

                int[] branchSizes = new int[7];

                for (int i = 1; i < 7; i++) {
                    List<Integer> seeds = new ArrayList<>();
                    for (Integer seed : fill.edges)
                        if (board[seed] == i + 48)
                            seeds.add(seed);

                    branchSizes[i] = new FillResult(fill.filledBoard, (char) (i + 48), (char) 48, seeds).nodesFilled.size();
                }

                int maxSize = 0;
                char bestColor = 0;

                for (int i = 1; i < 7; i++)
                    if (branchSizes[i] > maxSize) {
                        maxSize = branchSizes[i];
                        bestColor = (char) (i + 48);
                    }

                for (int i : fill.nodesFilled)
                    board[i] = bestColor;

                colorsUsed.add(bestColor);
                totalSteps++;
            }
            numSolved++;

            if (PRINT_FULL_OUTPUT) {
                if (numSolved % 1000 == 0)
                    System.out.println("Solved: " + numSolved); // So you know it's working
                String out = "";
                for (Character c : colorsUsed)
                    out += c;
                System.out.println(out);
            }

        }
        s.close();
        System.out.println("\nTotal steps to solve all cases: " + totalSteps);
        System.out.printf("\nSolved %d test cases in %.2f seconds", numSolved, (System.nanoTime() - startTime) / 1000000000.);
    }

    private static class FillResult {

        Set<Integer> nodesFilled, edges;
        char[] filledBoard;

        FillResult(char[] board, char target, char replacement, List<Integer> seeds) {
            Stack<Integer> nodes = new Stack<>();
            nodesFilled = new HashSet<>();
            edges = new HashSet<>();

            if (seeds == null)
                nodes.push(180);
            else
                for (int i : seeds)
                    nodes.push(i);

            filledBoard = new char[361];
            System.arraycopy(board, 0, filledBoard, 0, 361);

            while (!nodes.empty()) {
                int n = nodes.pop();
                if (n < 0 || n > 360)
                    continue;
                if (filledBoard[n] == target) {
                    filledBoard[n] = replacement;
                    nodesFilled.add(n);
                    if (n % 19 > 0)
                        nodes.push(n - 1);
                    if (n % 19 < 18)
                        nodes.push(n + 1);
                    if (n / 19 > 0)
                        nodes.push(n - 19);
                    if (n / 19 < 18)
                        nodes.push(n + 19);
                } else
                    edges.add(n);
            }
        }
    }
}

সম্পাদনা: আমি একটি যাচাইকারী লিখেছি, বিনামূল্যে নির্দ্বিধায় লিখুন, এটি আপনার প্রোগ্রামের ফলাফলগুলি এবং বন্যারতম ফাইলের ধাপগুলি অন্তর্ভুক্ত করে একটি steps.txt ফাইলের প্রত্যাশা করে: সম্পাদনা-সম্পাদনা: (ওপি দেখুন)

যদি কারও সমস্যা মনে হয় তবে দয়া করে তা আমাকে জানান!


সুন্দর, পিজ্জা! এবং যে যাচাইকারী সত্যিই একটি স্মার্ট এক! ওপিকে এই জাতীয় নিয়ন্ত্রণ সিস্টেমের মতো কিছু তৈরি করা উচিত ছিল (এটি অনেক সমস্যার সমাধান করতে পারে)।
হার্জান

3

সি - 2,480,714 পদক্ষেপ

এখনও অনুকূল নয়, তবে এটি এখন দ্রুত এবং স্কোরগুলি আরও ভাল।

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6];

bool loadmap(FILE *fp)
{
    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int main()
{
    char c, best;
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;

    while (loadmap(fp)) {
        do {
            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);
            if (reachsum[map[9][9] - '1'] == 361)
                break;

            memset(totalsum, 0, sizeof totalsum);
            calctotal();

            reachsum[map[9][9] - '1'] = 0;
            for (best = 0, c = 0; c < 6; c++) {
                if (!reachsum[c])
                    continue;
                if (reachsum[c] == totalsum[c]) {
                    best = c;
                    break;
                } else if (reachsum[c] > reachsum[best]) {
                    best = c;
                }
            }

            apply(best + '1');
        } while (++steps);
    }

    fclose(fp);

    printf("steps: %zu\n", steps);
    return 0;
}

উইলিম ভাল লাগল, আপনার বর্ণনায় আমাকে উল্লেখ করার জন্য ধন্যবাদ। আপনার অনুগ্রহে আমি সম্মানিত।
হার্জান

কোনও সমস্যা নেই, প্রিয় হার্জান
স্টিলটার্মাইট

যাইহোক, আপনার বক্তব্য "এটি হার্জানের তুলনায় তুলনামূলকভাবে ভাল স্কোর" ইতিমধ্যে পুরানো, আমি যেখানেই কথা বললাম সেই উন্নতিটি প্রয়োগ করেছি (মেইলে);) ভাগ্য এখন আমাকে মারছে!
হার্জান

1
আপনার তুলনায় ৫৫৫ ধাপ এগিয়ে, কখনও তুলনা করে একটি '=' যোগ / অপসারণের কথা শুনেছেন, হিহেহে
হেরজান

আসলে, হার্জান। আপনার পরামর্শ অনুযায়ী আমি আমার জমা আপডেট করব update
স্টিলটার্মাইট

3

জাভা - 2,245,529 2,201,995 পদক্ষেপ

"দ্বীপপুঞ্জ" এর সংখ্যা হ্রাস করে সমান্তরাল এবং গভীরতার 5 ডিগ্রি গাছের সন্ধান করুন। যেহেতু গভীরতা 4 থেকে গভীরতা 5 পর্যন্ত উন্নতি এত ছোট ছিল, তাই আমি মনে করি না এটির আরও উন্নতি করার কোনও পয়েন্ট আছে। তবে যদি এটির উন্নতির দরকার হয় তবে আমার অন্ত্র অনুভূতিটি বলেছে যে সমস্ত কিছু পুনরায় গণনার পরিবর্তে দ্বীপের সংখ্যা দুটি হিসাবে পৃথক হিসাবে গণনা করে কাজ করতে হবে।

ভেরিফায়ারের ইনপুট ফর্ম্যাটটি না জানা পর্যন্ত বর্তমানে স্টডআউটে আউটপুট।

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class FloodPaint {

    private static final ForkJoinPool FORK_JOIN_POOL = new ForkJoinPool();

    public static void main(String[] arg) throws IOException, InterruptedException, ExecutionException {
        try (BufferedReader reader = new BufferedReader(new FileReader("floodtest"))) {
            int sum = 0;
            State initState = readNextInitState(reader);
            while (initState != null) {
                List<Integer> solution = generateSolution(initState);
                System.out.println(solution);
                sum += solution.size();
                initState = readNextInitState(reader);
            }
            System.out.println(sum);
        }
    }

    private static State readNextInitState(BufferedReader reader) throws IOException {
        int[] initGrid = new int[State.DIM * State.DIM];
        String line = reader.readLine();
        while ((line != null) && line.isEmpty()) {
            line = reader.readLine();
        }
        if (line == null) {
            return null;
        }
        for (int rowNo = 0; rowNo < State.DIM; ++rowNo) {
            for (int colNo = 0; colNo < State.DIM; ++colNo) {
                initGrid[(State.DIM * rowNo) + colNo] = line.charAt(colNo) - '0';
            }
            line = reader.readLine();
        }
        return new State(initGrid);
    }

    private static List<Integer> generateSolution(State initState) throws InterruptedException, ExecutionException {
        List<Integer> solution = new LinkedList<>();
        StateFactory stateFactory = new StateFactory();
        State state = initState;
        while (!state.isSolved()) {
            int num = findGoodNum(state, stateFactory);
            solution.add(num);
            state = state.getNextState(num, stateFactory);
        }
        return solution;
    }

    private static int findGoodNum(State state, StateFactory stateFactory) throws InterruptedException, ExecutionException {
        SolverTask task = new SolverTask(state, stateFactory);
        FORK_JOIN_POOL.invoke(task);
        return task.get();
    }

}

class SolverTask extends RecursiveTask<Integer> {

    private static final int DEPTH = 5;

    private final State state;
    private final StateFactory stateFactory;

    SolverTask(State state, StateFactory stateFactory) {
        this.state = state;
        this.stateFactory = stateFactory;
    }

    @Override
    protected Integer compute() {
        try {
            Map<Integer,AnalyzerTask> tasks = new HashMap<>();
            for (int num = 1; num <= 6; ++num) {
                if (num != state.getCenterNum()) {
                    State nextState = state.getNextState(num, stateFactory);
                    AnalyzerTask task = new AnalyzerTask(nextState, DEPTH - 1, stateFactory);
                    tasks.put(num, task);
                }
            }
            invokeAll(tasks.values());
            int bestValue = Integer.MAX_VALUE;
            int bestNum = -1;
            for (Map.Entry<Integer,AnalyzerTask> taskEntry : tasks.entrySet()) {
                int value = taskEntry.getValue().get();
                if (value < bestValue) {
                    bestValue = value;
                    bestNum = taskEntry.getKey();
                }
            }
            return bestNum;
        } catch (InterruptedException | ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }

}

class AnalyzerTask extends RecursiveTask<Integer> {

    private static final int DEPTH_THRESHOLD = 3;

    private final State state;
    private final int depth;
    private final StateFactory stateFactory;

    AnalyzerTask(State state, int depth, StateFactory stateFactory) {
        this.state = state;
        this.depth = depth;
        this.stateFactory = stateFactory;
    }

    @Override
    protected Integer compute() {
        return (depth < DEPTH_THRESHOLD) ? analyze() : split();
    }

    private int analyze() {
        return analyze(state, depth);
    }

    private int analyze(State state, int depth) {
        if (state.isSolved()) {
            return -depth;
        }
        if (depth == 0) {
            return state.getNumIslands();
        }
        int bestValue = Integer.MAX_VALUE;
        for (int num = 1; num <= 6; ++num) {
            if (num != state.getCenterNum()) {
                State nextState = state.getNextState(num, stateFactory);
                int nextValue = analyze(nextState, depth - 1);
                bestValue = Math.min(bestValue, nextValue);
            }
        }
        return bestValue;
    }

    private int split() {
        try {
            if (state.isSolved()) {
                return -depth;
            }
            Collection<AnalyzerTask> tasks = new ArrayList<>(5);
            for (int num = 1; num <= 6; ++num) {
                State nextState = state.getNextState(num, stateFactory);
                AnalyzerTask task = new AnalyzerTask(nextState, depth - 1, stateFactory);
                tasks.add(task);
            }
            invokeAll(tasks);
            int bestValue = Integer.MAX_VALUE;
            for (AnalyzerTask task : tasks) {
                int nextValue = task.get();
                bestValue = Math.min(bestValue, nextValue);
            }
            return bestValue;
        } catch (InterruptedException | ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }

}

class StateFactory {

    private static final int INIT_CAPACITY = 40000;
    private static final float LOAD_FACTOR = 0.9f;

    private final ReadWriteLock cacheLock = new ReentrantReadWriteLock();
    private final Map<List<Integer>,State> cache = new HashMap<>(INIT_CAPACITY, LOAD_FACTOR);

    State get(int[] grid) {
        List<Integer> stateKey = new IntList(grid);
        State state;
        cacheLock.readLock().lock();
        try {
            state = cache.get(stateKey);
        } finally {
            cacheLock.readLock().unlock();
        }
        if (state == null) {
            cacheLock.writeLock().lock();
            try {
                state = cache.get(stateKey);
                if (state == null) {
                    state = new State(grid);
                    cache.put(stateKey, state);
                }
            } finally {
                cacheLock.writeLock().unlock();
            }
        }
        return state;
    }

}

class State {

    static final int DIM = 19;
    private static final int CENTER_INDEX = ((DIM * DIM) - 1) / 2;

    private final int[] grid;
    private int numIslands;

    State(int[] grid) {
        this.grid = grid;
        numIslands = calcNumIslands(grid);
    }

    private static int calcNumIslands(int[] grid) {
        int numIslands = 0;
        BitSet uncounted = new BitSet(DIM * DIM);
        uncounted.set(0, DIM * DIM);
        int index = -1;
        while (!uncounted.isEmpty()) {
            index = uncounted.nextSetBit(index + 1);
            BitSet island = new BitSet(DIM * DIM);
            generateIsland(grid, index, grid[index], island);
            ++numIslands;
            uncounted.andNot(island);
        }
        return numIslands;
    }

    private static void generateIsland(int[] grid, int index, int num, BitSet island) {
        if ((grid[index] == num) && !island.get(index)) {
            island.set(index);
            if ((index % DIM) > 0) {
                generateIsland(grid, index - 1, num, island);
            }
            if ((index % DIM) < (DIM - 1)) {
                generateIsland(grid, index + 1, num, island);
            }
            if ((index / DIM) > 0) {
                generateIsland(grid, index - DIM, num, island);
            }
            if ((index / DIM) < (DIM - 1)) {
                generateIsland(grid, index + DIM, num, island);
            }
        }
    }

    int getCenterNum() {
        return grid[CENTER_INDEX];
    }

    boolean isSolved() {
        return numIslands == 1;
    }

    int getNumIslands() {
        return numIslands;
    }

    State getNextState(int num, StateFactory stateFactory) {
        int[] nextGrid = grid.clone();
        if (num != getCenterNum()) {
            flood(nextGrid, CENTER_INDEX, getCenterNum(), num);
        }
        State nextState = stateFactory.get(nextGrid);
        return nextState;
    }

    private static void flood(int[] grid, int index, int fromNum, int toNum) {
        if (grid[index] == fromNum) {
            grid[index] = toNum;
            if ((index % 19) > 0) {
                flood(grid, index - 1, fromNum, toNum);
            }
            if ((index % 19) < (DIM - 1)) {
                flood(grid, index + 1, fromNum, toNum);
            }
            if ((index / 19) > 0) {
                flood(grid, index - DIM, fromNum, toNum);
            }
            if ((index / 19) < (DIM - 1)) {
                flood(grid, index + DIM, fromNum, toNum);
            }
        }
    }

}

class IntList extends AbstractList<Integer> implements List<Integer> {

    private final int[] arr;
    private int hashCode = -1;

    IntList(int[] arr) {
        this.arr = arr;
    }

    @Override
    public int size() {
        return arr.length;
    }

    @Override
    public Integer get(int index) {
        return arr[index];
    }

    @Override
    public Integer set(int index, Integer value) {
        int oldValue = arr[index];
        arr[index] = value;
        return oldValue;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof IntList) {
            IntList arg = (IntList) obj;
            return Arrays.equals(arr, arg.arr);
        }
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        if (hashCode == -1) {
            hashCode = 1;
            for (int elem : arr) {
                hashCode = 31 * hashCode + elem;
            }
        }
        return hashCode;
    }

}

চিত্তাকর্ষক, আপনি কি এটি কোনও ফাইলের ধাপগুলি লিখতে পারেন? যাতে আমরা এটি পরীক্ষা করতে পারি?
হার্জান

@ হারজান এটির কোডটি স্বতঃ-যাচাইযোগ্য বলে মনে হচ্ছে। আইস সলভড () দেখুন
বার্ট পিজ্জা

@ বারেন্টপিজা তাই? আমার কোডটি স্ব-যাচাইকরণও হ'ল ... আমি বোঝাতে চাইছি, এটি আমার নিজের কোডের মতোই ভুল হতে পারে।
হার্জান

isSolve () বৈধতার জন্য নয়, এটি সমাপ্তির জন্য। লেখার জন্য হিসাবে - পরবর্তী সংস্করণে করতে হবে।
মিঃব্যাকএন্ড

আমি আগ্রহী যদি কোনও হিউরিস্টিক যে এটি 5 টি ধাপ গভীরতার সাথে অনুসন্ধান করে তবেই 4 এর জন্য পাওয়া পদক্ষেপের সংখ্যা আরও বেশি 24কার্যকর রানটাইমের ফলাফল হতে পারে।
জো জেড।

2

আমার শেষ প্রবেশ: সি - 2,384,020 পদক্ষেপ

এবার একটি 'চেক-অল-সম্ভাবনা' এক ... এই স্কোরটি 3. তারিখে গভীরতার সাথে সেট করা হয় 5 এর গভীরতায় ~ 2.1M পদক্ষেপ দেওয়া উচিত ... খুব স্লোও। গভীরতা 20+ সর্বনিম্ন পরিমাণে পদক্ষেপগুলি দেয় (এটি কেবলমাত্র সমস্ত ম্যাচ এবং সংক্ষিপ্ততম জয় পরীক্ষা করে) ... এটির পদক্ষেপের ন্যূনতম পরিমাণ রয়েছে, যদিও আমি এটি ঘৃণা করি কারণ এটি কেবলমাত্র একটি সামান্য কিছুটা ভাল তবে কার্যকারিতা সাফল্য অর্জন করে। আমি আমার অন্যান্য সি প্রবেশাধিকার পছন্দ, যা এই পোস্টে হয়।

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6], mapCount = 0;
FILE *stepfile;

bool loadmap(FILE *fp)
{
    fprintf(stepfile, "%s", "\n");

    mapCount++;

    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int pown(int x, int y){
    int p = 1;
    for(int i = 0; i < y; i++){
        p = p * x;
    }

    return p;
}

int main()
{
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;
    if(!(stepfile = fopen("steps.txt", "w")))
        return 1;

    const int depth = 5;
    char possibilities[pown(6, depth)][depth];
    int t = 0;
    for(int a = 0; a < 6; a++){
        for(int b = 0; b < 6; b++){
            for(int c = 0; c < 6; c++){
                for(int d = 0; d < 6; d++){
                    for(int e = 0; e < 6; e++){
                        possibilities[t][0] = (char)(a + '1');
                        possibilities[t][1] = (char)(b + '1');
                        possibilities[t][2] = (char)(c + '1');
                        possibilities[t][3] = (char)(d + '1');
                        possibilities[t++][4] = (char)(e + '1');
                    }
                }
            }
        }
    }
    poes:
    while (loadmap(fp)) {
        do {
            char map2[19][19];
            memcpy(map2, map, sizeof(map));

            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);

            int best = 0, index = 0, end = depth;
            for(int i = 0; i < pown(6, depth); i++){
                for(int d = 0; d < end; d++){

                    apply(possibilities[i][d]);

                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);

                    if(reachsum[map[9][9] - '1'] == 361 && d < end){
                        end = d+1;
                        index = i;
                        break;
                    }
                }
                if(end == depth && best < reachsum[map[9][9] - '1']){
                    best = reachsum[map[9][9] - '1'];
                    index = i;
                }

                memcpy(map, map2, sizeof(map2));
                memset(reach, 0, sizeof reach);
                memset(reachsum, 0, sizeof reachsum);
                calcreach(true, 9, 9);
            }

            for(int d = 0; d < end; d++){

                apply(possibilities[index][d]);

                memset(reach, 0, sizeof reach);
                memset(reachsum, 0, sizeof reachsum);
                calcreach(true, 9, 9);

                fprintf(stepfile, "%c", possibilities[index][d]);
                steps++;
            }
            if(reachsum[map[9][9] - '1'] == 361)
                goto poes;
        } while (1);
    }

    fclose(fp);
    fclose(stepfile);

    printf("steps: %zu\n", steps);
    return 0;
}

সি-তে আরও একটি উন্নত এআই লিখেছেন - 2,445,761 পদক্ষেপ

স্টিলটার্মাইটের উপর ভিত্তি করে:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6], mapCount = 0;
FILE *stepfile;

bool loadmap(FILE *fp)
{
    fprintf(stepfile, "%s", "\n");

    if(mapCount % 1000 == 0)
        printf("mapCount = %d\n", mapCount);

    mapCount++;

    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int main()
{
    char c, best, answer;
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;
    if(!(stepfile = fopen("steps.txt", "w")))
            return 1;

    while (loadmap(fp)) {
        do {
            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);
            if (reachsum[map[9][9] - '1'] == 361)
                break;

            memset(totalsum, 0, sizeof totalsum);
            calctotal();

            reachsum[map[9][9] - '1'] = 0;
            for (best = 0, c = 0; c < 6; c++) {
                if (!reachsum[c])
                    continue;
                if (reachsum[c] == totalsum[c]) {
                    best = c;
                    goto outLoop;
                } else if (reachsum[c] > reachsum[best]) {
                    best = c;
                }
            }

            char map2[19][19];
            memcpy(map2, map, sizeof(map));

            int temp = best;
            for(c = 0; c < 6; c++){

                if(c != best){

                    apply(c + '1');

                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);
                    if (reachsum[best] == totalsum[best]) {

                        memcpy(map, map2, sizeof(map2));
                        memset(reach, 0, sizeof reach);
                        memset(reachsum, 0, sizeof reachsum);
                        calcreach(true, 9, 9);

                        if(temp == -1)
                            temp = c;
                        else if(reachsum[c] > reachsum[temp])
                            temp = c;
                    }

                    memcpy(map, map2, sizeof(map2));
                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);
                }
            }

outLoop:    answer = (char)(temp + '1');
            fprintf(stepfile, "%c", answer);
            apply(answer);
        } while (++steps);
    }

    fclose(fp);
    fclose(stepfile);

    printf("steps: %zu\n", steps);
    return 0;
}


আপনার প্রতিটি এন্ট্রি পৃথক উত্তর হিসাবে পোস্ট করা উচিত।
জো জে।

@JoeZ। দুঃখিত, তবে এটি স্প্যামিংয়ের মতো অনুভূত হয়েছে, তাই আমি তাদের একটি উত্তরে জড়ো করার সিদ্ধান্ত নিয়েছি (এটি কেবল সেরা (সবচেয়ে ভাল = এআই পদক্ষেপের সর্বনিম্ন পরিমাণ সহ) গণনা করার পরে গুরুত্বপূর্ণ নয়)। অন্তত আমি যা ভেবেছিলাম তা স্থির করে।
হার্জান

1

জাভা - 2,610,797 4,780,841 পদক্ষেপ

(ফিল-বাগ ঠিক করা, স্কোর এখন নাটকীয়ভাবে খারাপ --_-)

এটি আমার প্রাথমিক রেফারেন্স অ্যালগরিদম জমা, কেবল আঁকা জায়গার প্রান্তগুলিতে স্কোয়ারগুলির একটি হিস্টোগ্রাম তৈরি করে এবং সর্বাধিক সাধারণ রঙযুক্ত পেইন্টগুলি। কয়েক মিনিটের মধ্যে 100k চালায়।

অবশ্যই জিতবে না, তবে এটি অবশ্যই শেষ নয়। আমি বুদ্ধিমান স্টাফ জন্য সম্ভবত অন্য জমা করব। এই অ্যালগরিদমটিকে একটি বিন্দু হিসাবে বিনা দ্বিধায় ব্যবহার করুন।

সম্পূর্ণ আউটপুট জন্য মন্তব্য করা লাইন আন-মন্তব্য। গৃহীত পদক্ষেপের # টি মুদ্রণের জন্য ডিফল্ট।

import java.io.*;
import java.util.*;

public class PainterAI {

    public static void main(String[] args) throws IOException {

        int totalSteps = 0, numSolved = 0;

        char[] board = new char[361];
        Scanner s = new Scanner(new File("floodtest"));
        long startTime = System.nanoTime();
        caseloop: while (s.hasNextLine()) {
            for (int l = 0; l < 19; l++) {
                String line = s.nextLine();
                if (line.isEmpty())
                    continue caseloop;
                System.arraycopy(line.toCharArray(), 0, board, l * 19, 19);
            }

            List<Character> colorsUsed = new ArrayList<>();
            Stack<Integer> nodes = new Stack<>();

            for (;; totalSteps++) {
                char p = board[180];
                int[] occurrences = new int[7];
                nodes.add(180);
                int numToPaint = 0;
                while (!nodes.empty()) {
                    int n = nodes.pop();
                    if (n < 0 || n > 360)
                        continue;
                    if (board[n] == p) {
                        board[n] = 48;
                        numToPaint++;
                        if (n % 19 > 0)
                            nodes.push(n - 1);
                        if(n%19<18)
                            nodes.push(n + 1);
                        if(n/19>0)
                            nodes.push(n - 19);
                        if(n/19<18)
                            nodes.push(n + 19);
                    } else
                        occurrences[board[n] - 48]++;
                }
                if (numToPaint == 361)
                    break;
                char mostFrequent = 0;
                int times = -1;
                for (int i = 1; i < 7; i++)
                    if (occurrences[i] > times) {
                        times = occurrences[i];
                        mostFrequent = (char) (i + 48);
                    }
                for (int i = 0; i < 361; i++)
                    if (board[i] == 48)
                        board[i] = mostFrequent;
                //colorsUsed.add(mostFrequent);
            }
            numSolved++;

            /*String out = "";
            for (Character c : colorsUsed)
                out += c;
            System.out.println(out); //print output*/
        }
        s.close();
        System.out.println("Total steps to solve all cases: " + totalSteps);
        System.out.printf("\nSolved %d test cases in %.2f seconds", numSolved, (System.nanoTime() - startTime) / 1000000000.);
    }
}

860 চরগুলিতে গল্ফগুলি (ফর্ম্যাট করার ক্ষেত্রে নতুন লাইনগুলি অন্তর্ভুক্ত নয়) তবে চেষ্টা করার মতো মনে হলে আরও সঙ্কুচিত হতে পারে:

import java.io.*;import java.util.*;class P{
public static void main(String[]a)throws Exception{int t=0;char[]b=new char[361];
Scanner s=new Scanner(new File("floodtest"));c:while(s.hasNextLine()){
for(int l=0;l<19;l++){String L=s.nextLine();if(L.isEmpty())continue c;
System.arraycopy(L.toCharArray(),0,b,l*19,19);}List<Character>u=new ArrayList<>();
Stack<Integer>q=new Stack<>();for(int[]o=new int[7];;t++){char p=b[180];q.add(180);
int m=0;while(!q.empty()){int n=q.pop();if(n<0|n>360)continue;if(b[n]==p){b[n]=48;m++;
if(n%19>0)q.add(n-1);if(n%19<18)q.add(n+1);if(n/19>0)q.add(n-19);if(n/19<18)
q.add(n+19);}else o[b[n]-48]++;}if(m==361)break;
char f=0;int h=0;for(int i=1;i<7;i++)if(o[i]>h){h=o[i];f=(char)(i+48);}
for(int i=0;i<361;i++)if(b[i]==48)b[i]=f;u.add(f);}String y="";for(char c:u)y+=c;
System.out.println(y);}s.close();System.out.println("Steps: "+t);}}

এটির "অবশ্যই শেষ নয়" এর একমাত্র কারণ হ'ল আমার রেফারেন্স সমাধান জিনিসগুলি প্যাড করার জন্য রয়েছে। এই মুহুর্তে অন্য ব্যক্তিদের জমা দেওয়া সমস্ত ক্ষেত্রে এটি শেষ স্থান: পি
জো জেড

@JoeZ। ঠিক আছে, এটি স্টিলটার্মাইটের সামনে ছিল, তবে তিনি তার উন্নতি করেছিলেন। আমি এটিকে "নিষ্পাপ থেকে পরবর্তী যৌক্তিক পদক্ষেপ" হিসাবে অভিহিত করেছি। আমি যদি উদ্বিগ্ন হয়ে থাকি তবে এটি উদ্বিগ্ন হবে; পি
বার্টপিজা

1

হাস্কেল - 2,475,056 টি পদক্ষেপ

মন্তব্যগুলিতে মিঃব্যাকেন্ডের পরামর্শ অনুসারে অ্যালগরিদম অনুরূপ। পার্থক্যটি হ'ল: তার পরামর্শটি সর্বাধিক ব্যয়ের স্কোয়ারের সস্তারতম সন্ধান করে, আমার প্রতি লোভের সাথে প্রতিটি পদক্ষেপে গ্রাফের উত্সাহকে হ্রাস করে।

import Data.Array
import qualified Data.Map as M
import Data.Word
import Data.List
import Data.Maybe
import Data.Function (on)
import Data.Monoid
import Control.Arrow
import Control.Monad (liftM)
import System.IO
import System.Environment
import Control.Parallel.Strategies
import Control.DeepSeq

type Grid v = Array (Word8,Word8) v

main = do
  (ifn:_) <- getArgs
  hr <- openFile ifn ReadMode
  sp <- liftM parseFile $ hGetContents hr
  let (len,sol) = turns (map solve sp `using` parBuffer 3 (evalList rseq))
  putStrLn $ intercalate "\n" $ map (concatMap show) sol
  putStrLn $ "\n\nTotal turns: " ++ (show len)

turns :: [[a]] -> (Integer,[[a]])
turns l = rl' 0 l where
  rl' c [] = (c,[])
  rl' c (k:r) = let
   s = c + genericLength k
   (s',l') = s `seq` rl' s r
   in (s',k:l')

centrepoint :: Grid v -> (Word8,Word8)
centrepoint g = let
  ((x0,y0),(x1,y1)) = bounds g
  med l h = let t = l + h in t `div` 2 + t `mod` 2
  in (med x0 x1, med y0 y1)

neighbours :: Grid v -> (Word8,Word8) -> [(Word8,Word8)]
neighbours g (x,y) = filter
  (inRange $ bounds g)
  [(x,y+1),(x+1,y),(x,y-1),(x-1,y)]

areas :: Eq v => Grid v -> [[(Word8,Word8)]]
areas g = p $ indices g where
  p [] = []
  p (a:r) = f : p (r \\ f) where
    f = s g [a] []
s g [] _ = []
s g (h:o) v = let
  n = filter (((==) `on` (g !)) h) $ neighbours g h
  in h : s g ((n \\ (o ++ v)) ++ o) (h : v)

applyFill :: Eq v => v -> Grid v -> Grid v
applyFill c g = g // (zip fa $ repeat c) where
  fa = s g [centrepoint g] []

solve g = solve' gr' where
  aa = areas g
  cp = centrepoint g
  ca = head $ head $ filter (elem cp) aa
  gr' = M.fromList $ map (
    \r1 -> (head r1, map head $ filter (
      \r2 -> head r1 /= head r2 &&
        (not $ null $ intersect (concatMap (neighbours g) r1) r2)
     ) aa
    )
   ) aa
  solve' gr
    | null $ tail $ M.keys $ gr = []
    | otherwise = best : solve' ngr where
      djk _ [] = []
      djk v ((n,q):o) = (n,q) : djk (q:v) (
        o ++ zip (repeat (n+1))
        ((gr M.! q) \\ (v ++ map snd o))
       )
      dout = djk [] [(0,ca)]
      din = let
        m = maximum $ map fst dout
        s = filter ((== m) . fst) dout
        in djk [] s
      rc = filter (flip elem (gr M.! ca) . snd) din
      frc = let
        m = minimum $ map fst rc
        in map snd $ filter ((==m) . fst) rc
      msq = concat $ filter (flip elem frc . head) aa
      clr = map (length &&& head) $ group $ sort $ map (g !) msq
      best = snd $ maximumBy (compare `on` fst) clr
      ngr = let
        ssm = filter ((== best) . (g !)) $ map snd rc
        sml = (concatMap (gr M.!) ssm)
        ncl = ((gr M.! ca) ++ sml) \\ (ca : ssm)
        brk = M.insert ca ncl $ M.filterWithKey (\k _ ->
          (not . flip elem ssm) k
         ) gr
        in M.map 
          (\l -> nub $ map (\e -> if e `elem` ssm then ca else e) l)
          brk


parseFile :: String -> [Grid Word8]
parseFile f = map mk $ filter (not . null . head) $ groupBy ((==) `on` null) $
  map (map ((read :: String -> Word8) . (:[]))) $ lines f where
    mk :: [[Word8]] -> Grid Word8
    mk m = let
      w = fromIntegral (length $ head m) - 1
      h = fromIntegral (length m) - 1
      in array ((0,0),(w,h)) [ ((x,y),v) |
        (y,l) <- zip [h,h-1..] m,
        (x,v) <- zip [0..] l
       ]

showGrid :: Grid Word8 -> String
showGrid g = intercalate "\n" l where
  l = map sl $ groupBy ((==) `on` snd) $
    sortBy ((flip (compare `on` snd)) <> (compare `on` fst)) $
    indices g
  sl = intercalate " " . map (show . (g !))

testsolve = do
  hr <- openFile "floodtest" ReadMode
  sp <- liftM (head . parseFile) $ hGetContents hr
  let
   sol = solve sp
   a = snd $ mapAccumL (\g s -> let g' = applyFill s g in (g',g')) sp sol
  sequence_ $ map (\g -> putStrLn (showGrid g) >> putStrLn "\n") a

এটি এখনও চালানো শেষ হয়েছে?
জো জে।

এখনও না, এটি যদি এখনই রাতারাতি চলতে পারি তবে এটি এখনই শেষ হয়ে গেছে, তবে ফ্যানটি গোলমাল করেছে তাই আমি কম্পিউটারটি হাইবারনেটেড করেছিলাম। এটি এখন আবার চলছে, আমি কাজ থেকে বাড়ি ফিরলে আবার যাচাই করবে।
জেরেমি তালিকা

এটি স্ট্যাক ওভারফ্লোর কারণে ক্র্যাশ হয়ে গেছে, এটি এড়াতে এখনই পরিবর্তন করে।
জেরেমি তালিকা

1

সি # - 2,383,569

এটি সম্ভাব্য সমাধানগুলির গভীরতার পথের পথ যা মোটামুটি সেরা উন্নতির পথটি বেছে নেয় (হিরজনের সি প্রবেশের সমান / অনুরূপ), হেরজান একই নম্বর পোস্ট করার পরে আমি চতুরতার সাথে প্রার্থী সমাধান প্রজন্মের ক্রমটিকে বিপরীত করেছি । যদিও চালাতে 12+ ঘন্টা ভাল সময় লাগে।

class Solver
{
    static void Main()
    {
        int depth = 3;
        string text = File.ReadAllText(@"C:\TEMP\floodtest.txt");
        text = text.Replace("\n\n", ".").Replace("\n", "");
        int count = 0;
        string[] tests = text.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
        for (int i = 0; i < tests.Length; i++)
        {
            Solver s = new Solver(tests[i]);
            string k1 = s.solve(depth);
            count += k1.Length;
            Console.WriteLine(((100 * i) / tests.Length) + " " + i + " " + k1.Length + " " + count + " " + k1);
        }
        Console.WriteLine(count);
    }

    public readonly int MAX_DIM;
    public char[] board;
    public Solver(string prob)
    {
        board = read(prob);
        MAX_DIM = (int)Math.Sqrt(board.Length);
    }

    public string solve(int d)
    {
        var sol = "";
        while (score(eval(copy(board), sol)) != board.Length)
        {
            char[] b = copy(board);
            eval(b, sol);

            var canidates = new List<string>();
            buildCanidates("", canidates, d);
            var best = canidates.Select(c => new {score = score(eval(copy(b), c)), sol = c}).ToList().OrderByDescending(t=>t.score).ThenBy(v => v.sol.Length).First();
            sol = sol + best.sol[0];
        }
        return sol;
    }

    public void buildCanidates(string b, List<string> r, int d)
    {
        if(b.Length>0)
            r.Add(b);
        if (d > 0)
        {
            r.Add(b);
            for (char i = '6'; i >= '1'; i--)
                if(b.Length == 0 || b[b.Length-1] != i)
                    buildCanidates(b + i, r, d - 1);
        }
    }

    public char[] read(string s)
    {
        return s.Where(c => c >= '0' && c <= '9').ToArray();
    }

    public void print(char[] b)
    {
        for (int i = 0; i < MAX_DIM; i++)
        {
            for(int j=0; j<MAX_DIM; j++)
                Console.Write(b[i*MAX_DIM+j]);
            Console.WriteLine();
        }
        Console.WriteLine();
    }

    public char[] copy(char[] b)
    {
        char[] n = new char[b.Length];
        for (int i = 0; i < b.Length; i++)
            n[i] = b[i];
        return n;
    }

    public char[] eval(char[] b, string sol)
    {
        foreach (char c in sol)
            eval(b, c);
        return b;
    }

    public void eval(char[] b, char c)
    {
        foreach (var l in flood(b))
            b[l] = c;
    }

    public int score(char[] b)
    {
        return flood(b).Count;
    }

    public List<int> flood(char[] b)
    {
        int start = (MAX_DIM * (MAX_DIM / 2)) + (MAX_DIM / 2);
        var check = new List<int>(MAX_DIM * MAX_DIM);
        bool[] seen = new bool[b.Length];
        var hits = new List<int>(MAX_DIM*MAX_DIM);

        check.Add(start);
        seen[start]=true;
        char target = b[start];

        int at = 0;
        while (at<check.Count)
        {
            int toCheck = check[at++];
            if (b[toCheck] == target)
            {
                addNeighbors(check, seen, toCheck);
                hits.Add(toCheck);
            }
        }
        return hits;
    }

    public void addNeighbors(List<int> check, bool[] seen, int loc)
    {
        int x = loc / MAX_DIM;
        int y = loc % MAX_DIM;
        addNeighbor(check, seen, x, y - 1);
        addNeighbor(check, seen, x, y + 1);
        addNeighbor(check, seen, x - 1, y);
        addNeighbor(check, seen, x + 1, y);
    }

    public void addNeighbor(List<int> check, bool[] seen, int x, int y)
    {
        if (x >= 0 && x < MAX_DIM && y >= 0 && y < MAX_DIM)
        {
            int l = (x * MAX_DIM) + y;
            if (!seen[l])
            {
                seen[l] = true;
                check.Add(l);
            }
        }
    }
}

1

জাভা - 2,403,189

BUILD SUCCESSFUL (total time: 220 minutes 15 seconds)

এটি একটি নিষ্ঠুর বাহিনীর আমার প্রচেষ্টা বলে মনে করা হয়েছিল। কিন্ত! আমার একক-গভীরতার "সেরা" পছন্দটি প্রথম প্রয়োগ হয়েছে:

2,589,328 - BUILD SUCCESSFUL (total time: 3 minutes 11 seconds)

উভয়ের জন্য ব্যবহৃত কোডটি একইসাথে অন্যান্য সম্ভাব্য পদক্ষেপগুলির "স্ন্যাপশট" সঞ্চয় করে এবং এগুলির সমস্তটির উপরে অ্যালগরিদম চালিয়ে ব্রুট ফোর্সের সাথে একই।


  • সমস্যা

"মাল্টি" পাসের সাথে চলতে থাকলে এলোমেলো ব্যর্থতা দেখা দেয়। আমি ইউনিট পরীক্ষায় প্রথম 100 ধাঁধা এন্ট্রি সেটআপ করি এবং 100% সময় অর্জন করতে পারি তবে 100% সময় অর্জন করতে পারি না। ক্ষতিপূরণ দেওয়ার জন্য, আমি ব্যর্থ সময়ে স্রেফ বর্তমান ধাঁধা নম্বরটি সন্ধান করেছি এবং যেখানে সর্বশেষটি ছেড়ে গেছে সেখানে একটি নতুন থ্রেড পিকিং শুরু করলাম। প্রতিটি থ্রেড একটি ফাইল তাদের নিজ নিজ ফলাফল লিখেছে। ফাইল পুলটি তখন একটি ফাইলে কনডেন্স করা হয়েছিল।

  • অভিগমন

Nodeবোর্ডের টাইল / স্কোয়ার উপস্থাপন করে এবং এর সমস্ত প্রতিবেশীর একটি রেফারেন্স সঞ্চয় করে। তিন ট্র্যাক Set<Node>ভেরিয়েবল: Remaining, Painted, Targets। প্রতিটি পুনরাবৃত্তি Targetsসমস্ত গোষ্ঠী তাকানcandidatetarget value প্রভাবিত নোডকে "আক্রান্ত" নোডের সংখ্যা দ্বারা নির্বাচন করে মান অনুসারে করে। এই প্রভাবিত নোডগুলি পরের পুনরাবৃত্তির জন্য টার্গেটে পরিণত হয়।

উত্সটি অনেকগুলি ক্লাসে ছড়িয়ে আছে এবং স্নিপেটগুলি পুরো প্রসঙ্গে খুব সার্থক নয়। আমার উত্সটি গিটহাবের মাধ্যমে ব্রাউজ করা যায় । আমি জেএসফিডেলের সাথেও গোলমাল করেছি ভিজ্যুয়ালাইজেশনের জন্য ডেমো ।

তবুও, আমার ওয়ার্কহর্স পদ্ধতি থেকে Solver.java:

public void flood() {

 final Data data = new Data();
 consolidateCandidates(data, targets);

 input.add(data.getTarget());

 if(input.size() > SolutionRepository.getInstance().getThreshold()){
  //System.out.println("Exceeded threshold: " + input.toString());
  cancelled = true;
 }
 paintable.addAll(data.targets());
 remaining.removeAll(data.targets());

 if(!data.targets().isEmpty()){
  targets = data.potentialTargets(data.targets(), paintable);

  data.setPaintable(paintable);
  data.setRemaining(remaining);
  data.setInput(input);

  SolutionRepository.getInstance().addSnapshot(data, input);
 }
}

1

সি # - 2,196,462 2,155,834

এটি আমার অন্যান্য সমাধানকারী হিসাবে কার্যকরভাবে 'সেরা বংশধরদের অনুসন্ধান করুন' পদ্ধতির মতো, তবে কয়েকটি অপ্টিমাইজেশনের সাহায্যে যে সবেমাত্র, সমান্তরালতার সাথে, এটি 10 ​​ঘন্টার নিচে সামান্য 5 নম্বরে যেতে দেয়। এটি পরীক্ষার সময় আমি মূলতে একটি বাগও পেয়েছি, যেমন অ্যালগোরিদম মাঝে মাঝে শেষের রাজ্যে অকার্যকর পথগুলি নিয়ে যায় (এটি স্কোর = 64৪ সহ রাজ্যের গভীরতার জন্য অ্যাকাউন্টিং ছিল না; গভীরতার ফলাফলের সাথে টোয়িংয়ের সময় আবিষ্কার করা হয়েছিল) = 7)।

এটির পূর্ববর্তী সলভারের মধ্যে প্রধান পার্থক্য হ'ল এটি বন্যার গেমের রাজ্যগুলিকে স্মৃতিতে রাখে, সুতরাং এটি 6 ^ 5 টি রাজ্যকে পুনরায় তৈরি করতে হবে না। চলমান চলাকালীন সিপিইউ ব্যবহারের ভিত্তিতে, আমি মোটামুটি নিশ্চিত যে এটি সিপিইউ থেকে আবদ্ধ মেমরি ব্যান্ডউইথ বাউন্ডে চলে গেছে। মহা আনন্দ. অনেক পাপ।

সম্পাদনা: কারণগুলির কারণে, গভীরতা 5 অ্যালগরিদম সর্বদা সেরা ফলাফল দেয় না। পারফরম্যান্স উন্নত করতে, আসুন আমরা গভীরতা 5 ... এবং 4 ... এবং 3 এবং 2 এবং 1 এ করি এবং যা সেরা তা দেখুন। 40k এর অন্য চালগুলি ছাঁটাই করে দিয়েছে। যেহেতু গভীরতা 5 সময়ের সর্বাধিক সময়, তাই 4 এর মধ্যে 1 যোগ করা রানটাইমটি 10hrs থেকে 11hrs ডলারে বৃদ্ধি করে। হ্যাঁ!

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    static void Main()
    {
        int depth = 5;
        string text = File.ReadAllText(@"C:\TEMP\floodtest.txt");
        text = text.Replace("\n\n", ".").Replace("\n", "");
        int count = 0;
        string[] tests = text.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);

        Stopwatch start = Stopwatch.StartNew();

        const int parChunk = 16*16;
        for (int i = 0; i < tests.Length; i += parChunk)
        {
            //did not know that parallel select didn't respect order
            string[] sols = tests.Skip(i).Take(parChunk).AsParallel().Select((t, idx) => new { s = new Solver2(t).solve(depth), idx}).ToList().OrderBy(v=>v.idx).Select(v=>v.s).ToArray();
            for (int j = 0; j < sols.Length; j++)
            {
                string k1 = sols[j];
                count += k1.Length;
                int k = i + j;
                int estimate = (int)((count*(long)tests.Length)/(k+1));
                Console.WriteLine(k + "\t" + start.Elapsed.TotalMinutes.ToString("F2") + "\t" + count + "\t" + estimate + "\t" + k1.Length + "\t" + k1);
            }
        }
        Console.WriteLine(count);
    }
}

public class Solver2
{
    public readonly int MAX_DIM;
    public char[] board;
    public Solver2(string prob)
    {
        board = read(prob);
        MAX_DIM = (int)Math.Sqrt(board.Length);
    }

    public string solve(int d)
    {
        string best = null;
        for (int k = d; k >= 1; k--)
        {
            string c = subSolve(k);
            if (best == null || c.Length < best.Length)
                best = c;
        }
        return best;
    }

    public string subSolve(int d)
    {
        State current = new State(copy(board), '\0', flood(board));
        var sol = "";

        while (current.score != board.Length)
        {
            State nextState = subSolve(current, d);
            sol = sol + nextState.key;
            current = nextState;
        }
        return sol;
    }

    public State subSolve(State baseState, int d)
    {
        if (d == 0)
            return baseState;
        if (!baseState.childrenGenerated)
        {
            for (int i = 0; i < baseState.children.Length; i++)
            {
                if (('1' + i) == baseState.key) continue; //no point in even eval'ing
                char[] board = copy(baseState.board);
                foreach(int idx in baseState.flood)
                    board[idx] = (char)('1' + i);
                List<int> f = flood(board);
                if (f.Count != baseState.score)
                    baseState.children[i] = new State(board, (char)('1' + i), f);
            }
            baseState.childrenGenerated = true;
        }
        State bestState = null;

        for (int i = 0; i < baseState.children.Length; i++)
            if (baseState.children[i] != null)
            {
                State bestChild = subSolve(baseState.children[i], d - 1);
                baseState.children[i].bestChildScore = bestChild.bestChildScore;
                if (bestState == null || bestState.bestChildScore < bestChild.bestChildScore)
                    bestState = baseState.children[i];
            }
        if (bestState == null || bestState.bestChildScore == baseState.score)
        {
            if (baseState.score == baseState.board.Length)
                baseState.bestChildScore = baseState.score*(d + 1);
            return baseState;
        }
        return bestState;
    }

    public char[] read(string s)
    {
        return s.Where(c => c >= '1' && c <= '6').ToArray();
    }

    public char[] copy(char[] b)
    {
        char[] n = new char[b.Length];
        for (int i = 0; i < b.Length; i++)
            n[i] = b[i];
        return n;
    }

    public List<int> flood(char[] b)
    {
        int start = (MAX_DIM * (MAX_DIM / 2)) + (MAX_DIM / 2);
        var check = new List<int>(MAX_DIM * MAX_DIM);
        bool[] seen = new bool[b.Length];
        var hits = new List<int>(MAX_DIM * MAX_DIM);

        check.Add(start);
        seen[start] = true;
        char target = b[start];

        int at = 0;
        while (at < check.Count)
        {
            int toCheck = check[at++];
            if (b[toCheck] == target)
            {
                addNeighbors(check, seen, toCheck);
                hits.Add(toCheck);
            }
        }
        return hits;
    }

    public void addNeighbors(List<int> check, bool[] seen, int loc)
    {
        //int x = loc / MAX_DIM;
        int y = loc % MAX_DIM;

        if(loc+MAX_DIM < seen.Length)
            addNeighbor(check, seen, loc+MAX_DIM);
        if(loc-MAX_DIM >= 0)
            addNeighbor(check, seen, loc-MAX_DIM);
        if(y<MAX_DIM-1)
            addNeighbor(check, seen, loc+1);
        if (y > 0)
            addNeighbor(check, seen, loc-1);
    }

    public void addNeighbor(List<int> check, bool[] seen, int l)
    {
        if (!seen[l])
        {
            seen[l] = true;
            check.Add(l);
        }
    }
}

public class State
{
    public readonly char[] board;
    public readonly char key;
    public readonly State[] children = new State[6];
    public readonly List<int> flood; 
    public readonly int score;
    public bool childrenGenerated;
    public int bestChildScore;
    public State(char[] board, char k, List<int> flood)
    {
        this.board = board;
        key = k;
        this.flood = flood;
        score = flood.Count;
        bestChildScore = score;
    }
}

আমি আপনার কোড চেষ্টা করেছি এবং এটি সংকলন করে না। একটি সমাধান পদ্ধতি কলের কাছে একটি ত্রুটি রয়েছে। এর পাশাপাশি, কয়েকটি "ব্যবহার করে" বিবৃতি অনুপস্থিত রয়েছে। যাইহোক, যদি আপনার প্রোগ্রামটি কেবল 2.1M পদক্ষেপগুলিতে সমস্ত কিছু সমাধান করে, অভিনন্দন, এটি বরং চিত্তাকর্ষক।
tigrou

@ টিটিগ্রু বিবৃতি ব্যবহারে আমার কোনও সমস্যা হয়নি; সমাধান কল ত্রুটি সংশোধন করে - এটি পুনরায় (কপি / পেস্ট) -িংয়ের পরিবর্তে কোডটি আপডেট করার চেষ্টা করার থেকে এটি একটি নমুনা ছিল। সেটার জন্য দুঃখিত.
কোডারটাও

blarg। আপনি বোঝাতে চেয়েছিলেন == নেমস্পেস আমদানি। সেটাও ঠিক করা।
কোডারটাও

আপনি 11 ঘন্টা মধ্যে গভীরতার 5 তে সমস্ত বোর্ড সমাধান করতে কোন সিপিইউ ব্যবহার করেন? আমি একটি আই 5 760@2.8Ghz এর অধীনে প্রোগ্রাম পরিচালনা করেছি। এটি 256 বোর্ডের প্রতিটি অংশ আউটপুট দিতে 30 মিনিট সময় নিয়েছিল। এর ভিত্তিতে, 100.000 বোর্ডগুলি সমাধান করতে 8 দিন সময় লাগবে। সিপিইউ সেই সময়ে 80-100% ব্যবহারের মধ্যে বাউন্স করছিল, চারটি কোর ব্যবহৃত হয়েছিল। সম্ভবত পরীক্ষাগুলি চালানোর জন্য কোনও সমস্যা ভার্চুয়ালবক্স মেশিন ব্যবহার করা হয়েছে, তবে এটি আপনার চেয়ে প্রায় 16 গুণ গতি কমিয়ে দেয় (আপনি বলেছিলেন যে এটি 11 ঘন্টা সময় নিয়েছে)।
tigrou

@ টিটিগ্রু আমি একটি আই 5 750@2.67 (3-4 বছরের পুরানো হার্ডওয়্যার) এ চলেছি। ভিএস এর অধীনে, ডিবাগ বনাম রিলিজ মোড একটি 50% পার্থক্য, তবে আমি সন্দেহ করি যে এটি 16x পার্থক্য ব্যাখ্যা করবে। আপনি যদি কোনও লিনাক্স হোস্টের নীচে
ছুটে চলেছেন তবে আপনি মনোর

1

ডেলফি XE3 2,979,145 পদক্ষেপ

ঠিক আছে তাই এটা আমার চেষ্টা। আমি পরিবর্তিত অংশটিকে একটি ব্লব বলি, প্রতিটি পালা এটি অ্যারের একটি অনুলিপি তৈরি করে এবং প্রতিটি রঙের পরীক্ষা করে দেখবে যে কোন রঙটি সবচেয়ে বড় ব্লব দেবে।

3 ঘন্টা 6 মিনিটে সমস্ত ধাঁধা চালায়

program Main;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils,
  Classes,
  Generics.Collections,
  math,
  stopwatch in 'stopwatch.pas';

type
  myArr=array[0..1]of integer;
const
  MaxSize=19;
  puzLoc='here is my file';
var
  L:TList<TList<integer>>;
  puzzles:TStringList;
  sc:TList<myArr>;
  a:array[0..MaxSize-1,0..MaxSize-1] of Integer;
  aTest:array[0..MaxSize-1,0..MaxSize-1] of Integer;
  turns,midCol,sX,sY,i:integer;
  currBlob,biggestBlob,ColorBigBlob:integer;
  sTurn:string='';
  GLC:integer=0;

procedure FillArrays;
var
  ln,x,y:integer;
  puzzle:TStringList;
begin
  sc:=TList<myArr>.Create;
  puzzle:=TStringList.Create;    
  while puzzle.Count<19 do
  begin
    if puzzles[GLC]='' then
    begin
      inc(GLC);
      continue
    end
    else
      puzzle.Add(puzzles[GLC]);
    inc(GLC)
  end;    
  for y:=0to MaxSize-1do
    for x:=0to MaxSize-1do
      a[y][x]:=Ord(puzzle[y][x+1])-48;
  puzzle.Free;
end;
function CreateArr(nx,ny:integer):myArr;
begin
  Result[1]:=nx;
  Result[0]:=ny;
end;

procedure CreateBlob;
var
  tst:myArr;
  n,tx,ty:integer;
  currColor:integer;
begin
  n:=0;
  sc.Clear;
  currColor:=a[sy][sx];
  sc.Add(CreateArr(sx,sy));
  repeat
    tx:=sc[n][1];
    ty:=sc[n][0];
    if tx>0 then
      if a[ty][tx-1]=currColor then
      begin
        tst:=CreateArr(tx-1,ty);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if tx<MaxSize-1 then
      if a[ty][tx+1]=currColor then
      begin
        tst:=CreateArr(tx+1,ty);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if ty>0 then
      if a[ty-1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty-1);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if ty<MaxSize-1 then
      if a[ty+1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty+1);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    inc(n);
  until (n=sc.Count);
end;

function BlobSize:integer;
var
  L:TList<myArr>;
  tst:myArr;
  n,currColor,tx,ty:integer;
begin
  n:=0;
  L:=TList<myArr>.Create;
  currColor:=aTest[sy][sx];
  L.Add(CreateArr(sx,sy));

  repeat
    tx:=L[n][1];
    ty:=L[n][0];
    if tx>0then
      if aTest[ty][tx-1]=currColor then
      begin
        tst:=CreateArr(tx-1,ty);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if tx<MaxSize-1then
      if aTest[ty][tx+1]=currColor then
      begin
        tst:=CreateArr(tx+1,ty);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if ty>0then
      if aTest[ty-1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty-1);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if ty<MaxSize-1then
      if aTest[ty+1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty+1);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    inc(n);
  until n=l.Count;
  Result:=L.Count;
  L.Free;
end;

function AllsameColor(c:integer):boolean;
var
  cy,cx:integer;
begin
  Result:=true;
  for cy:=0to MaxSize-1do
    for cx:=0to MaxSize-1do
      if a[cy][cx]=c then
        continue
      else
        exit(false);
end;
procedure ChangeColors(old,new:integer; testing:boolean=false);
var
  i,j:integer;
  tst:myArr;
begin
  if testing then
  begin
    for i:= 0to MaxSize-1do
      for j:= 0to MaxSize-1do
        aTest[i][j]:=a[i][j];    
    for I:=0to sc.Count-1do
    begin
      tst:=sc[i];
      aTest[tst[0]][tst[1]]:=new;
    end;
  end
  else
  begin
    for I:=0to sc.Count-1do
    begin
      tst:=sc[i];
      a[tst[0]][tst[1]]:=new;
    end;
  end;
end;
var
  sw, swTot:TStopWatch;
  solved:integer=0;
  solutions:TStringList;
  steps:integer;
  st:TDateTime;
begin          
  st:=Now;
  writeln(FormatDateTime('hh:nn:ss',st));
  solutions:=TStringList.Create;
  puzzles:=TStringList.Create;
  puzzles.LoadFromFile(puzLoc);
  swTot:=TStopWatch.Create(true);
  turns:=0;
  repeat
    sTurn:='';    
    FillArrays;
    sX:=Round(Sqrt(MaxSize))+1;
    sY:=sX;    
    repeat
      biggestBlob:=0;
      ColorBigBlob:=0;
      midCol:=a[sy][sx];
      CreateBlob;
      for I:=1to 6do
      begin
        if I=midCol then continue;    
        ChangeColors(midCol,I,true);
        currBlob:=BlobSize;
        if currBlob>biggestBlob then
        begin
          biggestBlob:=currBlob;
          ColorBigBlob:=i;
        end;
      end;
      ChangeColors(midCol,ColorBigBlob);
      inc(turns);
      if sTurn='' then
        sTurn:=IntToStr(ColorBigBlob)
      else
        sTurn:=sTurn+', '+IntToStr(ColorBigBlob);
    until AllsameColor(a[sy][sx]);
    solutions.Add(sTurn);
    inc(solved);
    if solved mod 100=0then
      writeln(Format('Solved %d puzzles || %s',[solved,FormatDateTime('hh:nn:ss',Now-st)]));    
  until GLC>=puzzles.Count-1;    
  swTot.Stop;
  WriteLn(Format('solving these puzzles took %d',[swTot.Elapsed]));
  writeln(Format('Total moves: %d',[turns]));
  solutions.SaveToFile('save solutions here');
  readln;
end.

ব্রুটফোর্স ব্যাকট্র্যাসিং পদ্ধতি সম্পর্কেও ভাবনা।
এই সপ্তাহান্তে জন্য মজা হতে পারে ^^


0

জাভাস্ক্রিপ্ট / নোড.জেএস - 2,588,847

অ্যালগোরিটম তবে এখানে বেশ কিছুটা আলাদা কারণ এটি প্রাক্কলকুলেট অঞ্চলগুলি এবং গণনার মধ্যে পৃথক রাষ্ট্রের ব্যবহার করে। জাভাস্ক্রিপ্টের কারণে আপনি গতি নিয়ে চিন্তিত থাকলে এটি এখানে 10 মিনিটের নিচে চলে।

var fs = require('fs')


var file = fs.readFileSync('floodtest','utf8');
var boards = file.split('\n\n');
var linelength  = boards[0].split('\n')[0].length;
var maxdim = linelength* linelength;


var board = function(info){
    this.info =[];
    this.sameNeighbors = [];
    this.differentNeighbors = [];
    this.samedifferentNeighbors = [];
    for (var i = 0;i <info.length;i++ ){
        this.info.push(info[i]|0);
    };

    this.getSameAndDifferentNeighbors();
}

board.prototype.getSameAndDifferentNeighbors = function(){
    var self = this;
    var info = self.info;
    function getSameNeighbors(i,value,sameneighbors,diffneighbors){

        var neighbors = self.getNeighbors(i);
        for(var j =0,nl = neighbors.length; j< nl;j++){
            var index = neighbors[j];
            if (info[index]  === value ){
                if( sameneighbors.indexOf(index) === -1){
                    sameneighbors.push(index);
                    getSameNeighbors(index,value,sameneighbors,diffneighbors);
                }
            }else if( diffneighbors.indexOf(index) === -1){
                    diffneighbors.push(index);
            }
        } 

    }


    var sneighbors = [];
    var dneighbors = [];
    var sdneighbors = [];

    for(var i= 0,l= maxdim;i<l;i++){
        if (sneighbors[i] === undefined){
            var sameneighbors = [i];
            var diffneighbors = [];
            getSameNeighbors(i,info[i],sameneighbors,diffneighbors);
            for (var j = 0; j<sameneighbors.length;j++){
                var k = sameneighbors[j];
                sneighbors[k] = sameneighbors;
                dneighbors[k] = diffneighbors;
            } 
        }

    }

    for(var i= 0,l= maxdim;i<l;i++){
        if (sdneighbors[i] === undefined){
            var value = [];
            var dni = dneighbors[i];
            for (var j = 0,dnil = dni.length; j<dnil;j++){
                var dnij = dni[j];
                var sdnij = sneighbors[dnij];
                for(var k = 0,sdnijl = sdnij.length;k<sdnijl;k++){
                    if (value.indexOf(sdnij[k])=== -1){
                        value.push(sdnij[k]);
                    }
                }
            };
            var sni = sneighbors[i];
            for (var j=0,snil = sni.length;j<snil;j++){
                sdneighbors[sni[j]] = value;
            };
        };
    }
    this.sameNeighbors = sneighbors;
    this.differentNeighbors =  dneighbors;
    this.samedifferentNeighbors =sdneighbors;

}

board.prototype.getNeighbors = function(i){
        var returnValue = [];

        var index = i-linelength;
        if (index >= 0){
            returnValue.push(index);
        }

        index = i+linelength;
        if (index < maxdim){

            returnValue.push(index);
        }

        index = i-1;

        if (index >= 0 && index/linelength >>> 0 === i/linelength  >>> 0){
            returnValue.push(index);
        }
        index = i+1;
        if (index/linelength >>> 0 === i/linelength >>> 0){
            returnValue.push(index);
        }

        if (returnValue.indexOf(-1) !== -1){
            console.log(i,parseInt(index/linelength,10),parseInt(i/linelength,10));
        } 
        return returnValue 
}

board.prototype.solve = function(){
    var i,j;
    var info = this.info;
    var sameNeighbors = this.sameNeighbors;
    var samedifferentNeighbors = this.samedifferentNeighbors;
    var middle = 9*19+9;
    var maxValues = [];

    var done = {};
    for (i=0; i<sameNeighbors[middle].length;i++){
        done[sameNeighbors[middle][i]] = true;
    }
    var usefullNeighbors = [[],[],[],[],[],[],[]];
    var diff = [];
    var count = [0];

    count[1] = 0;
    count[2] = 0;
    count[3] = 0;
    count[4] = 0;
    count[5] = 0;
    count[6] = 0;

    var addusefullNeighbors = function(index,diff){

        var indexsamedifferentNeighbors =samedifferentNeighbors[index];
        for (var i=0;i < indexsamedifferentNeighbors.length;i++){
            var is = indexsamedifferentNeighbors[i];
            var value = info[is];
            if (done[is] === undefined && usefullNeighbors[value].indexOf(is) === -1){
                usefullNeighbors[value].push(is);
                diff.push(value);
            }

        }
    }
    addusefullNeighbors(middle,diff);


    while(  usefullNeighbors[1].length > 0 || usefullNeighbors[2].length > 0 ||
            usefullNeighbors[3].length > 0 || usefullNeighbors[4].length > 0 ||
            usefullNeighbors[5].length > 0 || usefullNeighbors[6].length > 0 ){
        for (i=0;i < diff.length;i++){ 
            count[diff[i]]++;
        };
        var maxValue = count.indexOf(Math.max.apply(null, count));
        diff.length = 0;
        var used = usefullNeighbors[maxValue];
        for (var i=0,ul = used.length;i < ul;i++){
            var index = used[i];
            if (info[index] === maxValue){
                done[index] = true;
                addusefullNeighbors(index,diff);
            }
        }
        used.length = 0;
        count[maxValue] = 0;


        maxValues.push(maxValue);
    }
    return maxValues.join("");
};
var solved = [];
var start = Date.now();
for (var boardindex =0;boardindex < boards.length;boardindex++){ 
    var b = boards[boardindex].replace(/\n/g,'').split('');
    var board2 = new board(b);
    solved.push(board2.solve());
};
var diff = Date.now()-start;
console.log(diff,boards.length);
console.log(solved.join('').length);
console.log("end");

fs.writeFileSync('solution.txt',solved.join('\n'),'utf8');

-3

সি কোড যা সাধারণ ব্রুট ফোর্সের মাধ্যমে অনুকূল সমাধান সন্ধানের গ্যারান্টিযুক্ত। স্বেচ্ছাসেবী আকারের গ্রিড এবং সমস্ত ইনপুটগুলির জন্য কাজ করে। বেশিরভাগ গ্রিডে চলতে খুব, খুব দীর্ঘ সময় লাগে।

বন্যার ভরাট চূড়ান্তভাবে অদক্ষ এবং পুনরাবৃত্তির উপর নির্ভর করে। আপনার স্ট্যাকটি খুব ছোট হলে আরও বড় করা দরকার make ব্রুট ফোর্স সিস্টেমটি সমস্ত সম্ভাব্য বিকল্পের মধ্য দিয়ে সংখ্যাগুলি ধরে রাখার জন্য স্ট্রিং এবং সহজ-বহন করে চালায় uses এটি চূড়ান্তভাবে বহু পদক্ষেপের পুনরাবৃত্তি করায় এটিও অত্যন্ত অদক্ষ fficient

দুর্ভাগ্যক্রমে আমি সমস্ত পরীক্ষার মামলার বিরুদ্ধে এটি পরীক্ষা করতে পারিনি, যেহেতু আমি এটি শেষ হওয়ার আগেই বার্ধক্যে মরে যাব।

#include <stdio.h>
#include <string.h>


#define GRID_SIZE       19

char grid[GRID_SIZE][GRID_SIZE] = { {3,3,5,4,1,3,4,1,5,3,3,5,4,1,3,4,1,5},
                                    {5,1,3,4,1,1,5,2,1,3,3,5,4,1,3,4,1,5},
                                    {6,5,2,3,4,3,3,4,3,3,3,5,4,1,3,4,1,5},
                                    {4,4,4,5,5,5,4,1,4,3,3,5,4,1,3,4,1,5},
                                    {6,2,5,3,3,1,1,6,6,3,3,5,4,1,3,4,1,5},
                                    {5,5,1,2,5,2,6,6,3,3,3,5,4,1,3,4,1,5},
                                    {6,1,1,5,3,6,2,3,6,3,3,5,4,1,3,4,1,5},
                                    {1,2,2,4,5,3,5,1,2,3,3,5,4,1,3,4,1,5},
                                    {3,6,6,1,5,1,3,2,4,3,3,5,4,1,3,4,1,5} };
char grid_save[GRID_SIZE][GRID_SIZE];

char test_grids[6][GRID_SIZE][GRID_SIZE];

void flood_fill(char x, char y, char old_colour, char new_colour)
{
    if (grid[y][x] == new_colour)
        return;

    grid[y][x] = new_colour;

    if (y > 0)
    {
        if (grid[y-1][x] == old_colour)
            flood_fill(x, y-1, old_colour, new_colour);
    }
    if (y < GRID_SIZE - 1)
    {
        if (grid[y+1][x] == old_colour)
            flood_fill(x, y+1, old_colour, new_colour);
    }

    if (x > 0)
    {
        if (grid[y][x-1] == old_colour)
            flood_fill(x-1, y, old_colour, new_colour);
    }
    if (x < GRID_SIZE - 1)
    {
        if (grid[y][x+1] == old_colour)
            flood_fill(x+1, y, old_colour, new_colour);
    }
}

bool check_grid(void)
{
    for (char i = 0; i < 6; i++)
    {
        if (!memcmp(grid, &test_grids[i][0][0], sizeof(grid)))
            return(true);
    }

    return(false);
}

void inc_string_num(char *s)
{
    char *c;

    c = s + strlen(s) - 1;
    *c += 1;

    // carry
    while (*c > '6')
    {
        *c = '1';
        if (c == s) // first char
        {
            strcat(s, "1");
            return;
        }
        c--;
        *c += 1;
    }
}

void print_grid(void)
{
    char x, y;
    for (y = 0; y < GRID_SIZE; y++)
    {
        for (x = 0; x < GRID_SIZE; x++)
            printf("%d ", grid[y][x]);
        printf("\n");
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    // create test grids for comparisons
    for (char i = 0; i < 6; i++)
        memset(&test_grids[i][0][0], i+1, GRID_SIZE*GRID_SIZE);

    char s[256] = "0";
    //char s[256] = "123456123456123455";
    memcpy(grid_save, grid, sizeof(grid));


    print_grid();
    do
    {
        memcpy(grid, grid_save, sizeof(grid));
        inc_string_num(s);

        for (unsigned int i = 0; i < strlen(s); i++)
        {
            flood_fill(4, 4, grid[4][4], s[i] - '0');
        }
    } while(!check_grid());
    print_grid();

    printf("%s\n", s);

    return 0;
}

আমি যতদূর বলতে পারি এটি বর্তমান বিজয়ী। প্রতিযোগিতার জন্য যে প্রয়োজন:

আপনার প্রোগ্রামটি সম্পূর্ণরূপে নির্বিচারক হওয়া উচিত; সিউডোর্যান্ডম সমাধানগুলি অনুমোদিত, তবে প্রোগ্রামটি অবশ্যই প্রতিবার একই পরীক্ষার ক্ষেত্রে একই আউটপুট উত্পন্ন করতে হবে।

চেক

বিজয়ী প্রোগ্রামটি এই ফাইলটিতে পাওয়া সমস্ত 100,000 পরীক্ষার কেস সমাধানের জন্য সর্বনিম্ন মোট পদক্ষেপ গ্রহণ করবে (জিপযুক্ত টেক্সট ফাইল, 14.23 এমবি)। যদি দুটি সমাধান একই সংখ্যক পদক্ষেপ নেয় (উদাহরণস্বরূপ যদি তারা উভয়ই অনুকূল কৌশলটি খুঁজে পেয়ে থাকে), তবে সংক্ষিপ্ত প্রোগ্রামটি জয়ী হবে।

যেহেতু এটি সর্বদা প্রতিটি বোর্ড সম্পূর্ণ করার জন্য সর্বনিম্ন সংখ্যার পদক্ষেপ খুঁজে পায় এবং অন্যরা কেউই তা করে না, এটি বর্তমানে এগিয়ে। যদি কেউ সংক্ষিপ্ততর প্রোগ্রাম নিয়ে আসতে পারে তবে তারা জিততে পারে, তাই আমি নীচের আকারের অনুকূলিত সংস্করণটি উপস্থাপন করি। মৃত্যুদন্ড কার্যকর করা কিছুটা ধীর, তবে মৃত্যুদন্ড কার্যকর করার সময়টি বিজয়ী অবস্থার অংশ নয়:

#include <stdio.h>
#include <string.h>
#define A 9
int g[A][A]={{3,3,5,4,1,3,4,1,5},{5,1,3,4,1,1,5,2,1},{6,5,2,3,4,3,3,4,3},{4,4,4,5,5,5,4,1,4},{6,2,5,3,3,1,1,6,6},{5,5,1,2,5,2,6,6,3},{6,1,1,5,3,6,2,3,6},{1,2,2,4,5,3,5,1,2},{3,6,6,1,5,1,3,2,4}};
int s[A][A];
int t[6][A][A];
void ff(int x,int y,int o,int n)
{if (g[y][x]==n)return;g[y][x]=n;if (y>0){if(g[y-1][x]==o)ff(x,y-1,o,n);}if(y<A-1){if(g[y+1][x]==o)ff(x,y+1,o,n);}if(x>0){if (g[y][x-1] == o)ff(x-1,y,o,n);}if(x<A-1){if(g[y][x+1]==o)ff(x+1,y,o,n);}}
bool check_g(void)
{for(int i=0;i<6;i++){if(!memcmp(g,&t[i][0][0],sizeof(g)))return(true);}return(0);}
void is(char*s){char*c;c=s+strlen(s)-1;*c+=1;while(*c>'6'){*c='1';if (c==s){strcat(s,"1");return;}c--;*c+=1;}}
void pr(void)
{int x, y;for(y=0;y<A;y++){for(x=0;x<A;x++)printf("%d ",g[y][x]);printf("\n");}printf("\n");}
int main(void)
{for(int i=0;i<6;i++)memset(&t[i][0][0],i+1,A*A);char s[256]="0";memcpy(s,g,sizeof(g));pr();do{memcpy(g,s,sizeof(g));is(s);for(int i=0;i<strlen(s);i++){ff(4,4,g[4][4],s[i]-'0');}}while(!check_g());
pr();printf("%s\n",s);return 0;}

এখন পর্যন্ত এটিই একমাত্র এন্ট্রি যা প্রতিবার সর্বাধিক অনুকূল সমাধান পায়। আমি যুক্তি দিয়েছি এটি একটি ভাল শেষ-স্থানের রেফারেন্স সমাধানও। প্রকৃতপক্ষে, আমি নিশ্চিত নই যে প্রকৃতপক্ষে আরও ভাল উপায় আছে যা প্রতিটি ক্ষেত্রেই অনুকূল সমাধান পাওয়ার গ্যারান্টি দেয় এবং এখনও অবধি অন্য কেউ প্রমাণিত হয়নি।
ব্যবহারকারী 15

1
যতক্ষণ না আপনি আসলে পদক্ষেপ সঠিক সংখ্যা এটি নিতে হবে জানতে পারেন, আমি এই সমাধান গ্রহণ করতে পারে না যদিও তা হয় (তাত্ত্বিকভাবে) সেরা এক।
জো জে।

এছাড়াও, গ্রিডের আকার 19 নয়, 9
জো জে।

ঠিক আছে, আমি গ্রিডের আকার ঠিক করেছি। কেউ কীভাবে প্রয়োজনীয় তাত্ত্বিক ন্যূনতম পদক্ষেপের গণনা করতে জানেন?
ব্যবহারকারী

নাঃ। এর সমাধানের জন্য আপনাকে একটি প্রোগ্রাম ব্যবহার করতে হবে, যা আপনার এখনই রয়েছে।
জো জেড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.