Guest User

Untitled

a guest
Feb 23rd, 2018
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.69 KB | None | 0 0
  1. '''
  2. Mine Sweeper
  3. Written by Kaz Yoshikawa
  4. Date: Feb 12, 2018
  5.  
  6. MIT License
  7.  
  8. Copyright (c) 2018
  9.  
  10. Permission is hereby granted, free of charge, to any person obtaining a copy
  11. of this software and associated documentation files (the "Software"), to deal
  12. in the Software without restriction, including without limitation the rights
  13. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. copies of the Software, and to permit persons to whom the Software is
  15. furnished to do so, subject to the following conditions:
  16.  
  17. The above copyright notice and this permission notice shall be included in all
  18. copies or substantial portions of the Software.
  19.  
  20. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26. SOFTWARE.
  27. '''
  28.  
  29. import random
  30.  
  31. def board_width():
  32. return 10
  33.  
  34. def board_height():
  35. return 10
  36.  
  37. def char_mine():
  38. return "*"
  39.  
  40. def char_flag():
  41. return "?"
  42.  
  43. def char_none_revealed():
  44. return "+"
  45.  
  46. def char_no_mine():
  47. return "."
  48.  
  49. def surrounding_vectors():
  50. return [[-1, -1], [-1, 0], [-1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1]]
  51.  
  52. def is_debugging():
  53. return False
  54.  
  55. def display_mine_sweeper():
  56. print " __ __ _ _____ "
  57. print " | \/ (_) / ____| "
  58. print " | \ / |_ _ __ ___ | (_____ _____ ___ _ __ ___ _ __ "
  59. print " | |\/| | | '_ \ / _ \ \___ \ \ /\ / / _ \/ _ \ '_ \ / _ \ '__|"
  60. print " | | | | | | | | __/ ____) \ V V / __/ __/ |_) | __/ | "
  61. print " |_| |_|_|_| |_|\___| |_____/ \_/\_/ \___|\___| .__/ \___|_| "
  62. print " | | "
  63.  
  64. def display_gameover():
  65. print " __ _ ____ ____ ___ ___ ____ "
  66. print "| |/ ] / || \ / \ / \ | \ "
  67. print "| ' / | o || o )| || || _ |"
  68. print "| \ | || || O || O || | |"
  69. print "| || _ || O || || || | |"
  70. print "| . || | || || || || | |"
  71. print "|__|\_||__|__||_____| \___/ \___/ |__|__|"
  72. print " "
  73. print " G A M E O V E R "
  74.  
  75. def display_congratulations():
  76. print " __ ___ ____ ____ ____ ____ ______ __ __ _ ____ ______ ____ ___ ____ _____"
  77. print " / ] / \ | \ / || \ / || || | || | / || || |/ \ | \ / ___/"
  78. print " / / | || _ || __|| D )| o || || | || | | o || | | || || _ ( \_ "
  79. print " / / | O || | || | || / | ||_| |_|| | || |___ | ||_| |_| | || O || | |\__ |"
  80. print "/ \_ | || | || |_ || \ | _ | | | | : || || _ | | | | || || | |/ \ |"
  81. print "\ || || | || || . \| | | | | | || || | | | | | || || | |\ |"
  82. print " \____| \___/ |__|__||___,_||__|\_||__|__| |__| \__,_||_____||__|__| |__| |____|\___/ |__|__| \___|"
  83. print " "
  84. print " You sweeped the all bombs!!"
  85.  
  86.  
  87. def display_welcome():
  88. display_mine_sweeper()
  89. print
  90. print "Instruction:"
  91. print
  92. print "The purpose of the game is to open all the cells of the board"
  93. print "which do not contain a bomb. You lose if you set off a bomb cell."
  94. print
  95. print "bluh, bluh bluh...."
  96.  
  97. def input_integer(message):
  98. while True:
  99. try:
  100. userInput = int(raw_input(message))
  101. except ValueError:
  102. print("Not an integer! Try again.")
  103. continue
  104. else:
  105. return userInput
  106. break
  107.  
  108.  
  109. def display_board(board):
  110. assert(len(board) == board_height())
  111. debug = is_debugging()
  112. print
  113. cols = board_width()
  114. rows = board_height()
  115. header = " "
  116. for ch in range(ord('a'), ord('a')+cols):
  117. header += (str(chr(ch)) + " ")
  118. if debug:
  119. header = header + " " + header
  120. print header
  121.  
  122.  
  123. for row in range(rows):
  124. string = "%1d:|" % row
  125. for col in range(rows):
  126. cell = board[row][col]
  127. string += (board[row][col][1] + "|")
  128. if debug:
  129. string += " %1d:|" % row
  130. for col in range(rows):
  131. cell = board[row][col]
  132. string += (board[row][col][0] + "|")
  133. print string
  134.  
  135.  
  136. def count_mines_in_neighbor(board, row, col):
  137. width = board_width()
  138. height = board_height()
  139. count = 0
  140. if board[row][col][0] == char_mine():
  141. return -1 # mine
  142. for vector in surrounding_vectors():
  143. dy = vector[0]
  144. dx = vector[1]
  145. y = row + dy
  146. x = col + dx
  147. if dx != 0 or dy != 0:
  148. if y >= 0 and y < height and x >= 0 and x < width:
  149. if board[y][x][0] == char_mine():
  150. count += 1
  151. return count
  152.  
  153. def cell_char(mine_count):
  154. if mine_count < 0:
  155. return "*"
  156. if mine_count >= 0 and mine_count <= 9:
  157. return chr(ord('0') + mine_count)
  158. assert(False)
  159.  
  160.  
  161. def make_board(mines):
  162. # each cell requires two states, concealed state that player cannot see,
  163. # and in-play state that player can see. In order to achieve this,
  164. # board[x][y] keeps two characters [0] for the concealed, [1] for in-play
  165. # [Concealed State]
  166. # '0'-'8': cell that whose neighbor
  167. # '*': mine
  168. # [In-Play State]
  169. # '0'-'8': cell that whose neighbor
  170. # '*': mine, '?": flagged, ".": no mine, '+': unknown
  171. # examples:
  172. # "*?" - mine with flagged
  173. # "*+" - hidden mine
  174. # "2 " - unvealed but there are two mines in neighbor cells
  175. # "11" - there is a mine in in neighbor cells, and disclosed
  176.  
  177. # create the board
  178. board = []
  179. for row in range(board_height()):
  180. cells = []
  181. for col in range(board_width()):
  182. cells.append("0 ")
  183. board.append(cells)
  184. count = mines
  185.  
  186. # set some mines
  187. while count > 0:
  188. x = random.randint(0, board_width() - 1)
  189. y = random.randint(0, board_height() - 1)
  190. if board[y][x][0] == "0":
  191. board[y][x] = char_mine() + char_none_revealed()
  192. count -= 1
  193.  
  194. # set hints
  195. for row in range(board_height()):
  196. for col in range(board_width()):
  197. count = count_mines_in_neighbor(board, row, col)
  198. board[row][col] = cell_char(count) + char_none_revealed()
  199. return board
  200.  
  201. def input_position():
  202. position = [] # expect [row, col]
  203. row_chars = []
  204. col_chars = []
  205. for row in range(board_height()):
  206. row_chars += chr(ord('0') + row)
  207. for col in range(board_width()):
  208. col_chars += chr(ord('a') + col)
  209. prompt = "Please enter a position to open or to flag: "
  210. while True:
  211. string = raw_input(prompt).lower()
  212. if len(string) != 2 :
  213. print "Not a valid position, please try again"
  214. continue
  215. if string[0] in col_chars and string[1] in row_chars:
  216. col = ord(string[0]) - ord('a')
  217. row = ord(string[1]) - ord('0')
  218. position = [row, col]
  219. break
  220. # may not be necessary, but make it easy for player to input
  221. if string[0] in row_chars and string[1] in col_chars:
  222. col = ord(string[1]) - ord('a')
  223. row = ord(string[0]) - ord('0')
  224. position = [row, col]
  225. break
  226. return position
  227.  
  228. def reveal_position(board, row, col):
  229.  
  230. # to avoid process the same call more than once, provide flags
  231. flags = []
  232. for y in range(board_height()):
  233. rowflags = []
  234. for x in range(board_width()):
  235. rowflags.append(False)
  236. flags.append(rowflags)
  237.  
  238. # '0': enqueue the position to process, other digits: reveal it
  239. queue = []
  240. cell = board[row][col]
  241. if cell[0] == "0":
  242. queue.append([row, col])
  243. elif cell[0].isdigit():
  244. board[row][col] = board[row][col][0] + board[row][col][0]
  245. flags[row][col] = True
  246.  
  247. width = board_width()
  248. height = board_height()
  249. count = 0
  250.  
  251. # keep processing untill queue is empty
  252. while len(queue) > 0:
  253. count += 1
  254. row_col = queue.pop()
  255. row = row_col[0]
  256. col = row_col[1]
  257. cell = board[row][col]
  258. assert(cell[0] == "0")
  259. board[row][col] = cell[0] + char_no_mine()
  260.  
  261. # look for neighboring cell for eight directions
  262. for vector in surrounding_vectors():
  263. y = row + vector[0]
  264. x = col + vector[1]
  265. # ignore if out of range or has been processed
  266. if x in range(width) and y in range(height) and not flags[y][x]:
  267. flags[y][x] = True # mark it off
  268. cell = board[y][x]
  269. if cell[0] == "0":
  270. queue.append([y, x]) # enqueue
  271. elif cell[0].isdigit():
  272. board[y][x] = cell[0] + board[y][x][0] # reveal the number
  273.  
  274.  
  275. def count_mines(board):
  276. count = 0
  277. for row in range(board_height()):
  278. for col in range(board_width()):
  279. if board[row][col][0] == char_mine():
  280. count += 1
  281. return count
  282.  
  283. def count_flags(board):
  284. count = 0
  285. for row in range(board_height()):
  286. for col in range(board_width()):
  287. if board[row][col][1] == char_flag():
  288. count += 1
  289. return count
  290.  
  291. def toggle_flag(board, row, col):
  292. if board[row][col][1] == char_flag():
  293. board[row][col] = board[row][col][0] + char_none_revealed()
  294. else:
  295. board[row][col] = board[row][col][0] + char_flag()
  296.  
  297. def reveal_board(board):
  298. for row in range(board_height()):
  299. for col in range(board_width()):
  300. cell = board[row][col]
  301. if cell[0] == "0":
  302. board[row][col] = cell[0] + char_no_mine()
  303. else:
  304. board[row][col] = cell[0] + cell[0]
  305.  
  306. def main():
  307. display_welcome()
  308. number_of_mines = input_integer("Please input a number of mines in a map: ")
  309. board = make_board(number_of_mines)
  310. display_board(board)
  311. while True:
  312.  
  313. # check if all mines are sweeped
  314. mines_left = count_mines(board) - count_flags(board)
  315. if mines_left == 0:
  316. display_congratulations()
  317. break
  318.  
  319. # input a position of borad [row, col]
  320. print "Thre are ", mines_left, "mines left out of ", number_of_mines, "."
  321. pos = input_position()
  322. row = pos[0]
  323. col = pos[1]
  324.  
  325. # when the cell is flagged, then ask to turn off
  326. if board[row][col][1] == char_flag():
  327. answer = raw_input("Would you like to turn the flag off?").lower()
  328. if answer == "y":
  329. toggle_flag(board, row, col)
  330.  
  331. # when the cell is not yet unvealed, then aks either to open or to flag
  332. elif board[row][col][1] == char_none_revealed():
  333. answer = raw_input("Would you like to open(o) or flag(f): ").lower()
  334. if answer == "o": # open
  335. if board[row][col][0] == char_mine():
  336. reveal_board(board)
  337. display_board(board)
  338. display_gameover()
  339. break
  340. elif board[row][col][0].isdigit():
  341. reveal_position(board, row, col)
  342. elif answer == "f": #flag
  343. toggle_flag(board, row, col)
  344. display_board(board)
  345.  
  346.  
  347. main()
Add Comment
Please, Sign In to add comment