代碼是這樣的,你輸入一個組合和另一個組合,這是你想要的組合,例如:
[
前兩行是組合,后兩行是所需的組合,第五行是所需的最小棋步數,然后程式會顯示得到該組合所需的最小棋步數,但現在我需要通過終端使程式作業,這樣一個檔案被傳入input. txt,然后結果將被保存為output.txt,并且可以從終端運行app.exe input.txt output.txt,現在代碼作業正常,但找到一個從檔案中讀取輸入的方法是有問題的
#include <iostream>
#include <fstream>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
struct State {
char a[2][4] 。
static State read() {
狀態s。
for (int i = 0; i < 2; i) {
for (int j = 0; j < 4; j) {
cin >> s.a[i][j]。
}
}
return s;
}
State shift(int di, int dj) const{
State next = *this;
for (int i = 0; i < 2; i) {
for (int j = 0; j < 4; j) {
if (next.a[i][j] == '#'/span>) {
int ni = di i;
int nj = dj j;
if (ni >= 0 & & ni < 2 & & nj >= 0 & & nj < 4) {
swap(next.a[i][j], next.a[ni][nj])。
}
return next;
}
}
}
}
};
int compare(const State& left, const State& rigth) {
for (int i = 0; i < 2; i) {
for (int j = 0; j < 4; j) {
if (left.a[i][j] != rigth.a[i][j] ) {
return left.a[i][j] - rigth.a[i][j] 。
}
}
}
return 0;
}
bool operator < (const State& left, const State& rigth) {
return compare(left, rigth) < 0;
}
bool operator ==(const State& left, const State& rigth) {
return compare(left, rigth) == 0;
}
int main(int argc, char** argv)
{
if (argc < 3) {
perror("not enough arguments")。
return 1;
}
string filename("input.txt")。
向量<char> bytes;
FILE* input_file = fopen(filename.c_str(), "r") 。
if (input_file == nullptr) {
return EXIT_FAILURE。
}
unsigned char character = 0;
while (!feof(input_file)) {
character = getc(input_file)。
cout << character << "-"/span>;
}
State start = State::read()。
State finish = State::read();
map<State, int> len;
queue<State> q;
len[start] = 0;
q.push(start)。
while (!q.empty() } {
State cur = q.front()。
q.pop()。
if (cur == finish) {
cout << len[cur];
return 0;
}
for (int i = -1; i < 2; i) {
for (int j = -1; j < 2; j) {
if (i * i j * j == 1) {
State next = cur.shift(i, j)。
if (len.count(Next) == 0) {
len[next] = len[cur] 1;
q.push(next)。
}
}
}
}
}
cout << -1;
}
uj5u.com熱心網友回復:
你需要閱讀并理解C iostream設施。請研究它們。
在那里你可以讀到提取運算子>>和插入運算子<<。
而你需要做的,是為你的類重寫提取運算子,并使用它來代替你的 "讀取 "函式。
因為提取運算子對所有的istreams和childs起作用,你基本上可以從所有的東西中讀取。
取自這里。在那里你可以看到,像std::cin這樣的istream或檔案流甚至是字串流之間基本上沒有區別。
因此,如果你已經為你的類State覆寫了提取運算子,那么你可以寫
State state。
std::cin >> state。
/or, if you have an std::ifstream ifs
ifs >> 狀態。
以此類推。你會理解這種模式。你可以在下面的代碼示例中看到一個實作的例子。
我很難理解你對原始問題的描述。它被描述得相當隱晦。基本上,你有一個帶有符號的游戲板,其中一個區域是空的。然后你可以將一個符號轉移到這個空閑區域。這意味著將符號與空場交換。目標是,通過許多步驟的轉移/交換,達到一個給定的目標模式。
此外,你在你的代碼中做了一些奇怪或復雜的實作。
而且,沒有一行注釋,變數名稱也不那么 "可讀"。
由于以上種種原因,我在你的演算法基礎上創建了一個新的實作,并做了一些小的改進。
請看下面一個可能的改進方案:
// -----------------------------------
//span>一些基本的定義。
//游戲板的尺寸 //游戲板的尺寸
constexpr size_t NumberOfRows {2u};
constexpr size_t NumberOfColumns {4u};
//表示空欄位的字符。
constexpr char EmptyField {'#'/span>}。
// -----------------------------------------------------------------
///方向將以行坐標和列坐標的偏移量給出。
using Direction = std::pair<const int, const>。
//上、下、左、右的方向。
constexpr std:: array<Direction, 4> Moves{{ {-1,0}, {1,0}, {0,-1},{0,1}. }};
// ----------------------------------------------------------
//保障gameBoard尺寸的最低要求。
static_assert ((NumberOfRows>1)&& (NumberOfColumns>1),"錯誤。錯誤的游戲板尺寸
")。)
// gameBoard的邊框。
constexpr int BorderLeft {0};
constexpr int BorderUp {0};
constexpr int BorderRight{NumberOfColumns - 1};
constexpr int BorderBottom{NumberOfRows - 1 };
//通過使用別名使讀/寫更簡單。
using GameBoard = std::array<std::array<char, NumberOfColumns>, NumberOfRows> 。
//---------------------------------------
//A game board at a certain point in time
class GameState {
//游戲板,以2d陣列形式存盤。
GameBoard gameBoard{};
public:
//創建一個新的GameState,將EmptyField移到一個新的位置。
GameState swapPosition(const Direction& direction)。
// 萃取器操作。從一個流中讀取一個游戲板。
friend std::istream& operator >> (std::istream& is, GameState& gs){
//讀取所有行和列的字符。
for (auto& row : gs.gameBoard) for (char& c : row) is >> c。
return is;
}
//為std::map重寫小于運算子。
bool operator < (const GameState& other) const { return gameBoard < other。 gameBoard; }
//和重寫等價運算子,以方便評估。
bool operator == (const GameState& other) const { {span class="hljs-keyword">return gameBoard == other.gameBoard; }; }
};
// --------------------------------------------------------------------
//創建一個新的GameState,將EmptyField移到一個新的位置。
GameState GameState::swapPosition(const Direction& direction){
//從這個gameBoard復制一個新的GameState。
GameState swappedGameState = *this;
//找到EmptyField。
for (int row{}; row < static_cast< const int> (NumberOfRows); row) {
for (int column{}; column < static_cast< const int> (NumberOfColumns); column) {
if (gameBoard[row][umn] == EmptyField) {
//根據給定的方向計算新的行和列索引。
//不要跨越gameBoard的邊界。
const int nextRow = std::clamp((row direction.first), BorderUp, BorderBottom) 。
const int nextColumn = std::clamp(( column direction.second), BorderLeft, BorderRight);
// Shift. 在給定的方向上用char交換EmptyField。
std::swap(swappedGameState.gameBoard[row][column],swappedGameState.gameBoard[nextRow][nextColumn]) 。
}
}
}
return swappedGameState。
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
int main(int argc, char **argv) {
//首先檢查我們是否有足夠的命令列引數。
if (argc == 3) {
// OK, we have command line arguments, try to open the specified files.
if (std::ifstream inputStream{argv[1]}; inputStream) {
//現在是輸出流。
if (std::ofstream outputStream{argv[2]}; outputStream) {
//所有檔案都打開了。獲得開始和目標游戲狀態
//首先定義實體[/span
GameState startGameState{}。
GameState destinationGameState{}。
//然后從檔案中讀取/提取資料并存盤在實體中。
inputStream >> startGameState;
inputStream >> destinationGameState。
//設定/初始化評估引數。
//這里我們將存盤導致這個狀態的交換次數。
std::map<GameState, unsigned int> numberOfSwaps{{startGameState, 0u}}。
//這里我們將存盤一次或多次交換后的所有中間狀態。
std::queue<GameState> trialGameState{}。
trialGameState.push(startGameState)。
//指示器,如果我們找到一個解決方案或沒有。
bool solutionFound{};
///直到我們找到一個解決方案(或沒有)。
while (not trialGameState.empty() && not solutionFound) {
//得到當前(最新交換的)游戲狀態。
GameState currentGameState = trialGameState.front()。
trialGameState.pop()。
//檢查結束條件。我們是否找到了desitnation組合。
if (currentGameState == destinationGameState) {
solutionFound = true;
outputStream << numberOfSwaps[currentGameState] << std::endl;
}
else {
//獲取所有方向的下一個狀態。遍歷所有可能的動作。
for (const Direction& direction : Moves) {
//此方向的下一個狀態。
GameState nextState = currentGameState.swapPosition(direction)。
//防止回圈交換和存盤雙重元素。
if (numberOfSwaps.count(nextState) == 0) {
// OK,有效的下一個狀態。存盤已完成的互換次數。
numberOfSwaps[nextState] = numberOfSwaps[currentGameState] 1 ;
//并將此狀態保存為一個潛在的新候選狀態。
trialGameState.push(nextState)。
}
}
}
} //所有錯誤界面。
if (not solutionFound)
std::cerr << "
沒有找到解決方案
"。
}
else std::cerr << "
錯誤。無法打開輸入檔案'" << argv[1] << "
"。
}
else std::cerr << "
錯誤。無法打開輸出檔案'" << argv[2] << "
"。
}
else std::cerr << "
錯誤。請用:app inputFileName outputFileName呼叫
"。
return 0;
}
但即使這樣也需要進一步改進。至少應該添加一個輸入驗證。總之,祝你玩得開心。
uj5u.com熱心網友回復:
在C 中像這樣從輸入檔案中讀取字符:
char input_c;
std::ifstream input_file("input.txt")。
while (input_file >> input_c) // stop at eof
{
//驗證輸入。
//...做你的事。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/310852.html
標籤:

